OneToOne bidirectional StackOverflow error

6,878 views
Skip to first unread message

Saulius

unread,
Apr 4, 2011, 5:27:14 PM4/4/11
to Ebean ORM
Hi,

There seems to be a bug with OneToOne bidirectional relationship.

For example take entities:

@Entity
@Table(name="wheel")
public class Wheel {

@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Version
private int version;

@OneToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
@JoinColumn(name = "car")
private Car car;

...
}

@Entity
@Table(name="car")
public class Car {

@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Version
private int version;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "wheel")
private Wheel wheel;

...
}

And try saving some objects:

Car car = new Car();

Wheel w1 = new Wheel();
w1.setCar(car);

car.setWheel(w1);

Ebean.save(car);

What you get is StackOverflowError exception:

java.lang.StackOverflowError
at
com.avaje.ebeaninternal.server.subclass.SubClassUtil.getSuperClassName(SubClassUtil.java:
40)
at
com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.getBeanManager(BeanDescriptorManager.java:
484)
at
com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager.getBeanManager(BeanDescriptorManager.java:
479)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.getBeanManager(DefaultPersister.java:
1381)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.createRequest(DefaultPersister.java:
1344)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveRecurse(DefaultPersister.java:
312)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveAssocOne(DefaultPersister.java:
1222)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:
399)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveEnhanced(DefaultPersister.java:
345)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveRecurse(DefaultPersister.java:
315)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveAssocOne(DefaultPersister.java:
1222)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:
399)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveEnhanced(DefaultPersister.java:
345)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveRecurse(DefaultPersister.java:
315)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveAssocOne(DefaultPersister.java:
1222)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:
399)
....

So I guess it gets into infinite recursion somewhere.

If I remove annotation @JoinColumn and add attribute mappedBy = "car"
to annotation @OneToOne by the field wheel in the entity Car,
everything works fine.

Saulius

unread,
Apr 6, 2011, 4:45:57 AM4/6/11
to Ebean ORM
Hi all,

Has anyone have an idea if this is a bug or just me doing something
wrong?

edge

unread,
Apr 6, 2011, 5:05:47 AM4/6/11
to Ebean ORM
infinite recursion is usually a bug! Looks like the the cascade on
both sides of the relationship is causing a problem coupled with the
JoinColumn (not Ebean doesn't support Merge)
However, I don't really see the point in keeping the foreign keys in
both wheel and car - the mappedBy solution that works is normally how
you would manage an OneToOne relationship and your example seems a bit
contrived - but that said we shouldn't go into infinite recursion.
Can you send us your test case and we'll investigate but I think this
has low prio

Saulius Pačekajus

unread,
Apr 6, 2011, 12:34:00 PM4/6/11
to eb...@googlegroups.com

Well you are actually right that the bidirectional OneToOne relationship
does not really have any advantages. Well I unless one forgets to add
index for a foreign key :)

Anyway there is another problem with unidirectional OneToOne
relationship either. Suppose we have entities e1 and e2. Now if I have
foreign key on e2 and saving e1 - it works fine, but if I save e2 - it
save the data and fails with an error. Please consider this example
(please not Car, Wheel and Tire is solely for example purposes - so some
relations might not make sense):

@Entity
@Table(name="tire")
public class Tire {

@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Version
private int version;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "wheel")
private Wheel wheel;

....
}

@Entity
@Table(name="wheel")
public class Wheel {

@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Version
private int version;

@OneToOne(mappedBy="wheel", cascade = CascadeType.ALL)
private Tire tire;

....
}

Now here is a simple code that creates beans:

Wheel w1 = new Wheel();

Tire t1 = new Tire();

t1.setWheel(w1);
w1.setTire(t1);

Now the success completely depends on which entity you provide to
Ebean.save(): make it Ebean.save(w1); and it's OK; make it
Ebean.save(t1); and you get exception:

javax.persistence.PersistenceException: ERROR executing DML
bindLog[Binding Insert [tire] set[id=121, version=1, wheel=121, ]]
error[ERROR: duplicate key value violates unique constraint "pk_tire"]
at
com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:116)
at
com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.insert(DmlBeanPersister.java:76)
at
com.avaje.ebeaninternal.server.persist.DefaultPersistExecute.executeInsertBean(DefaultPersistExecute.java:91)
at
com.avaje.ebeaninternal.server.core.PersistRequestBean.executeNow(PersistRequestBean.java:527)
at
com.avaje.ebeaninternal.server.core.PersistRequestBean.executeOrQueue(PersistRequestBean.java:557)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:404)


at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveEnhanced(DefaultPersister.java:345)
at
com.avaje.ebeaninternal.server.persist.DefaultPersister.saveRecurse(DefaultPersister.java:315)
at

com.avaje.ebeaninternal.server.persist.DefaultPersister.save(DefaultPersister.java:282)
at
com.avaje.ebeaninternal.server.core.DefaultServer.save(DefaultServer.java:1577)
at
com.avaje.ebeaninternal.server.core.DefaultServer.save(DefaultServer.java:1567)
at com.avaje.ebean.Ebean.save(Ebean.java:538)
at lt.travelonline.test.CarTest.testCarInsert(CarTest.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at
org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at
org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at
org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at
org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at
org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value
violates unique constraint "pk_tire"
at
org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1608)
at
org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1343)
at
org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:194)
at
org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:451)
at
org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:350)
at
org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:304)
at
com.jolbox.bonecp.PreparedStatementHandle.executeUpdate(PreparedStatementHandle.java:228)
at
com.avaje.ebeaninternal.server.type.DataBind.executeUpdate(DataBind.java:74)
at
com.avaje.ebeaninternal.server.persist.dml.InsertHandler.execute(InsertHandler.java:155)
at
com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:105)
... 40 more

The transaction log:

txn[1001], 19:27:37.932, insert into wheel (id, version) values (?,?)
txn[1001], 19:27:37.932, Binding Insert [wheel] set[id=141, version=1, ]
txn[1001], 19:27:37.936, Inserted [Wheel] [141]
txn[1001], 19:27:37.937, insert into tire (id, version, wheel) values
(?,?,?)
txn[1001], 19:27:37.937, Binding Insert [tire] set[id=141, version=1,
wheel=141, ]
txn[1001], 19:27:37.939, Inserted [Tire] [141]
txn[1001], 19:27:37.939, insert into tire (id, version, wheel) values
(?,?,?)
txn[1001], 19:27:37.939, Binding Insert [tire] set[id=141, version=1,
wheel=141, ]
txn[1001], 19:27:37.942, ERROR executing DML bindLog[Binding Insert
[tire] set[id=141, version=1, wheel=141, ]] error[ERROR: duplicate key
value violates unique constraint "pk_tire"]
txn[1001], 19:27:37.942, Rollback


Now given all this I believe this might as well be related to recursion
problem.

I can really live without bidirectional OneToOne as I don't really need
it, but trying to escape this bug would be a real nighmare :)

Saulius

unread,
Apr 11, 2011, 11:21:36 AM4/11/11
to Ebean ORM
Hi guys,

I know it's a low priority issue for you, but it is the only issue
that keeps me from using it in production and I think it is a serious
problem because Ebean.save fails for a valid entity.

Once again, just to picture the situation consider these 2 entities:

@Entity
@Table(name="invoice")
public class Invoice {

@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Version
private int version;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "booking")
private Booking booking;

...
}

@Entity
@Table(name = "booking")
public class Booking {

@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

@Version
private int version;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "client_invoice")
private Invoice clientInvoice;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "agent_invoice")
private Invoice agentInvoice;

...
}

As you can see I need this bidirectional OneToOne relationship in
order to get Booking entity when having Invoice entity. Without
JoinColumn on Booking side, I cannot identify which of the invoices is
client invoice and which is agent invoice. Without JoinColumn on
Invoice side, I cannot select (not that simple) all invoices for some
booking, also having an invoice I cannot easily find which booking it
belongs to.
> >>>          at...
>
> read more »

Rob Bygrave

unread,
Apr 11, 2011, 5:46:38 PM4/11/11
to eb...@googlegroups.com, Saulius

Well, there are no mappedBy attributes so this doesn't look like a valid bi-directional OneToOne. As there are 2 relationship here I suspect that is where the confusion is - specifically around the booking property in the Invoice. 

