[Hibernate-JIRA] Resolved: (HHH-1401) session.merge() executes unnecessary updates when one-to-many relationship is defined.
by Steve Ebersole (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1401?page=all ]
Steve Ebersole resolved HHH-1401:
---------------------------------
Resolution: Fixed
> session.merge() executes unnecessary updates when one-to-many relationship is defined.
> --------------------------------------------------------------------------------------
>
> Key: HHH-1401
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1401
> Project: Hibernate3
> Type: Bug
> Components: core
> Versions: 3.1.1
> Environment: Hibernate 3.1.1
> Postgres 8.03
> Java 1.4.2_09
> Reporter: David Trott
> Assignee: Steve Ebersole
> Fix For: 3.2.1
> Attachments: HHH-1401.zip, HHH1401Test.java, Screenshot-Debug - AbstractPersistentCollection.class - Eclipse SDK .png, TEST-org.hibernate.test.optlock.OptimisticLockTest.txt
>
>
> I am attempting to use the session.merge() functionality in order to synchronize the state of the data coming from the web tier with the database, however I am seeing unnecessary updates (when nothing has changed).
> In order to track down the problem I created a test case with four tables and four classes (A,B,C and D)
> Where:
> A is the parent of B.
> B is the parent of C.
> C is the parent of D.
> And there are no other relationships present.
> All these relationships are bi-directional with the one-to-many side marked as inverse="true" and cascade="all-delete-orphan".
> The merge() is working fine (the data gets updated correctly) except that when there is no change to the data hibernate still runs updates on A,B and C however not on D (D has no one-to-many relationships).
> I am including the code and hibernate mapping for B as it is representative of the code for all the other classes.
> I am no expect on the hibernate implementation, but my suspicion of the cause is when hibernate substitutes a PersistentBag for the ArrayList in the merged object (associated with the session) it detects this as a change and hence triggers the update, unfortunately the data itself has not changed hence no update is necessary.
> FYI: If I change the initialization of the bags from "new ArrayList()" to "new PersistentBag()" the extra updates go away, however then it doesn't save real changes correctly.
> package com.mycompany.dal.transfer.impl;
> import org.apache.commons.lang.builder.EqualsBuilder;
> import org.apache.commons.lang.builder.HashCodeBuilder;
> import org.apache.commons.lang.builder.ToStringBuilder;
> import java.util.ArrayList;
> import java.util.Collections;
> import java.util.List;
> import com.mycompany.dal.transfer.interfaces.ADTO;
> import com.mycompany.dal.transfer.interfaces.BDTO;
> import com.mycompany.dal.transfer.interfaces.CDTO;
> import org.apache.commons.collections.Closure;
> import org.apache.commons.collections.CollectionUtils;
> public class BDTOImpl implements BDTO {
> public BDTOImpl () {
> }
> private Long bId;
>
> public Long getBId() {
> return bId;
> }
> public void setBId(Long bId) {
> this.bId = bId;
> }
> private Long concurrentVersion;
>
> public Long getConcurrentVersion() {
> return concurrentVersion;
> }
> public void setConcurrentVersion(Long concurrentVersion) {
> this.concurrentVersion = concurrentVersion;
> }
> // Package level protection so that overrides can access it.
> boolean deleting = false;
> private String name;
> /**
> * Returns the Name.
> *
> * @return String - The Name
> */
> public String getName() {
> return name;
> }
> /**
> * Set the Name.
> *
> * @param name String - The Name.
> */
> public void setName(String name) {
> this.name = name;
> }
> private ADTO a;
> /**
> * Returns the A.
> *
> * @return ADTO - The A.
> */
> public ADTO getA() {
> return a;
> }
>
> public ADTO getAInternal() {
> return a;
> }
> /**
> * Updates the A.
> *
> * @param a - ADTO The A.
> */
> public void setA(ADTO a) {
> if (this.a == a) {
> return;
> }
> if (this.a != null) {
> ((ADTOImpl) this.a).removeBInternal(this);
> }
> this.a = a;
> if (a != null) {
> ((ADTOImpl) a).addBInternal(this);
> }
> }
> public void setAInternal(ADTO a) {
> if (deleting) {
> return;
> }
> if (this.a != a &&
> this.a != null && a != null) {
> throw new IllegalStateException("BDTO cannot be a member of two A collections: " + toString());
> }
> this.a = a;
> }
> private List cs;
> private List csMutable;
> { setCsMutable(new ArrayList()); }
> public List getCsMutable() {
> return csMutable;
> }
> public void setCsMutable(List cs) {
> this.cs = Collections.unmodifiableList(cs);
> this.csMutable = cs;
> }
> public List getCs() {
> return cs;
> }
>
> public void addC(CDTO c) {
> csMutable.add(c);
> ((CDTOImpl) c).setBInternal(this);
> }
> public void addCInternal(CDTO c) {
> csMutable.add(c);
> }
>
> public void removeC(CDTO c) {
> csMutable.remove(c);
> ((CDTOImpl) c).setBInternal(null);
> }
> public void removeCInternal(CDTO c) {
> if (!deleting) {
> csMutable.remove(c);
> }
> }
> public void beforeDelete() {
> // Guard to prevent infinite loop.
> if (deleting) {
> return;
> }
>
> deleting = true;
> if (this.a != null) {
> ((ADTOImpl) this.a).removeBInternal(this);
> }
> CollectionUtils.forAllDo(new ArrayList(csMutable), new Closure() {
> public void execute(Object ob) {
> ((CDTOImpl) ob).beforeDelete();
> }
> });
> }
> public int hashCode() {
> return (new HashCodeBuilder(17,37)
> .append(getBId())
> ).toHashCode();
> }
> public boolean equals(Object o) {
> boolean equals = false;
> if (o != null && o instanceof BDTO) {
> BDTO other = (BDTO) o;
> return (new EqualsBuilder()
> .append(getBId(), other.getBId())
> ).isEquals();
> }
> return equals;
> }
>
> public String toString() {
> return new ToStringBuilder(this)
> .append("bId", getBId())
> .append("name", getName())
> .toString();
> }
> }
> ******************************
> *** Mapping Document ****
> ******************************
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
> "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
> <hibernate-mapping package="com.mycompany.dal.transfer.impl" auto-import="true">
> <class name="com.mycompany.dal.transfer.impl.BDTOImpl" table="b">
> <id name="BId" type="long">
> <column name="b_id" not-null="true"/>
> <generator class="native"/>
> </id>
> <version name="concurrentVersion" column="concurrent_version" type="long"/>
> <property name="Name" type="string">
> <column name="name" length="60" not-null="false"/>
> </property>
> <many-to-one name="AInternal" class="com.mycompany.dal.transfer.impl.ADTOImpl">
> <column name="a_id" not-null="true"/>
> </many-to-one>
> <bag name="CsMutable" cascade="all-delete-orphan" inverse="true">
> <key>
> <column name="b_id" not-null="true"/>
> </key>
> <one-to-many class="com.mycompany.dal.transfer.impl.CDTOImpl"/>
> </bag>
> </class>
> </hibernate-mapping>
> *************************
> *** Generated SQL ****
> *************************
> 05:35:39,887 INFO [STDOUT] Hibernate: select adtoimpl0_.a_id as a1_162_2_, adtoimpl0_.concurrent_version as concurrent2_162_2_, adtoimpl0_.name as name162_2_, bsmutable1_.a_id as a4_4_, bsmutable1_.b_id as b1_4_, bsmutable1_.b_id as b1_164_0_, bsmutable1_.concurrent_version as concurrent2_164_0_, bsmutable1_.name as name164_0_, bsmutable1_.a_id as a4_164_0_, csmutable2_.b_id as b4_5_, csmutable2_.c_id as c1_5_, csmutable2_.c_id as c1_165_1_, csmutable2_.concurrent_version as concurrent2_165_1_, csmutable2_.name as name165_1_, csmutable2_.b_id as b4_165_1_ from a adtoimpl0_ left outer join b bsmutable1_ on adtoimpl0_.a_id=bsmutable1_.a_id left outer join c csmutable2_ on bsmutable1_.b_id=csmutable2_.b_id where adtoimpl0_.a_id=?
> 05:35:39,992 INFO [STDOUT] Hibernate: select ddtoimpl0_.d_id as d1_168_0_, ddtoimpl0_.concurrent_version as concurrent2_168_0_, ddtoimpl0_.name as name168_0_, ddtoimpl0_.c_id as c4_168_0_ from d ddtoimpl0_ where ddtoimpl0_.d_id=?
> 05:35:40,007 INFO [STDOUT] Hibernate: select dsmutable0_.c_id as c4_1_, dsmutable0_.d_id as d1_1_, dsmutable0_.d_id as d1_168_0_, dsmutable0_.concurrent_version as concurrent2_168_0_, dsmutable0_.name as name168_0_, dsmutable0_.c_id as c4_168_0_ from d dsmutable0_ where dsmutable0_.c_id=?
> *** Start Extra Updates **
> 05:35:40,030 INFO [STDOUT] Hibernate: update b set concurrent_version=?, name=?, a_id=? where b_id=? and concurrent_version=?
> 05:35:40,038 INFO [STDOUT] Hibernate: update c set concurrent_version=?, name=?, b_id=? where c_id=? and concurrent_version=?
> 05:35:40,044 INFO [STDOUT] Hibernate: update a set concurrent_version=?, name=? where a_id=? and concurrent_version=?
> *** End Extra Updates **
> **************************
> *** Accessing code ****
> **************************
> DataAccessLayer dal = DataAccessLayerBuilder.getInstance();
>
> ADAO aDAO = dal.getADAO();
> BDAO bDAO = dal.getBDAO();
> CDAO cDAO = dal.getCDAO();
> DDAO dDAO = dal.getDDAO();
>
> ADTO a = aDAO.newA();
> a.setAId(new Long(1));
> a.setConcurrentVersion(new Long(0));
> a.setName("A");
>
> BDTO b = bDAO.newB();
> CDTO c = cDAO.newC();
> DDTO d = dDAO.newD();
> b.setBId(new Long(2));
> c.setCId(new Long(3));
> d.setDId(new Long(4));
> b.setConcurrentVersion(new Long(0));
> c.setConcurrentVersion(new Long(0));
> d.setConcurrentVersion(new Long(0));
> b.setName("B");
> c.setName("C");
> d.setName("D");
> b.setA(a);
> c.setB(b);
> d.setC(c);
>
> aDAO.mergeA(a);
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira
18 years, 2 months
[Hibernate-JIRA] Commented: (HHH-1401) session.merge() executes unnecessary updates when one-to-many relationship is defined.
by Steve Ebersole (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1401?page=c... ]
Steve Ebersole commented on HHH-1401:
-------------------------------------
So at this point, I have added a bunch of tests now to test this behavior. If anyone is still experiencing issues here, please refer to one of these tests as a baseline for the behavior you see...
The tests consist of a couple new test methods in org.hibernate.test.ops.MergeTest:
(1) testNoExtraUpdatesOnMerge()
(2) testNoExtraUpdatesOnMergeWithCollection()
(3) testNoExtraUpdatesOnMergeVersioned()
(4) testNoExtraUpdatesOnMergeVersionedWithCollection()
and the new/expanded org.hibernate.test.collection.CollectionSuite
For those previously experiencing issues in this area, please check out SVN (3.2 or trunk) and test with my changes...
> session.merge() executes unnecessary updates when one-to-many relationship is defined.
> --------------------------------------------------------------------------------------
>
> Key: HHH-1401
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1401
> Project: Hibernate3
> Type: Bug
> Components: core
> Versions: 3.1.1
> Environment: Hibernate 3.1.1
> Postgres 8.03
> Java 1.4.2_09
> Reporter: David Trott
> Assignee: Steve Ebersole
> Fix For: 3.2.1
> Attachments: HHH-1401.zip, HHH1401Test.java, Screenshot-Debug - AbstractPersistentCollection.class - Eclipse SDK .png, TEST-org.hibernate.test.optlock.OptimisticLockTest.txt
>
>
> I am attempting to use the session.merge() functionality in order to synchronize the state of the data coming from the web tier with the database, however I am seeing unnecessary updates (when nothing has changed).
> In order to track down the problem I created a test case with four tables and four classes (A,B,C and D)
> Where:
> A is the parent of B.
> B is the parent of C.
> C is the parent of D.
> And there are no other relationships present.
> All these relationships are bi-directional with the one-to-many side marked as inverse="true" and cascade="all-delete-orphan".
> The merge() is working fine (the data gets updated correctly) except that when there is no change to the data hibernate still runs updates on A,B and C however not on D (D has no one-to-many relationships).
> I am including the code and hibernate mapping for B as it is representative of the code for all the other classes.
> I am no expect on the hibernate implementation, but my suspicion of the cause is when hibernate substitutes a PersistentBag for the ArrayList in the merged object (associated with the session) it detects this as a change and hence triggers the update, unfortunately the data itself has not changed hence no update is necessary.
> FYI: If I change the initialization of the bags from "new ArrayList()" to "new PersistentBag()" the extra updates go away, however then it doesn't save real changes correctly.
> package com.mycompany.dal.transfer.impl;
> import org.apache.commons.lang.builder.EqualsBuilder;
> import org.apache.commons.lang.builder.HashCodeBuilder;
> import org.apache.commons.lang.builder.ToStringBuilder;
> import java.util.ArrayList;
> import java.util.Collections;
> import java.util.List;
> import com.mycompany.dal.transfer.interfaces.ADTO;
> import com.mycompany.dal.transfer.interfaces.BDTO;
> import com.mycompany.dal.transfer.interfaces.CDTO;
> import org.apache.commons.collections.Closure;
> import org.apache.commons.collections.CollectionUtils;
> public class BDTOImpl implements BDTO {
> public BDTOImpl () {
> }
> private Long bId;
>
> public Long getBId() {
> return bId;
> }
> public void setBId(Long bId) {
> this.bId = bId;
> }
> private Long concurrentVersion;
>
> public Long getConcurrentVersion() {
> return concurrentVersion;
> }
> public void setConcurrentVersion(Long concurrentVersion) {
> this.concurrentVersion = concurrentVersion;
> }
> // Package level protection so that overrides can access it.
> boolean deleting = false;
> private String name;
> /**
> * Returns the Name.
> *
> * @return String - The Name
> */
> public String getName() {
> return name;
> }
> /**
> * Set the Name.
> *
> * @param name String - The Name.
> */
> public void setName(String name) {
> this.name = name;
> }
> private ADTO a;
> /**
> * Returns the A.
> *
> * @return ADTO - The A.
> */
> public ADTO getA() {
> return a;
> }
>
> public ADTO getAInternal() {
> return a;
> }
> /**
> * Updates the A.
> *
> * @param a - ADTO The A.
> */
> public void setA(ADTO a) {
> if (this.a == a) {
> return;
> }
> if (this.a != null) {
> ((ADTOImpl) this.a).removeBInternal(this);
> }
> this.a = a;
> if (a != null) {
> ((ADTOImpl) a).addBInternal(this);
> }
> }
> public void setAInternal(ADTO a) {
> if (deleting) {
> return;
> }
> if (this.a != a &&
> this.a != null && a != null) {
> throw new IllegalStateException("BDTO cannot be a member of two A collections: " + toString());
> }
> this.a = a;
> }
> private List cs;
> private List csMutable;
> { setCsMutable(new ArrayList()); }
> public List getCsMutable() {
> return csMutable;
> }
> public void setCsMutable(List cs) {
> this.cs = Collections.unmodifiableList(cs);
> this.csMutable = cs;
> }
> public List getCs() {
> return cs;
> }
>
> public void addC(CDTO c) {
> csMutable.add(c);
> ((CDTOImpl) c).setBInternal(this);
> }
> public void addCInternal(CDTO c) {
> csMutable.add(c);
> }
>
> public void removeC(CDTO c) {
> csMutable.remove(c);
> ((CDTOImpl) c).setBInternal(null);
> }
> public void removeCInternal(CDTO c) {
> if (!deleting) {
> csMutable.remove(c);
> }
> }
> public void beforeDelete() {
> // Guard to prevent infinite loop.
> if (deleting) {
> return;
> }
>
> deleting = true;
> if (this.a != null) {
> ((ADTOImpl) this.a).removeBInternal(this);
> }
> CollectionUtils.forAllDo(new ArrayList(csMutable), new Closure() {
> public void execute(Object ob) {
> ((CDTOImpl) ob).beforeDelete();
> }
> });
> }
> public int hashCode() {
> return (new HashCodeBuilder(17,37)
> .append(getBId())
> ).toHashCode();
> }
> public boolean equals(Object o) {
> boolean equals = false;
> if (o != null && o instanceof BDTO) {
> BDTO other = (BDTO) o;
> return (new EqualsBuilder()
> .append(getBId(), other.getBId())
> ).isEquals();
> }
> return equals;
> }
>
> public String toString() {
> return new ToStringBuilder(this)
> .append("bId", getBId())
> .append("name", getName())
> .toString();
> }
> }
> ******************************
> *** Mapping Document ****
> ******************************
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
> "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
> <hibernate-mapping package="com.mycompany.dal.transfer.impl" auto-import="true">
> <class name="com.mycompany.dal.transfer.impl.BDTOImpl" table="b">
> <id name="BId" type="long">
> <column name="b_id" not-null="true"/>
> <generator class="native"/>
> </id>
> <version name="concurrentVersion" column="concurrent_version" type="long"/>
> <property name="Name" type="string">
> <column name="name" length="60" not-null="false"/>
> </property>
> <many-to-one name="AInternal" class="com.mycompany.dal.transfer.impl.ADTOImpl">
> <column name="a_id" not-null="true"/>
> </many-to-one>
> <bag name="CsMutable" cascade="all-delete-orphan" inverse="true">
> <key>
> <column name="b_id" not-null="true"/>
> </key>
> <one-to-many class="com.mycompany.dal.transfer.impl.CDTOImpl"/>
> </bag>
> </class>
> </hibernate-mapping>
> *************************
> *** Generated SQL ****
> *************************
> 05:35:39,887 INFO [STDOUT] Hibernate: select adtoimpl0_.a_id as a1_162_2_, adtoimpl0_.concurrent_version as concurrent2_162_2_, adtoimpl0_.name as name162_2_, bsmutable1_.a_id as a4_4_, bsmutable1_.b_id as b1_4_, bsmutable1_.b_id as b1_164_0_, bsmutable1_.concurrent_version as concurrent2_164_0_, bsmutable1_.name as name164_0_, bsmutable1_.a_id as a4_164_0_, csmutable2_.b_id as b4_5_, csmutable2_.c_id as c1_5_, csmutable2_.c_id as c1_165_1_, csmutable2_.concurrent_version as concurrent2_165_1_, csmutable2_.name as name165_1_, csmutable2_.b_id as b4_165_1_ from a adtoimpl0_ left outer join b bsmutable1_ on adtoimpl0_.a_id=bsmutable1_.a_id left outer join c csmutable2_ on bsmutable1_.b_id=csmutable2_.b_id where adtoimpl0_.a_id=?
> 05:35:39,992 INFO [STDOUT] Hibernate: select ddtoimpl0_.d_id as d1_168_0_, ddtoimpl0_.concurrent_version as concurrent2_168_0_, ddtoimpl0_.name as name168_0_, ddtoimpl0_.c_id as c4_168_0_ from d ddtoimpl0_ where ddtoimpl0_.d_id=?
> 05:35:40,007 INFO [STDOUT] Hibernate: select dsmutable0_.c_id as c4_1_, dsmutable0_.d_id as d1_1_, dsmutable0_.d_id as d1_168_0_, dsmutable0_.concurrent_version as concurrent2_168_0_, dsmutable0_.name as name168_0_, dsmutable0_.c_id as c4_168_0_ from d dsmutable0_ where dsmutable0_.c_id=?
> *** Start Extra Updates **
> 05:35:40,030 INFO [STDOUT] Hibernate: update b set concurrent_version=?, name=?, a_id=? where b_id=? and concurrent_version=?
> 05:35:40,038 INFO [STDOUT] Hibernate: update c set concurrent_version=?, name=?, b_id=? where c_id=? and concurrent_version=?
> 05:35:40,044 INFO [STDOUT] Hibernate: update a set concurrent_version=?, name=? where a_id=? and concurrent_version=?
> *** End Extra Updates **
> **************************
> *** Accessing code ****
> **************************
> DataAccessLayer dal = DataAccessLayerBuilder.getInstance();
>
> ADAO aDAO = dal.getADAO();
> BDAO bDAO = dal.getBDAO();
> CDAO cDAO = dal.getCDAO();
> DDAO dDAO = dal.getDDAO();
>
> ADTO a = aDAO.newA();
> a.setAId(new Long(1));
> a.setConcurrentVersion(new Long(0));
> a.setName("A");
>
> BDTO b = bDAO.newB();
> CDTO c = cDAO.newC();
> DDTO d = dDAO.newD();
> b.setBId(new Long(2));
> c.setCId(new Long(3));
> d.setDId(new Long(4));
> b.setConcurrentVersion(new Long(0));
> c.setConcurrentVersion(new Long(0));
> d.setConcurrentVersion(new Long(0));
> b.setName("B");
> c.setName("C");
> d.setName("D");
> b.setA(a);
> c.setB(b);
> d.setC(c);
>
> aDAO.mergeA(a);
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira
18 years, 2 months
[Hibernate-JIRA] Commented: (HHH-1401) session.merge() executes unnecessary updates when one-to-many relationship is defined.
by David Trott (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1401?page=c... ]
David Trott commented on HHH-1401:
----------------------------------
All the cases I tested were consistent with Steve Ebersole's test case (I am not aware of any other ones).
> session.merge() executes unnecessary updates when one-to-many relationship is defined.
> --------------------------------------------------------------------------------------
>
> Key: HHH-1401
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1401
> Project: Hibernate3
> Type: Bug
> Components: core
> Versions: 3.1.1
> Environment: Hibernate 3.1.1
> Postgres 8.03
> Java 1.4.2_09
> Reporter: David Trott
> Assignee: Steve Ebersole
> Fix For: 3.2.1
> Attachments: HHH-1401.zip, HHH1401Test.java, Screenshot-Debug - AbstractPersistentCollection.class - Eclipse SDK .png, TEST-org.hibernate.test.optlock.OptimisticLockTest.txt
>
>
> I am attempting to use the session.merge() functionality in order to synchronize the state of the data coming from the web tier with the database, however I am seeing unnecessary updates (when nothing has changed).
> In order to track down the problem I created a test case with four tables and four classes (A,B,C and D)
> Where:
> A is the parent of B.
> B is the parent of C.
> C is the parent of D.
> And there are no other relationships present.
> All these relationships are bi-directional with the one-to-many side marked as inverse="true" and cascade="all-delete-orphan".
> The merge() is working fine (the data gets updated correctly) except that when there is no change to the data hibernate still runs updates on A,B and C however not on D (D has no one-to-many relationships).
> I am including the code and hibernate mapping for B as it is representative of the code for all the other classes.
> I am no expect on the hibernate implementation, but my suspicion of the cause is when hibernate substitutes a PersistentBag for the ArrayList in the merged object (associated with the session) it detects this as a change and hence triggers the update, unfortunately the data itself has not changed hence no update is necessary.
> FYI: If I change the initialization of the bags from "new ArrayList()" to "new PersistentBag()" the extra updates go away, however then it doesn't save real changes correctly.
> package com.mycompany.dal.transfer.impl;
> import org.apache.commons.lang.builder.EqualsBuilder;
> import org.apache.commons.lang.builder.HashCodeBuilder;
> import org.apache.commons.lang.builder.ToStringBuilder;
> import java.util.ArrayList;
> import java.util.Collections;
> import java.util.List;
> import com.mycompany.dal.transfer.interfaces.ADTO;
> import com.mycompany.dal.transfer.interfaces.BDTO;
> import com.mycompany.dal.transfer.interfaces.CDTO;
> import org.apache.commons.collections.Closure;
> import org.apache.commons.collections.CollectionUtils;
> public class BDTOImpl implements BDTO {
> public BDTOImpl () {
> }
> private Long bId;
>
> public Long getBId() {
> return bId;
> }
> public void setBId(Long bId) {
> this.bId = bId;
> }
> private Long concurrentVersion;
>
> public Long getConcurrentVersion() {
> return concurrentVersion;
> }
> public void setConcurrentVersion(Long concurrentVersion) {
> this.concurrentVersion = concurrentVersion;
> }
> // Package level protection so that overrides can access it.
> boolean deleting = false;
> private String name;
> /**
> * Returns the Name.
> *
> * @return String - The Name
> */
> public String getName() {
> return name;
> }
> /**
> * Set the Name.
> *
> * @param name String - The Name.
> */
> public void setName(String name) {
> this.name = name;
> }
> private ADTO a;
> /**
> * Returns the A.
> *
> * @return ADTO - The A.
> */
> public ADTO getA() {
> return a;
> }
>
> public ADTO getAInternal() {
> return a;
> }
> /**
> * Updates the A.
> *
> * @param a - ADTO The A.
> */
> public void setA(ADTO a) {
> if (this.a == a) {
> return;
> }
> if (this.a != null) {
> ((ADTOImpl) this.a).removeBInternal(this);
> }
> this.a = a;
> if (a != null) {
> ((ADTOImpl) a).addBInternal(this);
> }
> }
> public void setAInternal(ADTO a) {
> if (deleting) {
> return;
> }
> if (this.a != a &&
> this.a != null && a != null) {
> throw new IllegalStateException("BDTO cannot be a member of two A collections: " + toString());
> }
> this.a = a;
> }
> private List cs;
> private List csMutable;
> { setCsMutable(new ArrayList()); }
> public List getCsMutable() {
> return csMutable;
> }
> public void setCsMutable(List cs) {
> this.cs = Collections.unmodifiableList(cs);
> this.csMutable = cs;
> }
> public List getCs() {
> return cs;
> }
>
> public void addC(CDTO c) {
> csMutable.add(c);
> ((CDTOImpl) c).setBInternal(this);
> }
> public void addCInternal(CDTO c) {
> csMutable.add(c);
> }
>
> public void removeC(CDTO c) {
> csMutable.remove(c);
> ((CDTOImpl) c).setBInternal(null);
> }
> public void removeCInternal(CDTO c) {
> if (!deleting) {
> csMutable.remove(c);
> }
> }
> public void beforeDelete() {
> // Guard to prevent infinite loop.
> if (deleting) {
> return;
> }
>
> deleting = true;
> if (this.a != null) {
> ((ADTOImpl) this.a).removeBInternal(this);
> }
> CollectionUtils.forAllDo(new ArrayList(csMutable), new Closure() {
> public void execute(Object ob) {
> ((CDTOImpl) ob).beforeDelete();
> }
> });
> }
> public int hashCode() {
> return (new HashCodeBuilder(17,37)
> .append(getBId())
> ).toHashCode();
> }
> public boolean equals(Object o) {
> boolean equals = false;
> if (o != null && o instanceof BDTO) {
> BDTO other = (BDTO) o;
> return (new EqualsBuilder()
> .append(getBId(), other.getBId())
> ).isEquals();
> }
> return equals;
> }
>
> public String toString() {
> return new ToStringBuilder(this)
> .append("bId", getBId())
> .append("name", getName())
> .toString();
> }
> }
> ******************************
> *** Mapping Document ****
> ******************************
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
> "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
> <hibernate-mapping package="com.mycompany.dal.transfer.impl" auto-import="true">
> <class name="com.mycompany.dal.transfer.impl.BDTOImpl" table="b">
> <id name="BId" type="long">
> <column name="b_id" not-null="true"/>
> <generator class="native"/>
> </id>
> <version name="concurrentVersion" column="concurrent_version" type="long"/>
> <property name="Name" type="string">
> <column name="name" length="60" not-null="false"/>
> </property>
> <many-to-one name="AInternal" class="com.mycompany.dal.transfer.impl.ADTOImpl">
> <column name="a_id" not-null="true"/>
> </many-to-one>
> <bag name="CsMutable" cascade="all-delete-orphan" inverse="true">
> <key>
> <column name="b_id" not-null="true"/>
> </key>
> <one-to-many class="com.mycompany.dal.transfer.impl.CDTOImpl"/>
> </bag>
> </class>
> </hibernate-mapping>
> *************************
> *** Generated SQL ****
> *************************
> 05:35:39,887 INFO [STDOUT] Hibernate: select adtoimpl0_.a_id as a1_162_2_, adtoimpl0_.concurrent_version as concurrent2_162_2_, adtoimpl0_.name as name162_2_, bsmutable1_.a_id as a4_4_, bsmutable1_.b_id as b1_4_, bsmutable1_.b_id as b1_164_0_, bsmutable1_.concurrent_version as concurrent2_164_0_, bsmutable1_.name as name164_0_, bsmutable1_.a_id as a4_164_0_, csmutable2_.b_id as b4_5_, csmutable2_.c_id as c1_5_, csmutable2_.c_id as c1_165_1_, csmutable2_.concurrent_version as concurrent2_165_1_, csmutable2_.name as name165_1_, csmutable2_.b_id as b4_165_1_ from a adtoimpl0_ left outer join b bsmutable1_ on adtoimpl0_.a_id=bsmutable1_.a_id left outer join c csmutable2_ on bsmutable1_.b_id=csmutable2_.b_id where adtoimpl0_.a_id=?
> 05:35:39,992 INFO [STDOUT] Hibernate: select ddtoimpl0_.d_id as d1_168_0_, ddtoimpl0_.concurrent_version as concurrent2_168_0_, ddtoimpl0_.name as name168_0_, ddtoimpl0_.c_id as c4_168_0_ from d ddtoimpl0_ where ddtoimpl0_.d_id=?
> 05:35:40,007 INFO [STDOUT] Hibernate: select dsmutable0_.c_id as c4_1_, dsmutable0_.d_id as d1_1_, dsmutable0_.d_id as d1_168_0_, dsmutable0_.concurrent_version as concurrent2_168_0_, dsmutable0_.name as name168_0_, dsmutable0_.c_id as c4_168_0_ from d dsmutable0_ where dsmutable0_.c_id=?
> *** Start Extra Updates **
> 05:35:40,030 INFO [STDOUT] Hibernate: update b set concurrent_version=?, name=?, a_id=? where b_id=? and concurrent_version=?
> 05:35:40,038 INFO [STDOUT] Hibernate: update c set concurrent_version=?, name=?, b_id=? where c_id=? and concurrent_version=?
> 05:35:40,044 INFO [STDOUT] Hibernate: update a set concurrent_version=?, name=? where a_id=? and concurrent_version=?
> *** End Extra Updates **
> **************************
> *** Accessing code ****
> **************************
> DataAccessLayer dal = DataAccessLayerBuilder.getInstance();
>
> ADAO aDAO = dal.getADAO();
> BDAO bDAO = dal.getBDAO();
> CDAO cDAO = dal.getCDAO();
> DDAO dDAO = dal.getDDAO();
>
> ADTO a = aDAO.newA();
> a.setAId(new Long(1));
> a.setConcurrentVersion(new Long(0));
> a.setName("A");
>
> BDTO b = bDAO.newB();
> CDTO c = cDAO.newC();
> DDTO d = dDAO.newD();
> b.setBId(new Long(2));
> c.setCId(new Long(3));
> d.setDId(new Long(4));
> b.setConcurrentVersion(new Long(0));
> c.setConcurrentVersion(new Long(0));
> d.setConcurrentVersion(new Long(0));
> b.setName("B");
> c.setName("C");
> d.setName("D");
> b.setA(a);
> c.setB(b);
> d.setC(c);
>
> aDAO.mergeA(a);
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira
18 years, 2 months
[Hibernate-JIRA] Closed: (HHH-1629) SchemaUpdate/validator doesn't listen to quoting
by Max Rydahl Andersen (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1629?page=all ]
Max Rydahl Andersen closed HHH-1629:
------------------------------------
Resolution: Fixed
thanks for verifying.
...yes, lets hope its only the mysql driver that is weird in this respect.
p.s. hbmlint is also an option here (it gives more info than the current schemavalidator)
> SchemaUpdate/validator doesn't listen to quoting
> ------------------------------------------------
>
> Key: HHH-1629
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1629
> Project: Hibernate3
> Type: Bug
> Versions: 3.1.2
> Environment: Hibernate 3.1.2
> Postgres 8.0.4
> Linux
> Reporter: Nicklas Nordborg
> Priority: Trivial
> Fix For: 3.2.1
> Attachments: AffyFeatureData.hbm.xml, patch-HHH-1629.txt
>
>
> The SchemaUpdate only generates SQL with CREATE TABLE statements and can't update existing tables.
> With debugging turned on the SchemaUpdate reports:
> 11:25:22,599 INFO SchemaUpdate:114 - Running hbm2ddl schema update
> 11:25:22,599 INFO SchemaUpdate:126 - fetching database metadata
> .11:25:22,771 INFO SchemaUpdate:142 - updating schema
> 11:25:22,803 INFO DatabaseMetadata:91 - table not found: AffyFeatures
> 11:25:22,830 INFO DatabaseMetadata:91 - table not found: AnnotationSets
> 11:25:22,855 INFO DatabaseMetadata:91 - table not found: AnnotationTypeItems
> .... and so on for another 100+ tables
> All tables except two exists in the database. The two new tables are created successfully by SchemaUpdate.
> I attach one of my mapping files (generated by XDoclet).
> I had a quick look at the SchemaUpdate code (which calls DatabaseMetadata) and I think the problem is that it converts the table names to upper or lower case, even though I have quoted them in the mapping files. If the DatabaseMetadata.getTableMetadata could take a Table object as a parameter instead of the name, schema and catalog, it could check the Table.isQuoted() method before converting any names to upper or lower case. It seems like this method is only used by the Configuration class so it shouldn't be too hard to fix.
> I could do the fix myself, but I will only be able to validate it against Postgres and MySQL using quoted table names. So, others would probably have to validate it agains other databases and using unquoted table names.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira
18 years, 2 months
[Hibernate-JIRA] Created: (HHH-2162) Optimisitic Locking unusable with 1..N of Set or List
by Olli Blackburn (JIRA)
Optimisitic Locking unusable with 1..N of Set or List
-----------------------------------------------------
Key: HHH-2162
URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2162
Project: Hibernate3
Type: Bug
Components: core
Versions: 3.2.0.ga
Environment: Core 3.2 GA
EM 3.2 GA
HSQLDB 1.8.0.2 in memory
Reporter: Olli Blackburn
Priority: Blocker
Attachments: Playpen.zip
Calling merge() on an unmodified entity with 1..N relationship using Set or List results in the entity being marked dirty, its version number is increased and an SQL UPDATE performed on it. This makes it impossible to achieve any kind of sensible concurrency in our application which makes extensive use of detached objects.
See the attached test case (packaged as a complete eclipse 3.2 project). Set EJB3_HOME, HIBERNATE_HOME and HSQLDB_HOME in your eclipse workspace preferences and then run the included PojoTest launcher to see it run.
The test populates the DB, does a select by name, merge, merge and select by name again. Each of these five steps is in its own Tx and entity manager. The test is repeated for Set, Map and List. Interesting Map seems to work, but as our application doesn't use Maps that's little comfort to us. The pojo is not being modified (by my code) between the merge calls(), yet I get the following output (each print is before the commit following the operation):
findByUniqueName: PojoHashSet4 version=2
merge: PojoHashSet4 version=2
merge: PojoHashSet4 version=3
findByUniqueName: PojoHashSet4 version=5
findByUniqueName: PojoHashMap4 version=0
merge: PojoHashMap4 version=0
merge: PojoHashMap4 version=0
findByUniqueName: PojoHashMap4 version=0
findByUniqueName: PojoArrayList4 version=0
merge: PojoArrayList4 version=0
merge: PojoArrayList4 version=1
findByUniqueName: PojoArrayList4 version=2
HHH-1401 and HHH-1668 seem like they might be related to my problem, but debugging my test case shows otherwise. The problem seems to be caused by the replacement of the empty collection with a new empty collection. More specifically, the empty target collection is cleared, marking it dirty, even though it contains no members is is about to have nothing copied in it. This occurs in org.hibernate.type.CollectionType.replaceElements().
Looking at the code paths I think the problem runs deeper than my empty collection case. If the source and target being copied by replaceElements() are identical (whether zero length or not), the target will be marked dirty due to the result.clear() call in replaceElements(). It seems there needs to be a pre-check for this case to avoid the whole clear and copy process with it's associated setting of "dirtiness".
I'm attaching a patch for CollectionType which fixes the problem in the testing we've performed.
Feedback and comments appreciated.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira
18 years, 2 months
[Hibernate-JIRA] Commented: (HHH-1629) SchemaUpdate/validator doesn't listen to quoting
by Nicklas Nordborg (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1629?page=c... ]
Nicklas Nordborg commented on HHH-1629:
---------------------------------------
It now works for both MySQL and Postgres. Thank you very much for fixing this. Hope there will be no problem with other JDBC drivers.
> SchemaUpdate/validator doesn't listen to quoting
> ------------------------------------------------
>
> Key: HHH-1629
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1629
> Project: Hibernate3
> Type: Bug
> Versions: 3.1.2
> Environment: Hibernate 3.1.2
> Postgres 8.0.4
> Linux
> Reporter: Nicklas Nordborg
> Priority: Trivial
> Fix For: 3.2.1
> Attachments: AffyFeatureData.hbm.xml, patch-HHH-1629.txt
>
>
> The SchemaUpdate only generates SQL with CREATE TABLE statements and can't update existing tables.
> With debugging turned on the SchemaUpdate reports:
> 11:25:22,599 INFO SchemaUpdate:114 - Running hbm2ddl schema update
> 11:25:22,599 INFO SchemaUpdate:126 - fetching database metadata
> .11:25:22,771 INFO SchemaUpdate:142 - updating schema
> 11:25:22,803 INFO DatabaseMetadata:91 - table not found: AffyFeatures
> 11:25:22,830 INFO DatabaseMetadata:91 - table not found: AnnotationSets
> 11:25:22,855 INFO DatabaseMetadata:91 - table not found: AnnotationTypeItems
> .... and so on for another 100+ tables
> All tables except two exists in the database. The two new tables are created successfully by SchemaUpdate.
> I attach one of my mapping files (generated by XDoclet).
> I had a quick look at the SchemaUpdate code (which calls DatabaseMetadata) and I think the problem is that it converts the table names to upper or lower case, even though I have quoted them in the mapping files. If the DatabaseMetadata.getTableMetadata could take a Table object as a parameter instead of the name, schema and catalog, it could check the Table.isQuoted() method before converting any names to upper or lower case. It seems like this method is only used by the Configuration class so it shouldn't be too hard to fix.
> I could do the fix myself, but I will only be able to validate it against Postgres and MySQL using quoted table names. So, others would probably have to validate it agains other databases and using unquoted table names.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira
18 years, 2 months
[Hibernate-JIRA] Reopened: (HHH-1629) SchemaUpdate/validator doesn't listen to quoting
by Max Rydahl Andersen (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1629?page=all ]
Max Rydahl Andersen reopened HHH-1629:
--------------------------------------
I've applied a fix to branch3_2 for mysql. Could you verify on postgres and mysql again ? Thanks.
> SchemaUpdate/validator doesn't listen to quoting
> ------------------------------------------------
>
> Key: HHH-1629
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1629
> Project: Hibernate3
> Type: Bug
> Versions: 3.1.2
> Environment: Hibernate 3.1.2
> Postgres 8.0.4
> Linux
> Reporter: Nicklas Nordborg
> Priority: Trivial
> Fix For: 3.2.1
> Attachments: AffyFeatureData.hbm.xml, patch-HHH-1629.txt
>
>
> The SchemaUpdate only generates SQL with CREATE TABLE statements and can't update existing tables.
> With debugging turned on the SchemaUpdate reports:
> 11:25:22,599 INFO SchemaUpdate:114 - Running hbm2ddl schema update
> 11:25:22,599 INFO SchemaUpdate:126 - fetching database metadata
> .11:25:22,771 INFO SchemaUpdate:142 - updating schema
> 11:25:22,803 INFO DatabaseMetadata:91 - table not found: AffyFeatures
> 11:25:22,830 INFO DatabaseMetadata:91 - table not found: AnnotationSets
> 11:25:22,855 INFO DatabaseMetadata:91 - table not found: AnnotationTypeItems
> .... and so on for another 100+ tables
> All tables except two exists in the database. The two new tables are created successfully by SchemaUpdate.
> I attach one of my mapping files (generated by XDoclet).
> I had a quick look at the SchemaUpdate code (which calls DatabaseMetadata) and I think the problem is that it converts the table names to upper or lower case, even though I have quoted them in the mapping files. If the DatabaseMetadata.getTableMetadata could take a Table object as a parameter instead of the name, schema and catalog, it could check the Table.isQuoted() method before converting any names to upper or lower case. It seems like this method is only used by the Configuration class so it shouldn't be too hard to fix.
> I could do the fix myself, but I will only be able to validate it against Postgres and MySQL using quoted table names. So, others would probably have to validate it agains other databases and using unquoted table names.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://opensource.atlassian.com/projects/hibernate/secure/Administrators....
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira
18 years, 2 months