Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Hibernate/JPA MySql unidirectional OneToMany Mapping save exception

 
manvendra P singh
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a Unidirectional OneToMany mapping defined in a class and the other class is autonomous in itself.
but when I try to save the owner class EXPENSE_ITEM, hibernate throws exception because it tries to insert the child class without the foreign key.
Both the tables have primary key in mysql database as AUTO_INCREMENT
what is wrong in configuration.







20:21:05,784 DEBUG [org.hibernate.engine.spi.ActionQueue] - Executing identity-insert immediately
20:21:05,786 DEBUG [org.hibernate.SQL] - insert into EXPENSE_ITEM (DESCRIPTION, EXPENSE_DATE, EXPENSE_GROUP_ID) values (?, ?, ?)
20:21:05,882 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] - Natively generated identity: 12
20:21:05,883 DEBUG [org.hibernate.engine.spi.ActionQueue] - Executing identity-insert immediately
20:21:05,884 DEBUG [org.hibernate.SQL] - insert into EXPENSE_TRANSACTION (AMOUNT, PARTICIPANT_ID, TRANSACTION_TYPE) values (?, ?, ?)
20:21:05,985 DEBUG [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - Field 'EXPENSE_ITEM_ID' doesn't have a default value [n/a


Hibernate is not inserting the foreign key column in second insert. What should I change ?
 
Tim Holloway
Saloon Keeper
Posts: 18367
56
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're attempting to treat ORM objects like database tables. ORMs are designed to treat database tables like Java objects.

It really isn't a good idea to treat line-item rows as parent-less objects. For one thing, the database itself doesn't do things that way. SQL DBMS's are - with rare exceptions - not capable of creating single rows which themselves point to an undefined number of other items. Instead, the parent/child relationship is defined by having the children contain a reference back to their parent. Or in some cases, via a linkage table, but that's generally something you want to avoid for 1/many sets.

In the case of one of my most important databases, I don't use automatic key generation. It tends to lack flexibility and vendor-independence. Instead the IDs for the parents are obtained via manual key generation and the IDs for the children are compound keys of the parent ID plus a sequence ID, thus allowing consistent ordering of the line items (since in a "pure" SQL implementation, there is no natural record order).

To implement this sort of construction, I define a parent object reference in the child record and an ID class whose members are the parent ID and sequence number.
 
manvendra P singh
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tim Holloway wrote:You're attempting to treat ORM objects like database tables. ORMs are designed to treat database tables like Java objects.

It really isn't a good idea to treat line-item rows as parent-less objects. For one thing, the database itself doesn't do things that way. SQL DBMS's are - with rare exceptions - not capable of creating single rows which themselves point to an undefined number of other items. Instead, the parent/child relationship is defined by having the children contain a reference back to their parent. Or in some cases, via a linkage table, but that's generally something you want to avoid for 1/many sets.

In the case of one of my most important databases, I don't use automatic key generation. It tends to lack flexibility and vendor-independence. Instead the IDs for the parents are obtained via manual key generation and the IDs for the children are compound keys of the parent ID plus a sequence ID, thus allowing consistent ordering of the line items (since in a "pure" SQL implementation, there is no natural record order).

To implement this sort of construction, I define a parent object reference in the child record and an ID class whose members are the parent ID and sequence number.


Thanks for elaborative response Tim, But what you'r answer exactly suggesting is, to implement "Bidirectional OneToMany/ManyToOne Relationship", But as we know "Unidirectional OneToMany relationship" is also a concepts. Thats what I was trying to implement it. And its creating a problem.
 
Tim Holloway
Saloon Keeper
Posts: 18367
56
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Whether you do bidirectional or unidirectional, you still have to have something in the database that defines the parent/child linkages. And you aren't supplying that. There's no database field that corresponds to the java expenseTransactions List (which you didn't actually provide in your example).

The expenseTransactions List cannot be written out without a parent linkage in the child table, whether via a parentID column or a full bidirectional object definition. The expenseTransactions List cannot be read in at all if the ORM cannot generate some sort of SQL equivalent to

SELECT * FROM EXPENSE_TRANSACTION t WHERE t.PARENT_ID = ?

 
manvendra P singh
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tim Holloway wrote:Whether you do bidirectional or unidirectional, you still have to have something in the database that defines the parent/child linkages. And you aren't supplying that. There's no database field that corresponds to the java expenseTransactions List (which you didn't actually provide in your example).

The expenseTransactions List cannot be written out without a parent linkage in the child table, whether via a parentID column or a full bidirectional object definition. The expenseTransactions List cannot be read in at all if the ORM cannot generate some sort of SQL equivalent to

SELECT * FROM EXPENSE_TRANSACTION t WHERE t.PARENT_ID = ?



Thats the fundamental difference between Object and relational world, In relational world if A can query to find related data in B you will always have a back query to find B relations to A.
But in Java I wanted to implement that A(Expense_Item) can refer B (Expense_transaction), but object B should NOT have any clue about A and should be independent in itself.

Is it not possible, without an extra joinable ?
 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi manvendra P singh,

First of all, a warm welcome to CodeRanch!

manvendra P singh wrote:But as we know "Unidirectional OneToMany relationship" is also a concepts. Thats what I was trying to implement it. And its creating a problem.

When I am having troubles with a JPA mapping, I always check the Java Persistence WikiBook first to verify if my entity mappings are spot-on. It really is an awesome resource providing code snippets for every mapping. And you are correct: a unidirectional one-to-many relationship without inverse many-to-one and without join-table is possible but only in JPA 2.0. Have a look here for detailed information. And as you can see, it requires a join column for the foreign key mapping.

And also note that @LazyCollection is a pure Hibernate annotation (it's not JPA).

Hope it helps!
Kind regards,
Roel
 
manvendra P singh
Greenhorn
Posts: 9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:Hi manvendra P singh,

First of all, a warm welcome to CodeRanch!

manvendra P singh wrote:But as we know "Unidirectional OneToMany relationship" is also a concepts. Thats what I was trying to implement it. And its creating a problem.

When I am having troubles with a JPA mapping, I always check the Java Persistence WikiBook first to verify if my entity mappings are spot-on. It really is an awesome resource providing code snippets for every mapping. And you are correct: a unidirectional one-to-many relationship without inverse many-to-one and without join-table is possible but only in JPA 2.0. Have a look here for detailed information. And as you can see, it requires a join column for the foreign key mapping.

And also note that @LazyCollection is a pure Hibernate annotation (it's not JPA).

Hope it helps!
Kind regards,
Roel



Thanks Roel,
I did what was mentioned in the link.



No change in transaction class. So now hibernate is trying to insert the Expense_item_id, but the value is null. earlier it query was not even inserting this field as shown in logs in my original question.


New Hibernate logs

12:44:36,055 DEBUG [org.hibernate.SQL] - insert into EXPENSE_ITEM (DESCRIPTION, EXPENSE_DATE, EXPENSE_GROUP_ID) values (?, ?, ?)
12:44:36,169 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] - Natively generated identity: 15
12:44:36,172 DEBUG [org.hibernate.engine.spi.ActionQueue] - Executing identity-insert immediately
12:44:36,174 DEBUG [org.hibernate.SQL] - insert into EXPENSE_TRANSACTION (AMOUNT, EXPENSE_ITEM_ID, PARTICIPANT_ID, TRANSACTION_TYPE) values (?, ?, ?, ?)
12:44:36,310 DEBUG [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - Column 'EXPENSE_ITEM_ID' cannot be null [n/a]
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'EXPENSE_ITEM_ID' cannot be null

EDIT-1
I had to remove NOT_NULL check in database for Logical foreign_key column in transaction table, and then it worked because first hibernate insert the null and after dirty checking the collections on flush then it insert the foreign key.
Thats actually wrong to make the column unable. but I'll create a separate post if needed. My current problem is resolved.



13:01:55,850 DEBUG [org.hibernate.SQL] - insert into EXPENSE_ITEM (DESCRIPTION, EXPENSE_DATE, EXPENSE_GROUP_ID) values (?, ?, ?)
13:01:55,946 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] - Natively generated identity: 17
13:01:55,946 DEBUG [org.hibernate.engine.spi.ActionQueue] - Executing identity-insert immediately
13:01:55,947 DEBUG [org.hibernate.SQL] - insert into EXPENSE_TRANSACTION (AMOUNT, EXPENSE_ITEM_ID, PARTICIPANT_ID, TRANSACTION_TYPE) values (?, ?, ?, ?)
13:01:56,046 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] - Natively generated identity: 12
13:01:56,046 DEBUG [org.hibernate.engine.spi.ActionQueue] - Executing identity-insert immediately
13:01:56,046 DEBUG [org.hibernate.SQL] - insert into EXPENSE_TRANSACTION (AMOUNT, EXPENSE_ITEM_ID, PARTICIPANT_ID, TRANSACTION_TYPE) values (?, ?, ?, ?)
13:01:56,141 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] - Natively generated identity: 13
13:01:56,141 DEBUG [org.hibernate.engine.spi.ActionQueue] - Executing identity-insert immediately
13:01:56,142 DEBUG [org.hibernate.SQL] - insert into EXPENSE_TRANSACTION (AMOUNT, EXPENSE_ITEM_ID, PARTICIPANT_ID, TRANSACTION_TYPE) values (?, ?, ?, ?)
13:01:56,238 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] - Natively generated identity: 14
13:02:23,523 DEBUG [org.hibernate.event.internal.AbstractFlushingEventListener] - Processing flush-time cascades
13:02:23,524 DEBUG [org.hibernate.event.internal.AbstractFlushingEventListener] - Dirty checking collections
13:02:23,525 DEBUG [org.hibernate.engine.internal.Collections] - Collection found: [com.manvendra.ft.app.persistance.model.ExpenseItemVO.expenseTransactions#17], was: [<unreferenced>] (initialized)
13:02:23,526 DEBUG [org.hibernate.event.internal.AbstractFlushingEventListener] - Flushed: 0 insertions, 0 updates, 0 deletions to 4 objects
13:02:23,527 DEBUG [org.hibernate.event.internal.AbstractFlushingEventListener] - Flushed: 1 (re)creations, 0 updates, 0 removals to 1 collections
13:02:23,527 DEBUG [org.hibernate.internal.util.EntityPrinter] - Listing entities:
13:02:23,528 DEBUG [org.hibernate.internal.util.EntityPrinter] - com.manvendra.ft.app.persistance.model.ExpenseItemVO{expenseGroupVO=com.manvendra.ft.app.persistance.model.ExpenseGroupVO#1, description=Sample cruise, expenseTransactions=[com.manvendra.ft.app.persistance.model.ExpenseTransactionVO#12, com.manvendra.ft.app.persistance.model.ExpenseTransactionVO#13, com.manvendra.ft.app.persistance.model.ExpenseTransactionVO#14], id=17, expenseDate=Wed Oct 07 20:00:00 EDT 2015}
13:02:23,528 DEBUG [org.hibernate.internal.util.EntityPrinter] - com.manvendra.ft.app.persistance.model.ExpenseTransactionVO{transactionType=F, expenseItemVO=com.manvendra.ft.app.persistance.model.ExpenseItemVO#17, expenseAmont=54, id=14, participant=com.manvendra.ft.app.persistance.model.ParticipantVO#2}
13:02:23,529 DEBUG [org.hibernate.internal.util.EntityPrinter] - com.manvendra.ft.app.persistance.model.ExpenseTransactionVO{transactionType=F, expenseItemVO=com.manvendra.ft.app.persistance.model.ExpenseItemVO#17, expenseAmont=54, id=13, participant=com.manvendra.ft.app.persistance.model.ParticipantVO#1}
13:02:23,529 DEBUG [org.hibernate.internal.util.EntityPrinter] - com.manvendra.ft.app.persistance.model.ExpenseTransactionVO{transactionType=B, expenseItemVO=null, expenseAmont=108, id=12, participant=com.manvendra.ft.app.persistance.model.ParticipantVO#1}
13:02:23,530 DEBUG [org.hibernate.persister.collection.AbstractCollectionPersister] - Inserting collection: [com.manvendra.ft.app.persistance.model.ExpenseItemVO.expenseTransactions#17]
13:02:23,531 DEBUG [org.hibernate.SQL] - update EXPENSE_TRANSACTION set EXPENSE_ITEM_ID=? where EXPENSE_TRANSACTION_ID=?
13:02:23,629 DEBUG [org.hibernate.SQL] - update EXPENSE_TRANSACTION set EXPENSE_ITEM_ID=? where EXPENSE_TRANSACTION_ID=?
13:02:23,730 DEBUG [org.hibernate.SQL] - update EXPENSE_TRANSACTION set EXPENSE_ITEM_ID=? where EXPENSE_TRANSACTION_ID=?
13:02:23,823 DEBUG [org.hibernate.persister.collection.AbstractCollectionPersister] - Done inserting collection: 3 rows inserted

 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
manvendra P singh wrote:EDIT-1
I had to remove NOT_NULL check in database for Logical foreign_key column in transaction table, and then it worked because first hibernate insert the null and after dirty checking the collections on flush then it insert the foreign key.
Thats actually wrong to make the column unable. but I'll create a separate post if needed. My current problem is resolved.

If you want to use this approach, removing the NOT NULL constraint is required; otherwise it won't work. That's clearly mentioned in the introductory paragraph of the aforementioned link
Java Persistence/OneToMany - Unidirectional OneToMany, No Inverse ManyToOne, No Join Table wrote:The target object in a unidirectional OneToMany is an independent object, so it should not rely on the foreign key in any way, i.e. the foreign key cannot be part of its primary key, nor generally have a not null constraint on it.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic