当前位置: 首页 > 知识库问答 >
问题:

Struts/hibernate NonUniqueObjectException:具有相同标识符值的不同对象已经与会话关联

轩辕嘉平
2023-03-14

我有以下问题:

有人对此有解释吗?我考虑从我的业务服务中的hibernate会话中重新加载对象,并从Struts HTTP会话中复制实体对象中的数据。

@Override
    public boolean equals(Object autre) {
        if (this == autre) {
            return true;
        }
        if ((autre == null) || (autre.getClass() != this.getClass())) {
            return false;
        }
        MouvementFinancier entite = (MouvementFinancier) autre;
        if (pk == null || entite.pk == null) {
            return false;
        }
        return pk.equals(entite.pk);
    }

    @Override
    public int hashCode() {
        if (pk == null) {
            return super.hashCode();
        }
        return pk.hashCode();
    }

Hibernate映射

 <class name="com.XXX.MouvementFinancier" table="MOUVEMENT_FINANCIER"
            discriminator-value="0" abstract="true">

            <id name="pk" type="integer" column="PK_MOUVEMENT_FINANCIER" unsaved-value="null">
                <generator class="com.XXX.TableGenerator">
                    <param name="segment_value">MOUVEMENT_FINANCIER</param>
                </generator>
            </id>

            <discriminator column="CLASSE" type="integer" />
            <timestamp column="DATE_VERSION" name="version" unsaved-value="null" />

            <property name="commentaire" column="COMMENTAIRE" />
            ...

            <set name="actes" cascade="all,delete-orphan" fetch="select" sort="natural">
                <key column="PK_MOUVEMENT_FINANCIER" not-null="true" />
                <one-to-many class="com.p****.HistoriqueMouvement" />
            </set>

            <subclass name="com.XXX.Encaissement" discriminator-value="2">
                <property name="purpose" column="NATURE_RECUPERATION" />
                ...

                <many-to-one name="emetteur" column="PK_PERSONNE_EMETTEUR"
                    class="com.XXX.Personne" cascade="none" fetch="join" lazy="false"/>

                <many-to-one name="acteurEmetteur" column="PK_ACTEUR_EMETTEUR"
                    class="com.XXX.Acteur" cascade="none" fetch="join" lazy="false"/>
            </subclass>

            <subclass name="com.XXX.Reglement" discriminator-value="1">
                <property name="dateAutorisation" type="timestamp" column="DATE_AUTORISATION" />
                <property name="franchise" column="FRANCHISE" />
                ...

                <many-to-one name="beneficiaire" column="PK_PERSONNE_BENEFICIAIRE"
                    class="com.XXX.Personne" cascade="none" fetch="join" lazy="false"/>

                <many-to-one name="acteurBeneficiaire" column="PK_ACTEUR_BENEFICIAIRE"
                    class="com.XXX.Acteur" cascade="none" fetch="join" lazy="false"/>

                <many-to-one name="adresseCourrierReglementBeneficiaire" column="PK_ADD_COUR_REG_BENEF"
                    class="com.XXX.AdresseCourrierReglement" cascade="none" fetch="join" lazy="false"/>

                <many-to-one name="destinataire" column="PK_PERSONNE_DESTINATAIRE"
                    class="com.XXX.Personne" cascade="none" fetch="join" lazy="false"/>

                <many-to-one name="acteurDestinataire" column="PK_ACTEUR_DESTINATAIRE"
                    class="com.XXX.Acteur" cascade="none" fetch="join" lazy="false"/>

                <many-to-one name="adresseCourrierReglementDestinataire" column="PK_ADD_COUR_REG_DEST"
                    class="com.XXX.AdresseCourrierReglement" cascade="none" fetch="join" lazy="false"/>

                <many-to-one name="rib" column="PK_RIB" class="com.XXX.assureur.RIB"
                    cascade="all" fetch="select" />

                <set name="ventilationDepenses" cascade="all,delete-orphan" fetch="select">
                    <key column="PK_MOUVEMENT_FINANCIER" not-null="true" />
                    <one-to-many class="com.XXX.Depense"/>
                </set>

            </subclass>

        </class>

        <class name="com.XXXX.Depense" table="VENTILATION_DEPENSES">
            <id name="pk" type="integer" column="PK_VENTILATION_DEPENSE" unsaved-value="null">
                <generator class="com.XXX.TableGenerator">
                    <param name="segment_value">VENTILATION_DEPENSES</param>
                </generator>
            </id>

            <property name="nature" column="CODE_NATURE_DEPENSE" />
            <property name="montant" column="MONTANT_DEPENSE" />
            ...
        </class>

