Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child
OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #494526] Sat, 31 October 2009 07:14 Go to next message
Oliver Vesper is currently offline Oliver Vesper
Messages: 42
Registered: July 2009
Member
Hi,

I am having a simple test-case which fails and I wonder if I am doing
anything wrong or if it's a bug. I have two entites which look like this:

@Entity
public class Foo {
@Id
@GeneratedValue
private Long id;

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Collection<Bar> children = new ArrayList<Bar>();

/* ... */
}

@Entity
public class Bar {
@Id
@GeneratedValue
private Long id;

/* ... */
}

During my test I create a Foo instance, persist it and commit the
transaction. In the next step I lookup that entity, create a Bar
instance and add it to Foo's collection. Then I get a new transaction,
merge the Foo instance and commit the transaction. But the commit fails
with the following error:

[EL Warning]: UnitOfWork(7438914)--Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services -
2.0.0.v20091026-r5655): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLException: NULL not allowed for
column CHILDREN_ID [90006-71]
Error Code: 90006
Call: INSERT IGNORE INTO FOO_BAR (children_ID, Foo_ID) VALUES (?, ?)
bind => [null, 1]
Query: DataModifyQuery(sql="INSERT IGNORE INTO FOO_BAR (children_ID, Foo_ID)
VALUES (?, ?)")
at
org.eclipse.persistence.exceptions.DatabaseException.sqlExce ption(DatabaseException.java:324)

If I change the FetchType from LAZY to EAGER, it works fine. Am I
missing something? I am using dynamic weaving and my entity-classes are
woven successfully. The EclipseLink version is 2.0.0.v20091026-r5655.

Thx in advance,
Oliver
Re: OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #494765 is a reply to message #494526] Mon, 02 November 2009 15:18 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Seems quite odd, somehow the Bar id is null. The Bar should have been inserted before this, so what id was inserted?

Could you include the full log, and the code you are using for the test.

It probably has something to do with your merge, that is somehow corrupting the object clones. Why are you using merge? merge() is meant for when an object get serialized, are you serializing your objects?



James : Wiki : Book : Blog : Twitter
Re: OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #494770 is a reply to message #494765] Mon, 02 November 2009 15:29 Go to previous messageGo to next message
Oliver Vesper is currently offline Oliver Vesper
Messages: 42
Registered: July 2009
Member
Hi James,

thanks for your reply. I don't have the code with me right now, but I will post it as soon as possible. The Bar object has not been persisted before, but the owning Foo object (at that time with an empty collection of Bar objects). Then I create a Bar object and insert it to the Foo object's collection - I do not persist the Bar object itself. Then I call merge() in order to have the association Foo<-->Bar reflected in the database and the Bar object be persisted. As I annotated CascadeType.ALL I expect the Bar object to be persisted automatically. And it does work if I switch the fetching of the Collection<Bar> from LAZY to EAGER.

-Oliver
Re: OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #494799 is a reply to message #494765] Mon, 02 November 2009 16:53 Go to previous messageGo to next message
Oliver Vesper is currently offline Oliver Vesper
Messages: 42
Registered: July 2009
Member
> Seems quite odd, somehow the Bar id is null. The Bar should have been
> inserted before this, so what id was inserted?
>
> Could you include the full log, and the code you are using for the test.
>


Okay, so here's my Activator's start() code I am using through this test:

public void start(final BundleContext context) throws Exception {
		try {
			final Properties properties = new Properties();
			properties.put(PersistenceUnitProperties.CLASSLOADER, this
					.getClass().getClassLoader());

			final EntityManagerFactory emf = Persistence
					.createEntityManagerFactory("default", properties);
			final EntityManager em = emf.createEntityManager();

			EntityTransaction tx = em.getTransaction();
			tx.begin();
			final Foo foo = new Foo();
			em.persist(foo);
			tx.commit();

			final Query query = em.createQuery("SELECT f FROM Foo f");
			final List fooList = query.getResultList();
			for (final Object object : fooList) {
				Foo f = (Foo) object;
				final Bar bar = new Bar();
				f.getChildren().add(bar);
				tx = em.getTransaction();
				tx.begin();
				f = em.merge(f);
				tx.commit();
			}

			em.close();
			emf.close();
		} catch (final Throwable t) {
			System.err.println(t.getMessage());
		}
	}


And this is the log-output:
osgi> Time to load bundles: 250
[EL Config]: ServerSession(6613606)--The access type for the persistent 
class [class test.weaving.entities.Foo] is set to [FIELD].
[EL Config]: ServerSession(6613606)--The target entity (reference) class 
for the one to many mapping element [field children] is being defaulted 
to: class test.weaving.another.Bar.
[EL Config]: ServerSession(6613606)--The access type for the persistent 
class [class test.weaving.another.Bar] is set to [FIELD].
[EL Config]: ServerSession(6613606)--The alias name for the entity class 
[class test.weaving.entities.Foo] is being defaulted to: Foo.
[EL Config]: ServerSession(6613606)--The table name for entity [class 
test.weaving.entities.Foo] is being defaulted to: FOO.
[EL Config]: ServerSession(6613606)--The column name for element [field 
id] is being defaulted to: ID.
[EL Config]: ServerSession(6613606)--The column name for element [field 
x] is being defaulted to: X.
[EL Config]: ServerSession(6613606)--The alias name for the entity class 
[class test.weaving.another.Bar] is being defaulted to: Bar.
[EL Config]: ServerSession(6613606)--The table name for entity [class 
test.weaving.another.Bar] is being defaulted to: BAR.
[EL Config]: ServerSession(6613606)--The column name for element [field 
id] is being defaulted to: ID.
[EL Config]: ServerSession(6613606)--The column name for element [field 
myDate] is being defaulted to: MYDATE.
[EL Config]: ServerSession(6613606)--The join table name for the many to 
many mapping [field children] is being defaulted to: FOO_BAR.
[EL Config]: ServerSession(6613606)--The source primary key column name 
for the many to many mapping [field children] is being defaulted to: ID.
[EL Config]: ServerSession(6613606)--The source foreign key column name 
for the many to many mapping [field children] is being defaulted to: Foo_ID.
[EL Config]: ServerSession(6613606)--The target primary key column name 
for the many to many mapping [field children] is being defaulted to: ID.
[EL Config]: ServerSession(6613606)--The target foreign key column name 
for the many to many mapping [field children] is being defaulted to: 
children_ID.
Registering Service 
{org.eclipse.persistence.jpa.equinox.weaving.IWeaver}={service.id=32}
test.weaving.entities.Foo woven
test.weaving.another.Bar woven
[EL Info]: ServerSession(6613606)--EclipseLink, version: Eclipse 
Persistence Services - 2.0.0.v20091031-r5713
[EL Config]: 
ServerSession(6613606)--Connection(17235092)--connecting(DatabaseLogin(
	platform=>HSQLPlatform
	user name=> "xyz"
	datasource URL=> "jdbc:h2:c:/h2/default;create=true"
))
[EL Config]: ServerSession(6613606)--Connection(25383640)--Connected: 
jdbc:h2:c:/h2/default
	User: XYZ
	Database: H2  Version: 1.0.71 (2008-04-25)
	Driver: H2 JDBC Driver  Version: 1.0.71 (2008-04-25)
[EL Config]: 
ServerSession(6613606)--Connection(11800260)--connecting(DatabaseLogin(
	platform=>HSQLPlatform
	user name=> "xyz"
	datasource URL=> "jdbc:h2:c:/h2/default;create=true"
))
[EL Config]: ServerSession(6613606)--Connection(20280994)--Connected: 
jdbc:h2:c:/h2/default
	User: XYZ
	Database: H2  Version: 1.0.71 (2008-04-25)
	Driver: H2 JDBC Driver  Version: 1.0.71 (2008-04-25)
[EL Info]: ServerSession(6613606)--default login successful
[EL Fine]: ServerSession(6613606)--Connection(25383640)--CREATE TABLE 
BAR (ID NUMERIC(19) IDENTITY NOT NULL, MYDATE TIMESTAMP, PRIMARY KEY (ID))
[EL Fine]: ServerSession(6613606)--Connection(25383640)--CREATE TABLE 
FOO (ID NUMERIC(19) IDENTITY NOT NULL, X VARCHAR(255), PRIMARY KEY (ID))
[EL Fine]: ServerSession(6613606)--Connection(25383640)--CREATE TABLE 
FOO_BAR (Foo_ID NUMERIC(19) NOT NULL, children_ID NUMERIC(19) NOT NULL, 
PRIMARY KEY (Foo_ID, children_ID))
[EL Fine]: ClientSession(24478976)--Connection(20280994)--INSERT IGNORE INTO 
FOO (X) VALUES (?)
	bind => [null]
[EL Fine]: ClientSession(24478976)--Connection(20280994)--CALL IDENTITY()
[EL Fine]: ServerSession(6613606)--Connection(25383640)--SELECT ID, X 
FROM FOO
[EL Fine]: ClientSession(24478976)--Connection(20280994)--INSERT IGNORE INTO 
BAR (MYDATE) VALUES (?)
	bind => [null]
[EL Fine]: ClientSession(24478976)--Connection(20280994)--CALL IDENTITY()
[EL Fine]: ClientSession(24478976)--Connection(20280994)--INSERT IGNORE INTO 
FOO_BAR (children_ID, Foo_ID) VALUES (?, ?)
	bind => [null, 1]
[EL Warning]: UnitOfWork(2161283)--Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 
2.0.0.v20091031-r5713): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLException: NULL not allowed for 
column CHILDREN_ID [90006-71]
Error Code: 90006
Call: INSERT IGNORE INTO FOO_BAR (children_ID, Foo_ID) VALUES (?, ?)
	bind => [null, 1]
