I tried your suggestion to take out the commit inside the find but now
I'm getting the No Rows error. I am using Cayenne generated primary
keys on all my tables. This is something I don't understand on how
Cayenne works internally. The CommunicationType object does not yet
exist permanently in the database table so how or when does it generate
the primary key for the object to be referenced by another object before
it is committed? I was hoping to not have to worry about this as a
"high-level" user of Cayenne.
I think what I need to do is to retrieve and/or create the
CommunicationType object first to make sure it exists and committed and
then use it in my CommunicationLog object instead of trying to
dynamically create one during the creation of the other. It's a little
less convenient as I have to consider it during my coding. I also read
through the "ObjectContext Nesting" section of the Cayenne documentation
but the way I understand it is that the commits cascade from the parent
downwards which basically works opposite to what I'm trying to achieve
which is committing the children first to enable the proper creation of
the parent object.
Please correct me if I'm wrong. ;-)
Caused by: java.sql.SQLException: No rows for 'CommunicationType'
at
org.apache.cayenne.dba.mysql.MySQLPkGenerator.getLongPrimaryKey(MySQLPkGenerator.java:157)
at
org.apache.cayenne.dba.mysql.MySQLPkGenerator.longPkFromDatabase(MySQLPkGenerator.java:81)
at
org.apache.cayenne.dba.JdbcPkGenerator.generatePk(JdbcPkGenerator.java:230)
at
org.apache.cayenne.access.DataDomainInsertBucket.createPermIds(DataDomainInsertBucket.java:162)
at
org.apache.cayenne.access.DataDomainInsertBucket.appendQueriesInternal(DataDomainInsertBucket.java:73)
at
org.apache.cayenne.access.DataDomainSyncBucket.appendQueries(DataDomainSyncBucket.java:78)
at
org.apache.cayenne.access.DataDomainFlushAction.preprocess(DataDomainFlushAction.java:185)
at
org.apache.cayenne.access.DataDomainFlushAction.flush(DataDomainFlushAction.java:143)
at
org.apache.cayenne.access.DataDomain.onSyncFlush(DataDomain.java:633)
at
org.apache.cayenne.access.DataDomain.onSyncNoFilters(DataDomain.java:603)
at
org.apache.cayenne.access.DataDomain$DataDomainSyncFilterChain.onSync(DataDomain.java:764)
at
org.apache.cayenne.tx.TransactionFilter$1.perform(TransactionFilter.java:73)
at
org.apache.cayenne.tx.TransactionFilter$1.perform(TransactionFilter.java:70)
at
org.apache.cayenne.tx.DefaultTransactionManager.performInTransaction(DefaultTransactionManager.java:87)
at
org.apache.cayenne.tx.DefaultTransactionManager.performInLocalTransaction(DefaultTransactionManager.java:59)
at
org.apache.cayenne.tx.DefaultTransactionManager.performInTransaction(DefaultTransactionManager.java:52)
at
org.apache.cayenne.tx.DefaultTransactionManager.performInTransaction(DefaultTransactionManager.java:40)
at
org.apache.cayenne.tx.TransactionFilter.onSync(TransactionFilter.java:70)
at
org.apache.cayenne.access.DataDomain$DataDomainSyncFilterChain.onSync(DataDomain.java:764)
at org.apache.cayenne.access.DataDomain.onSync(DataDomain.java:590)
at
org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:742)
On 19/09/17 03:21 AM, Nikita Timofeev wrote:
Ok, looked closer at your code, commitChanges() call inside find()
method doing not what you expect, it flushes ALL changes in a given
context to DB, and that includes partially created CommunicationLog
object.
Generally there is no need to commit every object, you can create and
link as many objects as you need, so you can just skip commitChanges()
call inside find() method or you should find CommunicationType first
and then create CommunicationLog.
On Mon, Sep 18, 2017 at 7:08 PM, Andrew Willerding
<[email protected]> wrote:
Hi Nikita,
Based on what you said below, I rebuilt my Database Schema from scratch but
now I'm getting the error below. The validation is failing the line 34
ClientBaseAdmin.getObjectContext().commitChanges();
because of the line 418
cl.setCommunicationType(CommunicationType.find("Email"));
To me it looks like the commit can't happen in the child record because the
commit from the parent record is incomplete and no record is created at all.
Andrew
Caused by: org.apache.cayenne.validation.ValidationException: [v.4.0.B1 Jun
02 2017 15:11:18] Validation failures: Validation failure for
com.callistacti.clientbase.Database.CommunicationLog.communicationType:
"communicationType" is required.
Validation failure for
com.callistacti.clientbase.Database.CommunicationLog.communicationType:
"communicationType" is required.
at
org.apache.cayenne.access.ObjectStoreGraphDiff.validateAndCheckNoop(ObjectStoreGraphDiff.java:113)
at
org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:734)
at
org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:691)
at
com.callistacti.clientbase.Database.CommunicationType.find(CommunicationType.java:34)
at
com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:418)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
On 18/09/17 11:40 AM, Nikita Timofeev wrote:
Hi Andrew,
Can you provide stack trace for the exception you got (Cayenne related
part of it)?
It seems to me that you have problem with PK generation, not with your
data objects.
Your code looks fine to me and should work.
On Mon, Sep 18, 2017 at 6:30 PM, Andrew Willerding
<[email protected]> wrote:
Hi,
I am trying to create a DB record where a dependency record may not yet
exist and I'm getting a "No rows for ..." error. I don't understand how
I
should create the child record that will be used for the parent object so
it
can be referenced by the parent object without getting an error. The
idea
is to dynamically create a child record as needed.
Thanks,
Andrew
Example code:
ObjectContext oc = ClientBaseAdmin.getObjectContext();
CommunicationLog cl = oc.newObject(CommunicationLog.class);
cl.setCommunicationDT(LocalDateTime.now());
cl.setCommunicationType(CommunicationType.find("Email"));
oc.commitChanges();
and in CommunicationType I have
public static CommunicationType find(String value) {
CommunicationType result = null;
result = ObjectSelect.query(CommunicationType.class)
.where(CommunicationType.DESCRIPTION.eq(value))
.selectFirst(ClientBaseAdmin.getObjectContext());
if (result == null) {
CommunicationType ct =
ClientBaseAdmin.getObjectContext().newObject(CommunicationType.class);
ct.setDescription(value);
ClientBaseAdmin.getObjectContext().commitChanges();
result = ct;
}
return result;
}