I suspect you added that Booking property later (originally unidirectional?). Can you state again what the problem you had with your query (it was not obvious to me why you didn't query from the Booking ... to get the Invoices for a given booking).

Can you state what your DB tables look like (I'm especially interested in that booking column which looks dubious/incorrect so it would be good to clarify what the relational model looks like). 

I suspect removing the booking property on the Invoice is effectively the fix here. Otherwise you might be looking to use a join table (which Ebean does not support) but that is a guess and I suspect that is not what you want.


Cheers, Rob.


2011/4/12 Saulius <sau...@pacekajus.lt>

Saulius

unread,
Apr 12, 2011, 9:17:38 AM4/12/11
to Ebean ORM

Well I don't actually want to prove that bidirectional OneToOne
relationship is necessary for me or anybody else. In fact you are
right, I don't have this bidirectional OneToOne relationship - I've
just made it up as an example to illustrate that cascading bug that
leads to infinite recursion.

Anyway if you want to see complete booking and invoice entities, here
they are: Booking http://pastie.org/1786569 and Invoice http://pastie.org/1786543
(note it's actually OneToMany relationship). The database scheme for
these 2 entities is http://pastie.org/1786710

So it is not bidirectional OneToOne, but it is a real world example
and it does not change the fact, that when I try to save Booking with
both invoices set (http://pastie.org/1786739) I get the same infinite
recursion failure: http://pastie.org/1786745

So I get this error not only on bidirectional OneToOne but on other
relationships too. So my guess is that this happens when there is a
loop in relationship between 2 entities (E1 has reference to E2 and E2
has reference to E1 - and it does not have to be a bidirectional
relashionship) and it probably happens because after doing work on E1
and then cascading to E2 algorithm goes again back to E1 thus getting
into infinite recursion.

Regards, Saulius

On Apr 12, 12:46 am, Rob Bygrave <robin.bygr...@gmail.com> wrote:
> Well, there are no mappedBy attributes so this doesn't look like a valid
> bi-directional OneToOne. As there are 2 relationship here I suspect that is
> where the confusion is - specifically around the booking property in the
> Invoice.
>
> I suspect you added that Booking property later (originally
> unidirectional?). Can you state again what the problem you had with your
> query (it was not obvious to me why you didn't query from the Booking ... to
> get the Invoices for a given booking).
>
> Can you state what your DB tables look like (I'm especially interested in
> that booking column which looks dubious/incorrect so it would be good to
> clarify what the relational model looks like).
>
> I suspect removing the booking property on the Invoice is effectively the
> fix here. Otherwise you might be looking to use a join table (which Ebean
> does not support) but that is a guess and I suspect that is not what you
> want.
>
> Cheers, Rob.
>
> 2011/4/12 Saulius <saul...@pacekajus.lt>
> ...
>
> read more »

Rob Bygrave

unread,
Apr 12, 2011, 6:15:32 PM4/12/11
to eb...@googlegroups.com, Saulius
>> and Invoice http://pastie.org/1786543

So I see you have change Booking here to be a ManyToOne (when it used to be a OneToOne).

>> The database scheme for these 2 entities is http://pastie.org/1786710

I'm pretty sure the booking column is effectively derived data. Strictly speaking it is not required for either of the 2 relationships .... but you are looking to include it to help you navigate the other way - hmmm, I think that might not help you actually.


>> So it is not bidirectional OneToOne

Good - I think we are agreed on that. The problem being it almost looked like one which I think is the problem - Ebean likely thought you where trying to define a bi-directional OneToOne without any mappedBy attribute (hence the recursion problem).


>> So I get this error not only on bidirectional OneToOne but on other relationships too. 

Hmm, this statement is a regression. No mappedBy means no bi-directional OneToOne -> this was not a bi-directional OneToOne.


>> So my guess is that this happens when there is a ...

Sounds about right.

The summary for me is that you have 2 unidirectional OneToOne relationships... plus a derived relationship going back the other way. So the question is, if you remove that derived relationship (Booking on the Invoice entity) is there a problem?

Saulius Pačekajus

unread,
Apr 12, 2011, 6:44:58 PM4/12/11
to eb...@googlegroups.com
>>So the question is, if you remove that derived relationship (Booking on the Invoice entity) is there a problem?

I've commented out List<Invoice> invoices field on Booking entity. The problem stays the same: http://pastie.org/1788902

All the rest code is the same, just field invoices and its getter and setter are commented.

Rob Bygrave

unread,
Apr 12, 2011, 9:12:22 PM4/12/11
to eb...@googlegroups.com, Saulius Pačekajus

You will need to also remove from the Invoice entity:

@ManyToOne(cascade = CascadeType.ALL)

@JoinColumn(name = "booking")
private Booking booking;


2011/4/13 Saulius Pačekajus <sau...@pacekajus.lt>

Saulius Pačekajus

unread,
Apr 13, 2011, 2:19:36 AM4/13/11
to eb...@googlegroups.com

I removed it from Invoice entity too and it works.

But I would really prefer to have this one as I need Booking in most tasks where I process Invoice!



On 2011.04.13 04:12, Rob Bygrave wrote:

You will need to also remove from the Invoice entity:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "booking")
private Booking booking;



2011/4/13 Saulius Pa�ekajus <sau...@pacekajus.lt>
>>So the question is, if you remove that derived relationship (Booking on the Invoice entity) is there a problem?

I've commented out List<Invoice> invoices field on Booking entity. The problem stays the same: http://pastie.org/1788902

All the rest code is the same, just field invoices and its getter and setter are commented.



On 2011.04.13 01:15, Rob Bygrave wrote:
>>�and Invoice�http://pastie.org/1786543

So I see you have change Booking here to be a ManyToOne (when it used to be a OneToOne).

>>�The database scheme for�these 2 entities is�http://pastie.org/1786710

I'm pretty sure the booking column is effectively derived data. Strictly speaking it is not required for either of the 2 relationships .... but you are looking to include it to help you navigate the other way - hmmm, I think that might not help you actually.


>>�So it is not bidirectional OneToOne

Good - I think we are agreed on that. The problem being it almost looked like one which I think is the problem - Ebean likely thought you where trying to define a bi-directional OneToOne without any mappedBy attribute (hence the recursion problem).


>>�So I get this error not only on bidirectional OneToOne but on other�relationships too.�

Hmm, this statement is a regression. No mappedBy means no bi-directional OneToOne -> this was not a bi-directional OneToOne.


>>�So my guess is that this happens when there is a ...
> > ďż˝ ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > � � � �private Long id;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@Version
> > � � � �private int version;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> > ďż˝ ďż˝ ďż˝ ďż˝ @JoinColumn(name = "booking")
> > � � � �private Booking booking;
>
> > ďż˝ ďż˝ ďż˝ ďż˝...

> > }
>
> > @Entity
> > @Table(name = "booking")
> > public class Booking {
>
> > ďż˝ ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > � � � �private Long id;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@Version
> > � � � �private int version;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> > ďż˝ ďż˝ ďż˝ ďż˝ @JoinColumn(name = "client_invoice")
> > � � � �private Invoice clientInvoice;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> > ďż˝ ďż˝ ďż˝ ďż˝@JoinColumn(name = "agent_invoice")
> > � � � �private Invoice agentInvoice;
>
> > ďż˝ ďż˝ ďż˝ ďż˝...

> > }
>
> > As you can see I need this bidirectional OneToOne relationship in
> > order to get Booking entity when having Invoice entity. Without
> > JoinColumn on Booking side, I cannot identify which of the invoices is
> > client invoice and which is agent invoice. Without JoinColumn on
> > Invoice side, I cannot select (not that simple) all invoices for some
> > booking, also having an invoice I cannot easily find which booking it
> > belongs to.
>
> > On Apr 6, 7:34 pm, Saulius Pa�ekajus <saul...@pacekajus.lt> wrote:
> > > Well you are actually right that the bidirectional OneToOne relationship
> > > does not really have any advantages. Well I unless one forgets to add
> > > index for a foreign key :)
>
> > > Anyway there is another problem with unidirectional OneToOne
> > > relationship either. Suppose we have entities e1 and e2. Now if I have
> > > foreign key on e2 and saving e1 - it works fine, but if I save e2 - it
> > > save the data and fails with an error. Please consider this example
> > > (please not Car, Wheel and Tire is solely for example purposes - so some
> > > relations might not make sense):
>
> > > @Entity
> > > @Table(name="tire")
> > > public class Tire {
>
> > > ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > > � � �private Long id;
>
> > > ďż˝ ďż˝ ďż˝@Version
> > > � � �private int version;
>
> > > ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> > > ďż˝ ďż˝ ďż˝@JoinColumn(name = "wheel")
> > > � � �private Wheel wheel;
>
> > > ďż˝ ďż˝ ďż˝....

>
> > > }
>
> > > @Entity
> > > @Table(name="wheel")
> > > public class Wheel {
>
> > > ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > > � � �private Long id;
>
> > > ďż˝ ďż˝ ďż˝@Version
> > > � � �private int version;
>
> > > ďż˝ ďż˝ ďż˝@OneToOne(mappedBy="wheel", cascade = CascadeType.ALL)
> > > � � �private Tire tire;
>
> > > ďż˝ ďż˝ ďż˝....

>
> > > }
>
> > > Now here is a simple code that creates beans:
>
> > > � � �Wheel w1 = new Wheel();
> > > � � �Tire t1 = new Tire();
>
> > > � � �t1.setWheel(w1);
> > > � � �w1.setTire(t1);

>
> > > Now the success completely depends on which entity you provide to
> > > Ebean.save(): make it Ebean.save(w1); and it's OK; make it
> > > Ebean.save(t1); and you get exception:
>
> > > javax.persistence.PersistenceException: ERROR executing DML
> > > bindLog[Binding Insert [tire] �set[id=121, version=1, wheel=121, ]]

> > > error[ERROR: duplicate key value violates unique constraint "pk_tire"]
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:116)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.insert(DmlBeanPersister.java:76)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.DefaultPersistExecute.executeInsertBean(DefaultPersistExecute.java:91)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.core.PersistRequestBean.executeNow(PersistRequestBean.java:527)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.core.PersistRequestBean.executeOrQueue(PersistRequestBean.java:557)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.DefaultPersister.insert(DefaultPersister.java:404)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.DefaultPersister.saveEnhanced(DefaultPersister.java:345)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.DefaultPersister.saveRecurse(DefaultPersister.java:315)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.DefaultPersister.save(DefaultPersister.java:282)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.core.DefaultServer.save(DefaultServer.java:1577)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.core.DefaultServer.save(DefaultServer.java:1567)
> > > � � �at com.avaje.ebean.Ebean.save(Ebean.java:538)
> > > � � �at lt.travelonline.test.CarTest.testCarInsert(CarTest.java:22)
> > > � � �at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> > > � � �at
>
> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
> > > � � �at
>
> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> > > � � �at java.lang.reflect.Method.invoke(Method.java:616)
> > > � � �at
>
> > org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
> > > � � �at
>
> > org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
> > > � � �at
>
> > org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
> > > � � �at
>
> > org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
> > > � � �at
>
> > org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
> > > � � �at
>
> > org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
> > > � � �at
>
> > org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
> > > � � �at
>
> > org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
> > > � � �at
>
> > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
> > > � � �at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
> > > � � �at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
> > > � � �at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
> > > � � �at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
> > > � � �at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
> > > � � �at
>
> > org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
> > > � � �at
>
> > org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
> > > � � �at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
> > > � � �at
>
> > org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
> > > � � �at
>
> > org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
> > > � � �at
>
> > org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
> > > � � �at
>
> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
> > > � � �at
>
> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
> > > � � �at
>
> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
> > > � � �at