Query: DataModifyQuery(sql="INSERT IGNORE INTO FOO_BAR (children_ID, Foo_ID) 
VALUES (?, ?)")
	at 
org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:324)
	at 
org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:800)
	at 
org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:866)
	at 
org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:586)
	at 
org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:529)
	at 
org.eclipse.persistence.internal.sessions.AbstractSession.executeCall(AbstractSession.java:914)
	at 
org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:205)
	at 
org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:191)
	at 
org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeNoSelectCall(DatasourceCallQueryMechanism.java:234)
	at 
org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeNoSelect(DatasourceCallQueryMechanism.java:214)
	at 
org.eclipse.persistence.internal.queries.StatementQueryMechanism.executeNoSelect(StatementQueryMechanism.java:115)
	at 
org.eclipse.persistence.queries.DataModifyQuery.executeDatabaseQuery(DataModifyQuery.java:85)
	at 
org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:670)
	at 
org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:589)
	at 
org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2861)
	at 
org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1225)
	at 
org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1207)
	at 
org.eclipse.persistence.mappings.ManyToManyMapping.insertAddedObjectEntry(ManyToManyMapping.java:597)
	at 
org.eclipse.persistence.mappings.ManyToManyMapping.performDataModificationEvent(ManyToManyMapping.java:791)
	at 