共有1个答案

慕弘伟
2023-03-14

通过在DAO中使用Hiberante merge解决了这个问题,但我仍然想知道为什么在大多数情况下,如果不在从hibernate会话加载的实体中使用merge命令或copy将“分离的”实体发回服务层,就不会出现问题。

// TODO : save (twice) replaced by 1 merge to avoid issue on detached object
// if we have any more pb on this, redo all : load payment from session and copy data in from dto.
session.merge(reglement);

完整代码

    @Override
        public void update...(...) {
            if (logger.isDebugEnabled()) {
                logger.debug("Updating a settlement");
            }
            Session session = sf.getCurrentSession();
            final PartieFinanciere partieReglement = (PartieFinanciere) session.get(PartieFinanciere.class, pkPartieFinanciere);
            if (partieReglement == null) {
                throw new ExceptionPkEntiteInconnu(PartieFinanciere.class, pkPartieFinanciere);
            }

            // History : last movement amount to remove it on total amount
            HistoriqueMouvement movementHistoryLast = reglement.getActes().stream().sorted((h1, h2) -> h2.compareTo(h1)).findFirst().orElse(null);
            Double mouvementLastAmount = movementHistoryLast != null ? movementHistoryLast.getMontant() : 0;

            // History : add movement modification in history
            HistoriqueMouvement histo = new HistoriqueMouvement();
            histo.setActe(...);
            histo.setDate(...);
            histo.setMontant(...);
            .....
            reglement.getActes().add(histo);
            partieReglement.getMouvements().add(reglement);

            // Recalculate total amount : remove previous movement amount, set movement modified amount
            Double amountProvision = ofNullable(partieReglement.getTotalMouvements()).orElse(0.0).doubleValue() - mouvementLastAmount + reglement.getMontant();
            partieReglement.setTotalMouvements(amountProvision);

            if (logger.isDebugEnabled()) {
                logger.debug("Updating total mouvement and suspens.");
            }

            mettreAJourTotalMouvementsEtSuspens(session, partieReglement);
            ajouterActePartieFinanciere(gestionnaire, partieReglement, getHistoriquePartieActe(null, reglement.getType(), false), reglement.getMontant());

// TODO : save (twice) replaced by 1 merge to avoid issue on detached object
// if we have any more pb on this, redo all : load payment from session and copy data in from dto.
session.merge(reglement);
 }
 类似资料:
  • 此方法以事务开头 这是一个映射器类,我在其中创建DB帐户实体并映射地址和联系人。 当我不在地图内调用下面的方法时,一切都正常工作。但是当我调用它时,我得到了标题中描述的错误。 最后的方法是 异常堆栈跟踪 null

  • null 对于我的数据,我有时会遇到这样的问题:A有一组不同的B对象,而这些B对象引用同一个C对象。 当我调用时,我会得到一个hibernate错误:。我知道hibernate不能在同一个会话中插入/更新/删除同一个对象两次,但是有什么方法可以解决这个问题吗?这似乎并不是一种罕见的情况。 在我研究这个问题的过程中,我看到有人建议使用,但当我这样做时,任何“冲突”对象都会作为所有值都设置为null的

  • 我们试图通过Keycloak验证现有用户,因此实现了自定义SPI,并将自定义SPI添加为用户联合 原因:javax.persistence.EntityExistsException:具有相同标识符值的不同对象已与会话关联:[org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity#org.keycloak.storage.jpa

  • 问题内容: 在使用Spring和Hibernate的应用程序中,我解析CSV文件,并在每次从CSV文件中读取记录时通过调用来填充db 。 我的域模型: “家庭”有很多“子家庭” “子家庭”有很多“位置” “ Locus”属于“ Species” 都是双向映射。 码: 使用以下方法将物种分配给场所,该方法仅访问DAO层: Hibernate给出以下错误: 有小费吗? 问题答案: 使用。该异常表示当前

  • 以前我没有得到任何错误,但突然我开始得到错误:

  • 问题内容: 我有两个用户对象,而在尝试使用以下方法保存对象时 我收到以下错误: 我正在使用创建会话 我还尝试过在保存之前进行操作,但仍然没有运气。 这是我第一次在用户请求到来时获取会话对象,因此我要为什么要说该对象存在于会话中。 有什么建议么? 问题答案: 我已经多次发生此错误,很难追踪… 基本上,hibernate是指您有两个具有相同标识符(相同主键)但不是相同对象的对象。 我建议您分解代码,即