>
> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
> > > Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value
> > > violates unique constraint "pk_tire"
> > > � � �at
>
> > org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1608)
> > > � � �at
>
> > org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1343)
> > > � � �at
>
> > org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:194)
> > > � � �at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:451)
> > > � � �at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:350)
> > > � � �at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:304)
> > > � � �at
>
> > com.jolbox.bonecp.PreparedStatementHandle.executeUpdate(PreparedStatementHandle.java:228)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.type.DataBind.executeUpdate(DataBind.java:74)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.dml.InsertHandler.execute(InsertHandler.java:155)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:105)
> > > ďż˝ ďż˝ ďż˝... 40 more

>
> > > The transaction log:
>
> > > txn[1001], 19:27:37.932, insert into wheel (id, version) values (?,?)
> > > txn[1001], 19:27:37.932, Binding Insert [wheel]
>
> ...
>
> read more »


Rob Bygrave

unread,
Apr 13, 2011, 3:52:13 AM4/13/11
to eb...@googlegroups.com, Saulius Pačekajus
Right.

I believe the problem will be something along the lines of what you said earlier.... Ebean is probably searching for the other side of the OneToOne's ... finding that Booking property and then incorrectly thinking it is the other side of the OneToOne.

I don't have time to look at that tonight ... hopefully you can wait a day or two (until I find some time to investigate).

Cheers, Rob.

2011/4/13 Saulius Pačekajus <sau...@pacekajus.lt>

I removed it from Invoice entity too and it works.

But I would really prefer to have this one as I need Booking in most tasks where I process Invoice!



On 2011.04.13 04:12, Rob Bygrave wrote:

You will need to also remove from the Invoice entity:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "booking")
private Booking booking;



2011/4/13 Saulius Pačekajus <sau...@pacekajus.lt>
>>So the question is, if you remove that derived relationship (Booking on the Invoice entity) is there a problem?

I've commented out List<Invoice> invoices field on Booking entity. The problem stays the same: http://pastie.org/1788902

All the rest code is the same, just field invoices and its getter and setter are commented.



On 2011.04.13 01:15, Rob Bygrave wrote:
>> and Invoice http://pastie.org/1786543

So I see you have change Booking here to be a ManyToOne (when it used to be a OneToOne).

>> The database scheme for these 2 entities is http://pastie.org/1786710

I'm pretty sure the booking column is effectively derived data. Strictly speaking it is not required for either of the 2 relationships .... but you are looking to include it to help you navigate the other way - hmmm, I think that might not help you actually.


>> So it is not bidirectional OneToOne

Good - I think we are agreed on that. The problem being it almost looked like one which I think is the problem - Ebean likely thought you where trying to define a bi-directional OneToOne without any mappedBy attribute (hence the recursion problem).


>> So I get this error not only on bidirectional OneToOne but on other relationships too. 

Hmm, this statement is a regression. No mappedBy means no bi-directional OneToOne -> this was not a bi-directional OneToOne.


> >        @Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> >        private Long id;
>
> >        @Version
> >        private int version;
>
> >        @OneToOne(cascade = CascadeType.ALL)

> >         @JoinColumn(name = "booking")
> >        private Booking booking;
>
> >        ...
> > }
>
> > @Entity
> > @Table(name = "booking")
> > public class Booking {
>
> >        @Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> >        private Long id;
>
> >        @Version
> >        private int version;
>
> >        @OneToOne(cascade = CascadeType.ALL)
> >         @JoinColumn(name = "client_invoice")
> >        private Invoice clientInvoice;
>
> >        @OneToOne(cascade = CascadeType.ALL)
> >        @JoinColumn(name = "agent_invoice")
> >        private Invoice agentInvoice;
>
> >        ...
> > }
>
> > As you can see I need this bidirectional OneToOne relationship in
> > order to get Booking entity when having Invoice entity. Without
> > JoinColumn on Booking side, I cannot identify which of the invoices is
> > client invoice and which is agent invoice. Without JoinColumn on
> > Invoice side, I cannot select (not that simple) all invoices for some
> > booking, also having an invoice I cannot easily find which booking it
> > belongs to.
>
> > On Apr 6, 7:34 pm, Saulius Pačekajus <saul...@pacekajus.lt> wrote:
> > > Well you are actually right that the bidirectional OneToOne relationship
> > > does not really have any advantages. Well I unless one forgets to add
> > > index for a foreign key :)
>
> > > Anyway there is another problem with unidirectional OneToOne
> > > relationship either. Suppose we have entities e1 and e2. Now if I have
> > > foreign key on e2 and saving e1 - it works fine, but if I save e2 - it
> > > save the data and fails with an error. Please consider this example
> > > (please not Car, Wheel and Tire is solely for example purposes - so some
> > > relations might not make sense):
>
> > > @Entity
> > > @Table(name="tire")
> > > public class Tire {
>
> > >      @Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > >      private Long id;
>
> > >      @Version
> > >      private int version;
>
> > >      @OneToOne(cascade = CascadeType.ALL)
> > >      @JoinColumn(name = "wheel")
> > >      private Wheel wheel;
>
> > >      ....
>
> > > }
>
> > > @Entity
> > > @Table(name="wheel")
> > > public class Wheel {
>
> > >      @Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > >      private Long id;
>
> > >      @Version
> > >      private int version;
>
> > >      @OneToOne(mappedBy="wheel", cascade = CascadeType.ALL)
> > >      private Tire tire;

>
> > >      ....
>
> > > }
>
> > > Now here is a simple code that creates beans:
>
> > >      Wheel w1 = new Wheel();
> > >      Tire t1 = new Tire();
>
> > >      t1.setWheel(w1);

> > >      w1.setTire(t1);
>
> > > Now the success completely depends on which entity you provide to
> > > Ebean.save(): make it Ebean.save(w1); and it's OK; make it
> > > Ebean.save(t1); and you get exception:
>
> > > javax.persistence.PersistenceException: ERROR executing DML
> > > bindLog[Binding Insert [tire]  set[id=121, version=1, wheel=121, ]]