org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:130)
	at 
org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:3260)
	at 
org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1403)
	at 
org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:547)
	at 
org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1508)
	at 
org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:200)
	at 
org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1129)
	at 
org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:84)
	at 
org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:63)
	at test.weaving.internal.Activator.start(Activator.java:47)
	at 
org.eclipse.osgi.framework.internal.core.BundleContextImpl$1.run(BundleContextImpl.java:783)
	at java.security.AccessController.doPrivileged(Native Method)
	at 
org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:774)
	at 
org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:755)
	at 
org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:353)
	at 
org.eclipse.osgi.framework.internal.core.AbstractBundle.resume(AbstractBundle.java:370)
	at 
org.eclipse.osgi.framework.internal.core.Framework.resumeBundle(Framework.java:1068)
	at 
org.eclipse.osgi.framework.internal.core.StartLevelManager.resumeBundles(StartLevelManager.java:554)
	at 
org.eclipse.osgi.framework.internal.core.StartLevelManager.incFWSL(StartLevelManager.java:461)
	at 
org.eclipse.osgi.framework.internal.core.StartLevelManager.doSetStartLevel(StartLevelManager.java:246)
	at 
org.eclipse.osgi.framework.internal.core.StartLevelManager.dispatchEvent(StartLevelManager.java:442)
	at 
org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:227)
	at 
org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:337)
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column 
CHILDREN_ID [90006-71]
	at org.h2.message.Message.getSQLException(Message.java:92)
	at org.h2.message.Message.getSQLException(Message.java:96)
	at org.h2.message.Message.getSQLException(Message.java:74)
	at org.h2.table.Column.validateConvertUpdateSequence(Column.java:231)
	at org.h2.table.Table.validateConvertUpdateSequence(Table.java:470)
	at org.h2.command.dml.Insert.update(Insert.java:92)
	at org.h2.command.CommandContainer.update(CommandContainer.java:69)
	at org.h2.command.Command.executeUpdate(Command.java:198)
	at 
