[Hibernate-JIRA] Closed: (HHH-1021) OneToManyPersister issues redundant update in "insertRows" when using non-nullable JoinColumn
by Steve Ebersole (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1021?page=c... ]
Steve Ebersole closed HHH-1021.
-------------------------------
Closing stale resolved issues
> OneToManyPersister issues redundant update in "insertRows" when using non-nullable JoinColumn
> ---------------------------------------------------------------------------------------------
>
> Key: HHH-1021
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1021
> Project: Hibernate Core
> Issue Type: Improvement
> Components: core
> Environment: Hibernate 3.1beta3, annotations 3.1beta5, MSSQL
> Reporter: John
> Priority: Minor
>
> I have a parent/child relationship that is unidirectional, mapped by the parent side, with the foreign key field in the child table. (The docs say this isn't recommended, but no reason is given, so I'm doing this because it fits what I need.) This relationship works, but the way the sql is generated varies depending on two factors: the nullability of the join column (@JoinColumn), and the cascade settings.
> Consider code like this (each step a new session):
> 1. save new parent and child
> 2. remove old child (Set.clear) and add new one
> 3. remove parent
> If the join column is nullable, the somewhat ungainly set of sql is executed:
> 1.
> insert into parent (id, prop)
> insert into child (id, prop)
> update child set parent_id = ? where id = ?
> 2.
> insert into child (id, prop) (add new child)
> update child set parent = null where id = ? (remove old child)
> update child set parent = ? where id = ? (associate new child to parent)
> delete from child where id = ? (only if cascade delete orphan)
> 3.
> update child set parent = null where id = ?
> delete from parent where id = ?
> delete from child where id = ?
>
> If the join column is not nullable, then it seems that the sql is more efficient at first, but there are two problems. The first problem is that unless cascade delete orphan is specified, clearing the existing set of children on the parent object does not remove the children. The in-memory set won't contain them, but the next time that parent is loaded they will reappear. This makes sense in a way, since the way children are "deleted" is to set the parent reference to null, which can't happen if the column doesn't allow nulls. The persister doesn't issue the "update-to-null" delete, and the child stays attached to the parent. Now, assuming that the set-to-null-and-delete-later method of dealing with children is the best, then I think a documentation addition or warning in the code would be useful to help people avoid this situation.
> The second problem, and the one relating to the subject of the bug, has to do with the sql generated when the join column is not nullable. Assuming that cascade delete orphan is on for the relationship (which it has to be for it to be usable at all), sql like the following is generated:
> 1.
> insert into parent (id, prop)
> insert into child (id, parent_id, prop)
> update child set parent_id = ? where id = ? (redundant)
> 2.
> insert into child (id, parent_id, prop) (add new child)
> update child set parent_id = ? where id = ? (redundant)
> delete from child where id = ? (remove old child)
> 3.
> delete from child where id = ?
> delete from parent where id = ?
> Now, this is more appealing, firstly because the parent_id column is required in child. Secondly, instead of issuing an update and a delete to get rid of the child, just a delete is issued. However, while the insert has improved, the update to set the parent id is still issued. This doesn't hurt anything, but it is redundant since the parent_id is set on the insert. If this were removed, then the whole situation would be better: one insert to add instead of an insert and update, and one delete to remove instead of an update and a delete.
> Currently, OneToManyPersister has the following code:
> protected boolean isRowDeleteEnabled() {
> return keyIsUpdateable && keyIsNullable;
> }
> protected boolean isRowInsertEnabled() {
> return keyIsUpdateable;
> }
> My first thought at removing the redundant update is to add "&& keyIsNullable" to isRowInsertEnabled (so it matches isRowDeleteEnabled). Changing that will positively affect AbstractCollectionPersister.insertRows, removing the redundant sql. However, that value is also used in OneToManyPersister.doUpdateRows also AbstractCollectionPersister.recreate. I don't know exactly how these other uses would be affected by changing the one method. It could be that the change applies to all, or perhaps it should only affect insertRows. Either way, the change should be simple, but someone with deeper knowledge needs to evaluate the impact on the other uses of that value.
> Thanks
> John
--
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
15 years
[Hibernate-JIRA] Closed: (HHH-1433) many-to-many with additional 'with' join clause generates bad sql
by Steve Ebersole (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1433?page=c... ]
Steve Ebersole closed HHH-1433.
-------------------------------
Closing stale resolved issues
> many-to-many with additional 'with' join clause generates bad sql
> -----------------------------------------------------------------
>
> Key: HHH-1433
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1433
> Project: Hibernate Core
> Issue Type: Bug
> Components: query-hql
> Affects Versions: 3.1 rc2, 3.1.2
> Environment: java 1.4 - hibernate 3.1.2 - mysql 5
> Reporter: Dieter Cailliau
> Assignee: Steve Ebersole
> Priority: Minor
> Fix For: 3.1.3
>
>
> Say we have a many-to-many relation between Service and Package.
> I want all Service-Package combinations, for packages having title 'ok'. If for some service, there is no such a package, then i want the service anyways (with nulls in other places).
> select service,package from Service service left join service.packages package with package.title='ok'
> This produces sql
> select ...
> from SERVICE service0_
> left outer join PACKAGE_SERVICE packages1_ on service0_.ID=packages1_.SERVICE_ID
> and (package2_.TITLE='ok') -- [this line is bad]
> left outer join PACKAGE package2_ on packages1_.PACKAGE_ID=package2_.ID
> and (package2_.TITLE='ok')
> What happend? The hql-with-clause is present twice in the sql. The first occurence (at the join-table) is wrong: package2_ is not defined at that point.
> If i move the with clause into a where clause, it works fine, but this does not give me the "services that have no such package" (= it is equivalent with the inner join, but not with the left join).
--
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
15 years
[Hibernate-JIRA] Closed: (HHH-1094) ClassCastException on session.get or session.load with BigInteger as primary key
by Steve Ebersole (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1094?page=c... ]
Steve Ebersole closed HHH-1094.
-------------------------------
Closing stale resolved issues
> ClassCastException on session.get or session.load with BigInteger as primary key
> --------------------------------------------------------------------------------
>
> Key: HHH-1094
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1094
> Project: Hibernate Core
> Issue Type: Bug
> Components: core
> Affects Versions: 3.1 rc2
> Environment: Tomcat 5.5.4 on Windows XP Professional
> Oracle 9.2.0.6.0 64bit on Solaris
> Java 1.5.0_05
> Hibernate 3.1rc2
> Reporter: Dirk Weigenand
>
> The following code
> public static Produkt findProduktById( String produktId ) {
> Session session = HibernateUtil.currentSession();
> log.info( "produktId: " + produktId );
> Produkt produkt = (Produkt)session.get( Produkt.class, new BigInteger( produktId ) );
> HibernateUtil.closeSession();
>
> return produkt;
> }
> yields following exeption when executed:
> java.lang.ClassCastException: java.math.BigInteger
> org.hibernate.type.BigDecimalType.getHashCode(BigDecimalType.java:48)
> org.hibernate.type.AbstractType.getHashCode(AbstractType.java:120)
> org.hibernate.engine.EntityKey.getHashCode(EntityKey.java:68)
> org.hibernate.engine.EntityKey.<init>(EntityKey.java:41)
> org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:76)
> org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:809)
> org.hibernate.impl.SessionImpl.get(SessionImpl.java:749)
> org.hibernate.impl.SessionImpl.get(SessionImpl.java:742)
> de.gisa.orderit.beans.ProduktFinder.findProduktById(ProduktFinder.java:71)
> The class is mapped as follows:
> <class name="de.gisa.orderit.beans.Produkt" table="ORD_PRODUKTE" schema="ORDERITT">
> <id name="idProdPk" type="big_decimal">
> <column name="ID_PROD_PK" precision="22" scale="0" />
> <generator class="assigned" />
> </id>
> <many-to-one name="Produktkategorien" class="de.gisa.orderit.beans.Produktkategorie" fetch="select">
> <column name="ID_KAT_FK" precision="22" scale="0" not-null="true" />
> </many-to-one>
> <many-to-one name="Formular" class="de.gisa.orderit.beans.Formular" fetch="select">
> <column name="ID_FRM_FK" precision="22" scale="0" />
> </many-to-one>
> <many-to-one name="Mandant" class="de.gisa.orderit.beans.Mandant" fetch="select">
> <column name="ID_MDT_FK" precision="22" scale="0" not-null="true" />
> </many-to-one>
> <many-to-one name="User" class="de.gisa.orderit.beans.User" fetch="select">
> <column name="ID_USER_AV_FK" precision="22" scale="0" not-null="true" />
> </many-to-one>
> <many-to-one name="Produkttyp" class="de.gisa.orderit.beans.Produkttyp" fetch="select">
> <column name="ID_PTY_FK" precision="22" scale="0" not-null="true" />
> </many-to-one>
> <property name="name" type="string">
> <column name="NAME" length="100" not-null="true" />
> </property>
> <property name="beschreibung" type="string">
> <column name="BESCHREIBUNG" length="1000" />
> </property>
> <property name="plb" type="string">
> <column name="PLB" length="10" />
> </property>
> <property name="prodAktiv" type="character">
> <column name="PROD_AKTIV" length="1" not-null="true" />
> </property>
> <set name="Bestellungs" inverse="true">
> <key>
> <column name="ID_PROD_FK" precision="22" scale="0" not-null="true" />
> </key>
> <one-to-many class="de.gisa.orderit.beans.Bestellung" />
> </set>
> </class>
> Thanks.
> Dirk
--
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
15 years
[Hibernate-JIRA] Closed: (HHH-1336) ForeignGenerator does not handle transient entities with an entity-name properly
by Steve Ebersole (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1336?page=c... ]
Steve Ebersole closed HHH-1336.
-------------------------------
Closing stale resolved issues
> ForeignGenerator does not handle transient entities with an entity-name properly
> --------------------------------------------------------------------------------
>
> Key: HHH-1336
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1336
> Project: Hibernate Core
> Issue Type: Bug
> Components: core
> Affects Versions: 3.1
> Environment: Hibernate 3.1, any platform/database
> Reporter: Paul Andrews
> Assignee: Steve Ebersole
> Priority: Minor
> Fix For: 3.1.1
>
>
> I have an entity that has a one-to-one relationship with another entity, i.e. (ommitting a bunch of mandatory stuff for the sake of brevity):
> <class entity-name="AnEntity">
> <id name="primaryKey">
> <generator class="foreign">
> <param name="property">aProperty</param>
> </generator>
> </id>
> <one-to-one name="aProperty" entity-name="AnotherEntity"/>
> </class>
> I then create a detached (aka transient) instance of AnEntity with an embedded detached instance of AnotherEntity with both of their id's set to null and then do a saveOrUpdate(). Hibernate then throws an 'unknown entity mapping' exception with the classname of the instance of AnotherEntity. In other words it is looking for a mapping for the actual class name of the associated entity when it should be looking for a mapping for the entity-name of the associated entity.
> Tracing into the code ForeignGenerator.generate() calls session.save as follows:
> Serializable id;
> try {
> id = ForeignKeys.getEntityIdentifierIfNotUnsaved(
> type.getAssociatedEntityName(),
> associatedObject,
> sessionImplementor);
> } catch (TransientObjectException toe) {
> id = session.save(associatedObject);
> }
> Modifying the session.save() call as follows seems to fix the problem:
> Serializable id;
> try {
> id = ForeignKeys.getEntityIdentifierIfNotUnsaved(
> type.getAssociatedEntityName(),
> associatedObject,
> sessionImplementor);
> } catch (TransientObjectException toe) {
> id = session.save(type.getAssociatedEntityName(), associatedObject);
> }
>
--
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
15 years
[Hibernate-JIRA] Closed: (HHH-1044) Doc improvement for assigned identifiers and unsaved value
by Steve Ebersole (JIRA)
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-1044?page=c... ]
Steve Ebersole closed HHH-1044.
-------------------------------
Closing stale resolved issues
> Doc improvement for assigned identifiers and unsaved value
> ----------------------------------------------------------
>
> Key: HHH-1044
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1044
> Project: Hibernate Core
> Issue Type: Improvement
> Components: documentation
> Affects Versions: 3.1 rc 1
> Environment: hibernate 3.1 beta3, mssql
> Reporter: John
> Priority: Trivial
>
> --current doc--
> 6.1.4.5. Assigned identifiers
> If you want the application to assign identifiers (as opposed to having Hibernate generate them), you may use the assigned generator. This special generator will use the identifier value already assigned to the object's identifier property. This generator is used when the primary key is a natural key instead of a surrogate key. This is the default behavior if you do no specify a <generator> element.
> Choosing the assigned generator makes Hibernate use unsaved-value="undefined", forcing Hibernate to go to the database to determine if an instance is transient or detached, unless there is a version or timestamp property, or you define Interceptor.isUnsaved().
> --/current doc--
> I have found the part about being forced to use unsaved-value="undefined" to be true in Hibernate 2. However, I had some mappings that were in use in Hibernate 2 that were migrated to Hibernate 3. A little bit of copy and paste from an identity column mapping to an assigned mapping left me with a mapping like this:
> <id name="id" column="id" type="int" unsaved-value="-1">
> <generator class="assigned" />
> </id>
> This worked in 2, but did not in 3. It appeared that Hibernate worked halfway. It did a select to determine if the row was in the database, which means it saw the assigned part. However, even after determining the row wasn't there it still tried to do an update, indicating that at that point it was checking the unsaved-value. The update failed since with an unexpected rowcount error. Changing unsaved-value to "undefined" or removing the attribute completely fixed the problem and allowed the insert to work as expected.
> Obviously the mapping is internally inconsisten, but I think either Hibernate should be changed to ignore the unsaved-value for assigned ids, or the docs should be changed to better indicate that it's best to leave unsaved-value off if you are using assigned identifiers.
--
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
15 years