> > > error[ERROR: duplicate key value violates unique constraint "pk_tire"]
> > >      at
>
> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
> > > Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value
> > > violates unique constraint "pk_tire"
> > >      at
>
> > org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1608)
> > >      at
>
> > org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1343)
> > >      at
>
> > org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:194)
> > >      at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:451)
> > >      at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:350)
> > >      at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:304)
> > >      at
>
> > com.jolbox.bonecp.PreparedStatementHandle.executeUpdate(PreparedStatementHandle.java:228)
> > >      at
>
> > com.avaje.ebeaninternal.server.type.DataBind.executeUpdate(DataBind.java:74)
> > >      at
>
> > com.avaje.ebeaninternal.server.persist.dml.InsertHandler.execute(InsertHandler.java:155)
> > >      at
>
> > com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:105)
> > >      ... 40 more
>
> > > The transaction log:
>
> > > txn[1001], 19:27:37.932, insert into wheel (id, version) values (?,?)
> > > txn[1001], 19:27:37.932, Binding Insert [wheel]
>
> ...
>
> read more »



Saulius Pačekajus

unread,
Apr 13, 2011, 4:01:04 AM4/13/11
to eb...@googlegroups.com

Sure I can wait a day or two. I appreciate your help!

Regards, Saulius



On 2011.04.13 10:52, Rob Bygrave wrote:
Right.

I believe the problem will be something along the lines of what you said earlier.... Ebean is probably searching for the other side of the OneToOne's ... finding that Booking property and then incorrectly thinking it is the other side of the OneToOne.

I don't have time to look at that tonight ... hopefully you can wait a day or two (until I find some time to investigate).

Cheers, Rob.

2011/4/13 Saulius Pa�ekajus <sau...@pacekajus.lt>

I removed it from Invoice entity too and it works.

But I would really prefer to have this one as I need Booking in most tasks where I process Invoice!



On 2011.04.13 04:12, Rob Bygrave wrote:

You will need to also remove from the Invoice entity:


@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "booking")
private Booking booking;





2011/4/13 Saulius Pa�ekajus <sau...@pacekajus.lt>
>>So the question is, if you remove that derived relationship (Booking on the Invoice entity) is there a problem?

I've commented out List<Invoice> invoices field on Booking entity. The problem stays the same: http://pastie.org/1788902

All the rest code is the same, just field invoices and its getter and setter are commented.



On 2011.04.13 01:15, Rob Bygrave wrote:
>>�and Invoice�http://pastie.org/1786543

So I see you have change Booking here to be a ManyToOne (when it used to be a OneToOne).

>>�The database scheme for�these 2 entities is�http://pastie.org/1786710

I'm pretty sure the booking column is effectively derived data. Strictly speaking it is not required for either of the 2 relationships .... but you are looking to include it to help you navigate the other way - hmmm, I think that might not help you actually.


>>�So it is not bidirectional OneToOne

Good - I think we are agreed on that. The problem being it almost looked like one which I think is the problem - Ebean likely thought you where trying to define a bi-directional OneToOne without any mappedBy attribute (hence the recursion problem).


>>�So I get this error not only on bidirectional OneToOne but on other�relationships too.�

Hmm, this statement is a regression. No mappedBy means no bi-directional OneToOne -> this was not a bi-directional OneToOne.


>>�So my guess is that this happens when there is a ...
> > ďż˝ ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > � � � �private Long id;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@Version
> > � � � �private int version;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> > ďż˝ ďż˝ ďż˝ ďż˝ @JoinColumn(name = "booking")
> > � � � �private Booking booking;
>
> > ďż˝ ďż˝ ďż˝ ďż˝...

> > }
>
> > @Entity
> > @Table(name = "booking")
> > public class Booking {
>
> > ďż˝ ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > � � � �private Long id;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@Version
> > � � � �private int version;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> > ďż˝ ďż˝ ďż˝ ďż˝ @JoinColumn(name = "client_invoice")
> > � � � �private Invoice clientInvoice;
>
> > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> > ďż˝ ďż˝ ďż˝ ďż˝@JoinColumn(name = "agent_invoice")
> > � � � �private Invoice agentInvoice;
>
> > ďż˝ ďż˝ ďż˝ ďż˝...

> > }
>
> > As you can see I need this bidirectional OneToOne relationship in
> > order to get Booking entity when having Invoice entity. Without
> > JoinColumn on Booking side, I cannot identify which of the invoices is
> > client invoice and which is agent invoice. Without JoinColumn on
> > Invoice side, I cannot select (not that simple) all invoices for some
> > booking, also having an invoice I cannot easily find which booking it
> > belongs to.
>
> > On Apr 6, 7:34 pm, Saulius Pa�ekajus <saul...@pacekajus.lt> wrote:
> > > Well you are actually right that the bidirectional OneToOne relationship
> > > does not really have any advantages. Well I unless one forgets to add
> > > index for a foreign key :)
>
> > > Anyway there is another problem with unidirectional OneToOne
> > > relationship either. Suppose we have entities e1 and e2. Now if I have
> > > foreign key on e2 and saving e1 - it works fine, but if I save e2 - it
> > > save the data and fails with an error. Please consider this example
> > > (please not Car, Wheel and Tire is solely for example purposes - so some
> > > relations might not make sense):
>
> > > @Entity
> > > @Table(name="tire")
> > > public class Tire {
>
> > > ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > > � � �private Long id;
>
> > > ďż˝ ďż˝ ďż˝@Version
> > > � � �private int version;
>
> > > ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> > > ďż˝ ďż˝ ďż˝@JoinColumn(name = "wheel")
> > > � � �private Wheel wheel;
>
> > > ďż˝ ďż˝ ďż˝....

>
> > > }
>
> > > @Entity
> > > @Table(name="wheel")
> > > public class Wheel {
>
> > > ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy = GenerationType.SEQUENCE)
> > > � � �private Long id;
>
> > > ďż˝ ďż˝ ďż˝@Version
> > > � � �private int version;
>
> > > ďż˝ ďż˝ ďż˝@OneToOne(mappedBy="wheel", cascade = CascadeType.ALL)
> > > � � �private Tire tire;
>
> > > ďż˝ ďż˝ ďż˝....

>
> > > }
>
> > > Now here is a simple code that creates beans:
>
> > > � � �Wheel w1 = new Wheel();
> > > � � �Tire t1 = new Tire();
>
> > > � � �t1.setWheel(w1);
> > > � � �w1.setTire(t1);

>
> > > Now the success completely depends on which entity you provide to
> > > Ebean.save(): make it Ebean.save(w1); and it's OK; make it
> > > Ebean.save(t1); and you get exception:
>
> > > javax.persistence.PersistenceException: ERROR executing DML
> > > bindLog[Binding Insert [tire] �set[id=121, version=1, wheel=121, ]]

> > > error[ERROR: duplicate key value violates unique constraint "pk_tire"]
> > > � � �at

>
> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
> > > Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value
> > > violates unique constraint "pk_tire"
> > > � � �at
>
> > org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1608)
> > > � � �at
>
> > org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1343)
> > > � � �at
>
> > org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:194)
> > > � � �at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:451)
> > > � � �at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:350)
> > > � � �at
>
> > org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:304)
> > > � � �at
>
> > com.jolbox.bonecp.PreparedStatementHandle.executeUpdate(PreparedStatementHandle.java:228)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.type.DataBind.executeUpdate(DataBind.java:74)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.dml.InsertHandler.execute(InsertHandler.java:155)
> > > � � �at
>
> > com.avaje.ebeaninternal.server.persist.dml.DmlBeanPersister.execute(DmlBeanPersister.java:105)
> > > ďż˝ ďż˝ ďż˝... 40 more

>
> > > The transaction log:
>
> > > txn[1001], 19:27:37.932, insert into wheel (id, version) values (?,?)
> > > txn[1001], 19:27:37.932, Binding Insert [wheel]
>
> ...
>
> read more »



Saulius

unread,
Apr 26, 2011, 2:05:07 PM4/26/11
to Ebean ORM

Hey guys, any news on this?

I've spent quite some time migrating my app to use Ebean, but I cannot
release it to production for 3 weeks now because of this cascading
bug. Maybe a donation could help?

Regards, Saulius