org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:131)
	at 
org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:120)
	at 
org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:791)
	... 40 more

Exception [EclipseLink-4002] (Eclipse Persistence Services - 
2.0.0.v20091031-r5713): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLException: NULL not allowed for 
column CHILDREN_ID [90006-71]
Error Code: 90006
Call: INSERT IGNORE INTO FOO_BAR (children_ID, Foo_ID) VALUES (?, ?)
	bind => [null, 1]
Query: DataModifyQuery(sql="INSERT IGNORE INTO FOO_BAR (children_ID, Foo_ID) 
VALUES (?, ?)")



> It probably has something to do with your merge, that is somehow
> corrupting the object clones. Why are you using merge? merge() is
> meant for when an object get serialized, are you serializing your
objects?

I want to merge my entity's state into the persistence layer which
should result in having the Bar object be persisted and have the Foo
object be the Bar's owner. To achieve this I have to use the merge() as
far as I know.

-Oliver
Re: OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #494984 is a reply to message #494799] Tue, 03 November 2009 13:19 Go to previous messageGo to next message
Oliver Vesper is currently offline Oliver Vesper
Messages: 42
Registered: July 2009
Member
Hi,

can anybody confirm whether I am doing it the right way or not? If there is nothing wrong with my provided test-code, then I will file a bug.

Thx,
Oliver
Re: OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #495108 is a reply to message #494984] Tue, 03 November 2009 19:08 Go to previous messageGo to next message
Oliver Vesper is currently offline Oliver Vesper
Messages: 42
Registered: July 2009
Member
> can anybody confirm whether I am doing it the right way or not? If there
> is nothing wrong with my provided test-code, then I will file a bug.

I filed a bug report: https://bugs.eclipse.org/bugs/show_bug.cgi?id=294098

-Oliver
Re: OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #495645 is a reply to message #494526] Thu, 05 November 2009 15:39 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Thanks for logging the bug, as there does seem to be an issue here.

But in general, you should not be calling the merge(), you should never need to merge and object into itself. merge() should only be used for detached copies or serialized objects. The merge seems to be confusing EclipseLink somehow.


James : Wiki : Book : Blog : Twitter
Re: OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #495667 is a reply to message #495645] Thu, 05 November 2009 17:21 Go to previous messageGo to next message
Oliver Vesper is currently offline Oliver Vesper
Messages: 42
Registered: July 2009
Member
James wrote on Thu, 05 November 2009 10:39
But in general, you should not be calling the merge(), you should never need to merge and object into itself. merge() should only be used for detached copies or serialized objects. The merge seems to be confusing EclipseLink somehow.



That is very interesting, I always thought it would be necessary to call merge() after making changes to an already persisted entity. But as I just figured out it is totally sufficient to call flush() upon the EM within a transaction. As you pointed out, in general merge() should only be used for detached objects.

Could you verify if the following working test-code is more appropriate instead of the merge-code I posted before?

EntityTransaction tx = em.getTransaction();
tx.begin();
final Foo foo = new Foo();
em.persist(foo);
tx.commit();

final Query query = em.createQuery("SELECT f FROM Foo f");
final List fooList = query.getResultList();
for (final Object object : fooList) {
	final Foo f = (Foo) object;
	final Bar bar = new Bar();
	f.getChildren().add(bar);
}

tx = em.getTransaction();
tx.begin();
em.flush();
tx.commit();


Thx,
Oliver
Re: OneToMany, FetchType.LAZY, CascadeType.ALL: Fails to persist child [message #496287 is a reply to message #494526] Mon, 09 November 2009 15:46 Go to previous message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Yes, that is better.

You may also wish to move the tx.begin() to before the query, as this is technically when the transaction begins.


James : Wiki : Book : Blog : Twitter
Previous Topic:Fixed String or Oracle CHAR
Next Topic:removed
Goto Forum:
  


Current Time: Thu Sep 18 07:40:24 GMT 2014

Powered by FUDForum. Page generated in 1.31905 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software