On Apr 13, 11:01 am, Saulius Pačekajus <saul...@pacekajus.lt> wrote:
> Sure I can wait a day or two. I appreciate your help!
>
> Regards, Saulius
>
> On 2011.04.13 10:52, Rob Bygrave wrote:
>
>
>
>
>
>
>
> > Right.
>
> > I believe the problem will be something along the lines of what you
> > said earlier.... Ebean is probably searching for the other side of the
> > OneToOne's ... finding that Booking property and then incorrectly
> > thinking it is the other side of the OneToOne.
>
> > I don't have time to look at that tonight ... hopefully you can wait a
> > day or two (until I find some time to investigate).
>
> > Cheers, Rob.
>
> > 2011/4/13 Saulius Pa�ekajus <saul...@pacekajus.lt
> > <mailto:saul...@pacekajus.lt>>
>
> > I removed it from Invoice entity too and it works.
>
> > But I would really prefer to have this one as I need Booking in
> > most tasks where I process Invoice!
>
> > On 2011.04.13 04:12, Rob Bygrave wrote:
>
> >> You will need to also remove from the Invoice entity:
>
> >> @ManyToOne(cascade = CascadeType.ALL)
> >> @JoinColumn(name = "booking")
> >> private Booking booking;
>
> >> 2011/4/13 Saulius Pa�ekajus <saul...@pacekajus.lt
> >> <mailto:saul...@pacekajus.lt>>
>
> >> >>So the question is, if you remove that derived relationship
> >> (Booking on the Invoice entity) is there a problem?
>
> >> I've commented out /List<Invoice> invoices/ field on Booking
> >> entity. The problem stays the same:http://pastie.org/1788902
>
> >> All the rest code is the same, just field /invoices /and its
> >> getter and setter are commented.
>
> >> On 2011.04.13 01:15, Rob Bygrave wrote:
> >>> >> and Invoicehttp://pastie.org/1786543
>
> >>> So I see you have change Booking here to be a ManyToOne
> >>> (when it used to be a OneToOne).
>
> >>> >> The database scheme for these 2 entities is
> >>> http://pastie.org/1786710
>
> >>> I'm pretty sure the booking column is effectively derived
> >>> data. Strictly speaking it is not required for either of the
> >>> 2 relationships .... but you are looking to include it to
> >>> help you navigate the other way - hmmm, I think that might
> >>> not help you actually.
>
> >>> >> So it is not bidirectional OneToOne
>
> >>> Good - I think we are agreed on that. The problem being it
> >>> almost looked like one which I think is the problem - Ebean
> >>> likely thought you where trying to define a bi-directional
> >>> OneToOne without any mappedBy attribute (hence the recursion
> >>> problem).
>
> >>> >> So I get this error not only on bidirectional OneToOne
> >>> but on other relationships too.
>
> >>> Hmm, this statement is a regression. No mappedBy means no
> >>> bi-directional OneToOne -> this was not a bi-directional
> >>> OneToOne.
>
> >>> >> So my guess is that this happens when there is a ...
>
> >>> Sounds about right.
>
> >>> The summary for me is that you have 2 unidirectional
> >>> OneToOne relationships... plus a derived relationship going
> >>> back the other way. So the question is, if you remove that
> >>> derived relationship (Booking on the Invoice entity) is
> >>> there a problem?
>
> >>> On Wed, Apr 13, 2011 at 1:17 AM, Saulius
> >>> <saul...@pacekajus.lt <mailto:saul...@pacekajus.lt>> wrote:
>
> >>> Well I don't actually want to prove that bidirectional
> >>> OneToOne
> >>> relationship is necessary for me or anybody else. In
> >>> fact you are
> >>> right, I don't have this bidirectional OneToOne
> >>> relationship - I've
> >>> just made it up as an example to illustrate that
> >>> cascading bug that
> >>> leads to infinite recursion.
>
> >>> Anyway if you want to see complete booking and invoice
> >>> entities, here
> >>> they are: Bookinghttp://pastie.org/1786569and Invoice
> >>> http://pastie.org/1786543
> >>> (note it's actually OneToMany relationship). The
> >>> database scheme for
> >>> these 2 entities ishttp://pastie.org/1786710
>
> >>> So it is not bidirectional OneToOne, but it is a real
> >>> world example
> >>> and it does not change the fact, that when I try to save
> >>> Booking with
> >>> both invoices set (http://pastie.org/1786739) I get the
> >>> same infinite
> >>> recursion failure:http://pastie.org/1786745
>
> >>> So I get this error not only on bidirectional OneToOne
> >>> but on other
> >>> relationships too. So my guess is that this happens when
> >>> there is a
> >>> loop in relationship between 2 entities (E1 has
> >>> reference to E2 and E2
> >>> has reference to E1 - and it does not have to be a
> >>> bidirectional
> >>> relashionship) and it probably happens because after
> >>> doing work on E1
> >>> and then cascading to E2 algorithm goes again back to E1
> >>> thus getting
> >>> into infinite recursion.
>
> >>> Regards, Saulius
>
> >>> On Apr 12, 12:46 am, Rob Bygrave
> >>> <robin.bygr...@gmail.com
> >>> <mailto:saul...@pacekajus.lt>>
>
> >>> > > Hi guys,
>
> >>> > > I know it's a low priority issue for you, but it is
> >>> the only issue
> >>> > > that keeps me from using it in production and I
> >>> think it is a serious
> >>> > > problem because Ebean.save fails for a valid entity.
>
> >>> > > Once again, just to picture the situation consider
> >>> these 2 entities:
>
> >>> > > @Entity
> >>> > > @Table(name="invoice")
> >>> > > public class Invoice {
>
> >>> > > @Id @GeneratedValue(strategy =
> >>> GenerationType.SEQUENCE)
> >>> > > private Long id;
>
> >>> > > @Version
> >>> > > private int version;
>
> >>> > > @OneToOne(cascade = CascadeType.ALL)
> >>> > > @JoinColumn(name = "booking")
> >>> > > private Booking booking;
>
> >>> > > ...
> >>> > > }
>
> >>> > > @Entity
> >>> > > @Table(name = "booking")
> >>> > > public class Booking {
>
> >>> > > @Id @GeneratedValue(strategy =
> >>> GenerationType.SEQUENCE)
> >>> > > private Long id;
>
> >>> > > @Version
> >>> > > private int version;
>
> >>> > > @OneToOne(cascade = CascadeType.ALL)
> >>> > > @JoinColumn(name = "client_invoice")
> >>> > > private Invoice clientInvoice;
>
> >>> > > @OneToOne(cascade = CascadeType.ALL)
> >>> > > @JoinColumn(name = "agent_invoice")
> >>> > > private Invoice agentInvoice;
>
> >>> > > ...
> >>> > > }
>
> >>> > > As you can see I need this bidirectional OneToOne
> >>> relationship in
> >>> > > order to get Booking entity when having Invoice
> >>> entity. Without
> >>> > > JoinColumn on Booking side, I cannot identify which
> >>> of the invoices is
> >>> > > client invoice and which is agent invoice. Without
> >>> JoinColumn on
> >>> > > Invoice side, I cannot select (not that simple) all
> >>> invoices for some
> >>> > > booking, also having an invoice I cannot easily find
> >>> which booking it
> >>> > > belongs to.
>
> >>> > > On Apr 6, 7:34 pm, Saulius Pa�ekajus
> >>> <saul...@pacekajus.lt <mailto:saul...@pacekajus.lt>> wrote:
>
> ...
>
> read more >>

Rob Bygrave

unread,
Apr 26, 2011, 5:26:37 PM4/26/11
to eb...@googlegroups.com
Nope, no news ... been busy.

>> Maybe a donation could help?

Donations are always gratefully received. Unfortunately that would be about the 4th donation received and the first for quite some time - so donations are not exactly funding any of my time. We don't have a corporate sponsor so currently people will have to exercise patience. Suggestions welcome.


Cheers, Rob.

2011/4/27 Saulius <sau...@pacekajus.lt>

Saulius Pačekajus

unread,
Apr 26, 2011, 6:15:31 PM4/26/11
to eb...@googlegroups.com

Well I think making some PayPal "donate" button could help - I've been searching for it a couple of times earlier, couldn't find it.

I really need this bug fixed - changing ORM is a prerequisite for the solution of a very important efficiency problem (I cannot have efficient caching because of Hibernate/JPA session approach). Ebean (at least by description) seems to fit my needs well and everything went smoothly so far and this bug is the only serious challenge standing in my way now. Could you give me your honest opinion - is Ebean mature enough to be used with an average complexity ~100 table DB model for production purpose? I just want to know if I'm not wasting my time...

I cannot find if Ebean is an open source project - can I contribute by solving this problem myself? I'm not really an expert of ORM frameworks, but I'm pretty sure I could figure it out.

Regards, Saulius


On 2011.04.27 00:26, Rob Bygrave wrote:
Nope, no news ... been busy.

>>�Maybe a donation could help?

Donations are always�gratefully�received. Unfortunately that would be about the 4th donation�received and the first for quite some time -�so donations are not exactly funding any of my time. We don't have a corporate sponsor so currently people will have to exercise patience. Suggestions welcome.


Cheers, Rob.

2011/4/27 Saulius <sau...@pacekajus.lt>

Hey guys, any news on this?

I've spent quite some time migrating my app to use Ebean, but I cannot
release it to production for 3 weeks now because of this cascading
bug. Maybe a donation could help?

Regards, Saulius

On Apr 13, 11:01 am, Saulius Pa�ekajus <saul...@pacekajus.lt> wrote:
> Sure I can wait a day or two. I appreciate your help!
>
> Regards, Saulius
>
> On 2011.04.13 10:52, Rob Bygrave wrote:
>
>
>
>
>
>
>
> > Right.
>
> > I believe the problem will be something along the lines of what you
> > said earlier.... Ebean is probably searching for the other side of the
> > OneToOne's ... finding that Booking property and then incorrectly
> > thinking it is the other side of the OneToOne.
>
> > I don't have time to look at that tonight ... hopefully you can wait a
> > day or two (until I find some time to investigate).
>
> > Cheers, Rob.
>
> > 2011/4/13 Saulius Pa�ekajus <saul...@pacekajus.lt
> > <mailto:saul...@pacekajus.lt>>
>
> > ďż˝ ďż˝ I removed it from Invoice entity too and it works.
>
> > ďż˝ ďż˝ But I would really prefer to have this one as I need Booking in
> > ďż˝ ďż˝ most tasks where I process Invoice!
>
> > ďż˝ ďż˝ On 2011.04.13 04:12, Rob Bygrave wrote:
>
> >> ďż˝ ďż˝ You will need to also remove from the Invoice entity:
>
> >> � � @ManyToOne(cascade �= �CascadeType.ALL)
> >> ďż˝ ďż˝ @JoinColumn(name ďż˝= ďż˝"booking")
> >> � � private �Booking �booking;
>
> >> � � 2011/4/13 Saulius Pa�ekajus <saul...@pacekajus.lt
> >> ďż˝ ďż˝ <mailto:saul...@pacekajus.lt>>
>
> >> ďż˝ ďż˝ ďż˝ ďż˝ >>So the question is, if you remove that derived relationship
> >> ďż˝ ďż˝ ďż˝ ďż˝ (Booking on the Invoice entity) is there a problem?
>
> >> ďż˝ ďż˝ ďż˝ ďż˝ I've commented out /List<Invoice> invoices/ field on Booking
> >> ďż˝ ďż˝ ďż˝ ďż˝ entity. The problem stays the same:http://pastie.org/1788902
>
> >> ďż˝ ďż˝ ďż˝ ďż˝ All the rest code is the same, just field /invoices /and its
> >> ďż˝ ďż˝ ďż˝ ďż˝ getter and setter are commented.
>
> >> ďż˝ ďż˝ ďż˝ ďż˝ On 2011.04.13 01:15, Rob Bygrave wrote:
> >>> ďż˝ ďż˝ ďż˝ ďż˝ >> and Invoicehttp://pastie.org/1786543
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ So I see you have change Booking here to be a ManyToOne
> >>> ďż˝ ďż˝ ďż˝ ďż˝ (when it used to be a OneToOne).
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ >> The database scheme for these 2 entities is
> >>> � � � �http://pastie.org/1786710
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ I'm pretty sure the booking column is effectively derived
> >>> ďż˝ ďż˝ ďż˝ ďż˝ data. Strictly speaking it is not required for either of the
> >>> ďż˝ ďż˝ ďż˝ ďż˝ 2 relationships .... but you are looking to include it to
> >>> ďż˝ ďż˝ ďż˝ ďż˝ help you navigate the other way - hmmm, I think that might
> >>> ďż˝ ďż˝ ďż˝ ďż˝ not help you actually.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ >> So it is not bidirectional OneToOne
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ Good - I think we are agreed on that. The problem being it
> >>> ďż˝ ďż˝ ďż˝ ďż˝ almost looked like one which I think is the problem - Ebean
> >>> ďż˝ ďż˝ ďż˝ ďż˝ likely thought you where trying to define a bi-directional
> >>> ďż˝ ďż˝ ďż˝ ďż˝ OneToOne without any mappedBy attribute (hence the recursion
> >>> ďż˝ ďż˝ ďż˝ ďż˝ problem).
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ >> So I get this error not only on bidirectional OneToOne
> >>> ďż˝ ďż˝ ďż˝ ďż˝ but on other relationships too.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ Hmm, this statement is a regression. No mappedBy means no
> >>> ďż˝ ďż˝ ďż˝ ďż˝ bi-directional OneToOne -> this was not a bi-directional
> >>> ďż˝ ďż˝ ďż˝ ďż˝ OneToOne.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ >> So my guess is that this happens when there is a ...
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ Sounds about right.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ The summary for me is that you have 2 unidirectional
> >>> ďż˝ ďż˝ ďż˝ ďż˝ OneToOne relationships... plus a derived relationship going
> >>> ďż˝ ďż˝ ďż˝ ďż˝ back the other way. So the question is, if you remove that
> >>> ďż˝ ďż˝ ďż˝ ďż˝ derived relationship (Booking on the Invoice entity) is
> >>> ďż˝ ďż˝ ďż˝ ďż˝ there a problem?
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ On Wed, Apr 13, 2011 at 1:17 AM, Saulius
> >>> ďż˝ ďż˝ ďż˝ ďż˝ <saul...@pacekajus.lt <mailto:saul...@pacekajus.lt>> wrote:
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ Well I don't actually want to prove that bidirectional
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ OneToOne
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ relationship is necessary for me or anybody else. In
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ fact you are
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ right, I don't have this bidirectional OneToOne
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ relationship - I've
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ just made it up as an example to illustrate that
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ cascading bug that
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ leads to infinite recursion.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ Anyway if you want to see complete booking and invoice
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ entities, here
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ they are: Bookinghttp://pastie.org/1786569and Invoice
> >>> � � � � � �http://pastie.org/1786543
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ (note it's actually OneToMany relationship). The
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ database scheme for
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ these 2 entities ishttp://pastie.org/1786710
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ So it is not bidirectional OneToOne, but it is a real
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ world example
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ and it does not change the fact, that when I try to save
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ Booking with
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ both invoices set (http://pastie.org/1786739) I get the
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ same infinite
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ recursion failure:http://pastie.org/1786745
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ So I get this error not only on bidirectional OneToOne
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ but on other
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ relationships too. So my guess is that this happens when
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ there is a
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ loop in relationship between 2 entities (E1 has
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ reference to E2 and E2
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ has reference to E1 - and it does not have to be a
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ bidirectional
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ relashionship) and it probably happens because after
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ doing work on E1
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ and then cascading to E2 algorithm goes again back to E1
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ thus getting
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ into infinite recursion.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ Regards, Saulius
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ On Apr 12, 12:46 am, Rob Bygrave
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ <robin.bygr...@gmail.com
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ <mailto:robin.bygr...@gmail.com>> wrote:
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > Well, there are no mappedBy attributes so this doesn't
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ look like a valid
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > bi-directional OneToOne. As there are 2 relationship
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ here I suspect that is
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > where the confusion is - specifically around the
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ booking property in the
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > Invoice.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > I suspect you added that Booking property later
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ (originally
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > unidirectional?). Can you state again what the problem
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ you had with your
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > query (it was not obvious to me why you didn't query
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ from the Booking ... to
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > get the Invoices for a given booking).
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > Can you state what your DB tables look like (I'm
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ especially interested in
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > that booking column which looks dubious/incorrect so
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ it would be good to
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > clarify what the relational model looks like).
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > I suspect removing the booking property on the Invoice
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ is effectively the
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > fix here. Otherwise you might be looking to use a join
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ table (which Ebean
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > does not support) but that is a guess and I suspect
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ that is not what you
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > want.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > Cheers, Rob.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > 2011/4/12 Saulius <saul...@pacekajus.lt
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ <mailto:saul...@pacekajus.lt>>
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > Hi guys,
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > I know it's a low priority issue for you, but it is
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ the only issue
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > that keeps me from using it in production and I
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ think it is a serious
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > problem because Ebean.save fails for a valid entity.
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > Once again, just to picture the situation consider
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ these 2 entities:
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > @Entity
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > @Table(name="invoice")
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > public class Invoice {
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy =
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ GenerationType.SEQUENCE)
> >>> � � � � � � > > � � � �private Long id;
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝@Version
> >>> � � � � � � > > � � � �private int version;
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝ @JoinColumn(name = "booking")
> >>> � � � � � � > > � � � �private Booking booking;
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝...
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > }
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > @Entity
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > @Table(name = "booking")
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > public class Booking {
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝@Id @GeneratedValue(strategy =
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ GenerationType.SEQUENCE)
> >>> � � � � � � > > � � � �private Long id;
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝@Version
> >>> � � � � � � > > � � � �private int version;
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝ @JoinColumn(name = "client_invoice")
> >>> � � � � � � > > � � � �private Invoice clientInvoice;
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝@OneToOne(cascade = CascadeType.ALL)
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝@JoinColumn(name = "agent_invoice")
> >>> � � � � � � > > � � � �private Invoice agentInvoice;
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > ďż˝ ďż˝ ďż˝ ďż˝...
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > }
>
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > As you can see I need this bidirectional OneToOne
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ relationship in
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > order to get Booking entity when having Invoice
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ entity. Without
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > JoinColumn on Booking side, I cannot identify which
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ of the invoices is
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > client invoice and which is agent invoice. Without
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ JoinColumn on
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > Invoice side, I cannot select (not that simple) all
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ invoices for some
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > booking, also having an invoice I cannot easily find
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ which booking it
> >>> ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ ďż˝ > > belongs to.
>
> >>> � � � � � � > > On Apr 6, 7:34 pm, Saulius Pa�ekajus

Rob Bygrave

unread,
Apr 26, 2011, 11:28:01 PM4/26/11
to eb...@googlegroups.com

>> paypal
Fair enough. The button is on the source forge download page... but I see it is pretty tiny now. I will put a donate button or two on the avaje site.

>> open source
Yes it is. Links etc on the download page. Svn repo in source forge.

>> mature enough
Unfortunately I can't claim to be unbiased. After all... There are a lot more hibernate users out there.

Technically yes I think Ebean is mature enough. On the other hand the community is very small and not very 'vocal' so there is a significant support/community problem. Most questions are answered by about 4 people.

There is also no financial backing so finding time to do bugs and develop features is difficult.

Ideally Ebean finds enough support to make the next step.

Not sure if that answers your question.

Cheers, Rob.

On Apr 27, 2011 10:15 AM, "Saulius Pačekajus" <sau...@pacekajus.lt> wrote:
>
> Well I think making some PayPal "donate" button could help - I've been
> searching for it a couple of times earlier, couldn't find it.
>
> I really need this bug fixed - changing ORM is a prerequisite for the
> solution of a very important efficiency problem (I cannot have efficient
> caching because of Hibernate/JPA session approach). Ebean (at least by
> description) seems to fit my needs well and everything went smoothly so
> far and this bug is the only serious challenge standing in my way now.
> Could you give me your honest opinion - is Ebean mature enough to be
> used with an average complexity ~100 table DB model for production
> purpose? I just want to know if I'm not wasting my time...
>
> I cannot find if Ebean is an open source project - can I contribute by
> solving this problem myself? I'm not really an expert of ORM frameworks,
> but I'm pretty sure I could figure it out.
>
> Regards, Saulius
>
> On 2011.04.27 00:26, Rob Bygrave wrote:
>> Nope, no news ... been busy.
>>
>> >> Maybe a donation could help?
>>
>> Donations are always gratefully received. Unfortunately that would be
>> about the 4th donation received and the first for quite some time - so
>> donations are not exactly funding any of my time. We don't have a
>> corporate sponsor so currently people will have to exercise patience.
>> Suggestions welcome.
>>
>>
>> Cheers, Rob.
>>
>> 2011/4/27 Saulius <sau...@pacekajus.lt <mailto:sau...@pacekajus.lt>>

>>
>>
>> Hey guys, any news on this?
>>
>> I've spent quite some time migrating my app to use Ebean, but I cannot
>> release it to production for 3 weeks now because of this cascading
>> bug. Maybe a donation could help?
>>
>> Regards, Saulius
>>
>> On Apr 13, 11:01 am, Saulius Pačekajus <saul...@pacekajus.lt

>> <mailto:saul...@pacekajus.lt>> wrote:
>> > Sure I can wait a day or two. I appreciate your help!
>> >
>> > Regards, Saulius
>> >
>> > On 2011.04.13 10:52, Rob Bygrave wrote:
>> >
>> >
>> >
>> >
>> >
>> >
>> >
>> > > Right.
>> >
>> > > I believe the problem will be something along the lines of
>> what you
>> > > said earlier.... Ebean is probably searching for the other
>> side of the
>> > > OneToOne's ... finding that Booking property and then incorrectly
>> > > thinking it is the other side of the OneToOne.
>> >
>> > > I don't have time to look at that tonight ... hopefully you
>> can wait a
>> > > day or two (until I find some time to investigate).
>> >
>> > > Cheers, Rob.
>> >
>> > > 2011/4/13 Saulius Pa�ekajus <saul...@pacekajus.lt
>> <mailto:saul...@pacekajus.lt>
>> > > <mailto:saul...@pacekajus.lt <mailto:saul...@pacekajus.lt>>>

>> >
>> > > I removed it from Invoice entity too and it works.
>> >
>> > > But I would really prefer to have this one as I need
>> Booking in
>> > > most tasks where I process Invoice!
>> >
>> > > On 2011.04.13 04:12, Rob Bygrave wrote:
>> >
>> > >> You will need to also remove from the Invoice entity:
>> >
>> > >> @ManyToOne(cascade = CascadeType.ALL)
>> > >> @JoinColumn(name = "booking")
>> > >> private Booking booking;
>> >
>> > >> 2011/4/13 Saulius Pa�ekajus <saul...@pacekajus.lt
>> <mailto:saul...@pacekajus.lt>
>> > >> <mailto:saul...@pacekajus.lt <mailto:saul...@pacekajus.lt>>>

>> >
>> > >> >>So the question is, if you remove that derived relationship
>> > >> (Booking on the Invoice entity) is there a problem?
>> >
>> > >> I've commented out /List<Invoice> invoices/ field on
>> Booking
>> > >> entity. The problem stays the
>> same:http://pastie.org/1788902
>> >
>> > >> All the rest code is the same, just field /invoices
>> /and its
>> > >> getter and setter are commented.
>> >
>> > >> On 2011.04.13 01:15, Rob Bygrave wrote:
>> > >>> >> and Invoicehttp://pastie.org/1786543
>> <http://pastie.org/1786543>

>> >
>> > >>> So I see you have change Booking here to be a ManyToOne
>> > >>> (when it used to be a OneToOne).
>> >
>> > >>> >> The database scheme for these 2 entities is

>> >
>> > >>> I'm pretty sure the booking column is effectively
>> derived
>> > >>> data. Strictly speaking it is not required for
>> either of the
>> > >>> 2 relationships .... but you are looking to include
>> it to
>> > >>> help you navigate the other way - hmmm, I think that
>> might
>> > >>> not help you actually.

>> >
>> > >>> >> So it is not bidirectional OneToOne
>> >
>> > >>> Good - I think we are agreed on that. The problem
>> being it
>> > >>> almost looked like one which I think is the problem
>> - Ebean
>> > >>> likely thought you where trying to define a
>> bi-directional
>> > >>> OneToOne without any mappedBy attribute (hence the
>> recursion
>> > >>> problem).

>> >
>> > >>> >> So I get this error not only on bidirectional OneToOne
>> > >>> but on other relationships too.
>> >
>> > >>> Hmm, this statement is a regression. No mappedBy
>> means no
>> > >>> bi-directional OneToOne -> this was not a bi-directional
>> > >>> OneToOne.

>> >
>> > >>> >> So my guess is that this happens when there is a ...
>> >
>> > >>> Sounds about right.

>> >
>> > >>> The summary for me is that you have 2 unidirectional
>> > >>> OneToOne relationships... plus a derived
>> relationship going
>> > >>> back the other way. So the question is, if you
>> remove that
>> > >>> derived relationship (Booking on the Invoice entity) is
>> > >>> there a problem?

>> >
>> > >>> On Wed, Apr 13, 2011 at 1:17 AM, Saulius

>> <mailto:saul...@pacekajus.lt <mailto:saul...@pacekajus.lt>>> wrote:
>> >
>> > >>> Well I don't actually want to prove that
>> bidirectional
>> > >>> OneToOne

>> > >>> relationship is necessary for me or anybody else. In
>> > >>> fact you are

>> > >>> right, I don't have this bidirectional OneToOne
>> > >>> relationship - I've

>> > >>> just made it up as an example to illustrate that
>> > >>> cascading bug that
>> > >>> leads to infinite recursion.
>> >
>> > >>> Anyway if you want to see complete booking and
>> invoice
>> > >>> entities, here
>> > >>> they are: Bookinghttp://pastie.org/1786569and

>> > >>> (note it's actually OneToMany relationship). The
>> > >>> database scheme for
>> > >>> these 2 entities ishttp://pastie.org/1786710
>> <http://pastie.org/1786710>

>> >
>> > >>> So it is not bidirectional OneToOne, but it is a
>> real
>> > >>> world example

>> > >>> and it does not change the fact, that when I try
>> to save
>> > >>> Booking with

>> > >>> both invoices set (http://pastie.org/1786739) I
>> get the
>> > >>> same infinite
>> > >>> recursion failure:http://pastie.org/1786745
>> >
>> > >>> So I get this error not only on bidirectional
>> OneToOne
>> > >>> but on other
>> > >>> relationships too. So my guess is that this

>> happens when
>> > >>> there is a
>> > >>> loop in relationship between 2 entities (E1 has
>> > >>> reference to E2 and E2
>> > >>> has reference to E1 - and it does not have to be a
>> > >>> bidirectional

>> > >>> relashionship) and it probably happens because after
>> > >>> doing work on E1

>> > >>> and then cascading to E2 algorithm goes again
>> back to E1
>> > >>> thus getting
>> > >>> into infinite recursion.
>> >
>> > >>> Regards, Saulius
>> >
>> > >>> On Apr 12, 12:46 am, Rob Bygrave

>> <mailto:robin.bygr...@gmail.com>>> wrote:
>> > >>> > Well, there are no mappedBy attributes so this doesn't
>> > >>> look like a valid

>> > >>> > bi-directional OneToOne. As there are 2 relationship
>> > >>> here I suspect that is
>> > >>> > where the confusion is - specifically around the
>> > >>> booking property in the
>> > >>> > Invoice.
>> >
>> > >>> > I suspect you added that Booking property later
>> > >>> (originally

>> > >>> > unidirectional?). Can you state again what the problem
>> > >>> you had with your

>> > >>> > query (it was not obvious to me why you didn't query
>> > >>> from the Booking ... to
>> > >>> > get the Invoices for a given booking).
>> >
>> > >>> > Can you state what your DB tables look like (I'm
>> > >>> especially interested in

>> > >>> > that booking column which looks dubious/incorrect so
>> > >>> it would be good to
>> > >>> > clarify what the relational model looks like).
>> >
>> > >>> > I suspect removing the booking property on the Invoice
>> > >>> is effectively the

>> > >>> > fix here. Otherwise you might be looking to use a join
>> > >>> table (which Ebean

>> > >>> > does not support) but that is a guess and I suspect
>> > >>> that is not what you
>> > >>> > want.
>> >
>> > >>> > Cheers, Rob.
>> >
>> > >>> > 2011/4/12 Saulius <saul...@pacekajus.lt
>> <mailto:saul...@pacekajus.lt>
>> > >>> <mailto:saul...@pacekajus.lt <mailto:saul...@pacekajus.lt>>>
>> >
>> > >>> > > Hi guys,
>> >

>> > >>> > > I know it's a low priority issue for you, but it is
>> > >>> the only issue

>> > >>> > > that keeps me from using it in production and I
>> > >>> think it is a serious
>> > >>> > > problem because Ebean.save fails for a valid entity.
>> >
>> > >>> > > Once again, just to picture the situation consider
>> > >>> > > As you can see I need this bidirectional OneToOne
>> > >>> relationship in

>> > >>> > > order to get Booking entity when having Invoice
>> > >>> entity. Without

>> > >>> > > JoinColumn on Booking side, I cannot identify which
>> > >>> of the invoices is

>> > >>> > > client invoice and which is agent invoice. Without
>> > >>> JoinColumn on

>> > >>> > > Invoice side, I cannot select (not that simple) all
>> > >>> invoices for some

>> > >>> > > booking, also having an invoice I cannot easily find
>> > >>> which booking it
>> > >>> > > belongs to.
>> >
>> > >>> > > On Apr 6, 7:34 pm, Saulius Pa�ekajus

edge

unread,
Apr 28, 2011, 7:08:49 AM4/28/11
to Ebean ORM
As a first step to solving these problems I've added the following
tests:
#1 TestOneToOneWheelTire reproduces the Wheel + Tire problem -> unique
constraint problem
#2 TestOne2OneBookingInvoice reproduces the Booking + Invoice problem -
> infinite recursion
see package com.avaje.tests.basic.one2one;

we're working on a solution!



Saulius Pačekajus

unread,
Apr 28, 2011, 6:12:53 PM4/28/11
to eb...@googlegroups.com
That is really great news - I really appreciate that!

Regards, Saulius

Rob Bygrave

unread,
May 5, 2011, 6:06:28 AM5/5/11
to eb...@googlegroups.com
I'm curious if this model works with another ORM and if so how it persists this model.

Essentially one of the relationships I would describe as 'derived' and that means that part of the relationship can not be included in the original INSERT and an extra UPDATE statement will be required.

So in the transaction log below you will note that the booking is null for the invoice inserts (as the booking id has not been determined yet).

txn[1003], 21:51:19.120, insert into invoice (id, version, booking) values (?,?,?)
txn[1003], 21:51:19.121, Binding Insert [invoice]  set[id=1, version=1, booking=null, ]
txn[1003], 21:51:19.122, Inserted [Invoice] [1]
txn[1003], 21:51:19.122, insert into invoice (id, version, booking) values (?,?,?)
txn[1003], 21:51:19.122, Binding Insert [invoice]  set[id=2, version=1, booking=null, ]
txn[1003], 21:51:19.122, Inserted [Invoice] [2]
txn[1003], 21:51:19.124, insert into booking (id, version, agent_invoice, client_invoice) values (?,?,?,?)
txn[1003], 21:51:19.124, Binding Insert [booking]  set[id=1, version=1, agent_invoice=1, client_invoice=2, ]
txn[1003], 21:51:19.124, Inserted [Booking] [1]

I believe the expected solution is to detect this scenario and automatically execute some update statements to set the booking on the invoices.

Hmmm...


2011/4/29 Saulius Pačekajus <sau...@pacekajus.lt>

Rob Bygrave

unread,
May 5, 2011, 7:33:26 AM5/5/11
to eb...@googlegroups.com
So the "Fix" does:  (note the additional updates executed "after the insert" of the Invoice).


txn[1003], 23:29:06.564, insert into drel_invoice (id, version, booking) values (?,?,?)
txn[1003], 23:29:11.762, Binding Insert [drel_invoice]  set[id=1, version=1, booking=null, ]
txn[1003], 23:29:11.763, Inserted [Invoice] [1]
txn[1003], 23:29:11.763, insert into drel_invoice (id, version, booking) values (?,?,?)
txn[1003], 23:29:11.764, Binding Insert [drel_invoice]  set[id=2, version=1, booking=null, ]
txn[1003], 23:29:11.764, Inserted [Invoice] [2]
txn[1003], 23:29:11.767, insert into drel_booking (id, version, agent_invoice, client_invoice) values (?,?,?,?)
txn[1003], 23:29:11.767, Binding Insert [drel_booking]  set[id=1, version=1, agent_invoice=1, client_invoice=2, ]
txn[1003], 23:29:11.767, Inserted [Booking] [1]
txn[1003], 23:29:15.156, update drel_invoice set version=?, booking=? where id=? and version=?
txn[1003], 23:29:15.158, Binding Update [drel_invoice]  set[version=2, booking=1, ] where[id=1, version=1, ]
txn[1003], 23:29:15.190, Updated [Invoice] [1]
txn[1003], 23:29:18.636, update drel_invoice set version=?, booking=? where id=? and version=?
txn[1003], 23:29:18.636, Binding Update [drel_invoice]  set[version=2, booking=1, ] where[id=2, version=1, ]
txn[1003], 23:29:18.636, Updated [Invoice] [2]

And the unit test is:

    public void test() {
        Booking b = new Booking();

        Invoice ai = new Invoice();
        Invoice ci = new Invoice();

        ai.setBooking(b);
        ci.setBooking(b);

        b.setAgentInvoice(ai);
        b.setClientInvoice(ci);

        Ebean.save(b);
       
        Booking b1 = Ebean.find(Booking.class, b.getId());
       
        Invoice ai1 = b1.getAgentInvoice();
        Assert.assertNotNull(ai1);
       
        Booking b2 = ai1.getBooking();
        Assert.assertNotNull(b2);
        Assert.assertEquals(b1.getId(), b2.getId());
        Assert.assertSame(b1, b2);
       
        Invoice ci1 = b1.getClientInvoice();
        Booking b3 = ci1.getBooking();
        Assert.assertNotNull(b3);
        Assert.assertEquals(b1.getId(), b2.getId());
        Assert.assertSame(b1, b2);

Rob Bygrave

unread,
May 5, 2011, 9:00:00 AM5/5/11
to eb...@googlegroups.com
FYI

The "fix" for this has been committed to HEAD.
Reply all
Reply to author
Forward
0 new messages