Unless I'm misunderstanding something, I believe I do have a separate field to handle the relationship.  The NotifyQueue entity has a notifyEventID that is used to map back to the id of the NotifyEvent.  The clientID, and other "ID" fields in NotifyQueue is also used for a similar relationship to other DB entities but a phantom object is not created for any of those tables and I use this type of relationship elsewhere in my code and in other applications without Phantom objects being created.  This is the first time I've encountered this which is why I'm at a bit of a loss as to how to get around it.  I've included an extract of my map file to show the relationship between these two tables.  I can't see anything different in the map file for the NotifyEvent->NotifyQueue relationship compared to the NotifyQueue->Client relationship.

    <db-entity name="NotifyEvent">
        <db-attribute name="DTStart" type="TIMESTAMP" isMandatory="true"/>
        <db-attribute name="id" type="INTEGER" isPrimaryKey="true" isGenerated="true" isMandatory="true"/>
    </db-entity>

    <db-entity name="NotifyQueue">
        <db-attribute name="clientID" type="INTEGER" isMandatory="true"/>
        <db-attribute name="description" type="VARCHAR" length="255"/>
        <db-attribute name="durationMS" type="INTEGER"/>
        <db-attribute name="id" type="INTEGER" isPrimaryKey="true" isGenerated="true" isMandatory="true"/>
        <db-attribute name="notifyContactID" type="INTEGER"/>
        <db-attribute name="notifyEventID" type="INTEGER" isMandatory="true"/>         <db-attribute name="notifyTypeID" type="INTEGER" isMandatory="true">             <info:property xmlns:info="http://cayenne.apache.org/schema/10/info"; name="comment" value="Phone, email, sms, etc"/>
        </db-attribute>
        <db-attribute name="statusID" type="SMALLINT" isMandatory="true"/>
    </db-entity>

    <db-entity name="Client">
        <db-attribute name="id" type="INTEGER" isPrimaryKey="true" isGenerated="true" isMandatory="true" length="10"/>         <db-attribute name="name" type="VARCHAR" isMandatory="true" length="64"/>
    </db-entity>

    <obj-entity name="NotifyQueue" className="com.callistacti.clientbase.Database.NotifyQueue" dbEntityName="NotifyQueue">         <obj-attribute name="description" type="java.lang.String" db-attribute-path="description"/>         <obj-attribute name="statusID" type="short" db-attribute-path="statusID"/>
    </obj-entity>

    <db-relationship name="notifyEvent" source="NotifyQueue" target="NotifyEvent">
        <db-attribute-pair source="notifyEventID" target="id"/>
    </db-relationship>

    <db-relationship name="listNotifyQueue" source="NotifyEvent" target="NotifyQueue" toMany="true">
        <db-attribute-pair source="id" target="notifyEventID"/>
    </db-relationship>

    <db-relationship name="listNotifyQueue" source="Client" target="NotifyQueue" toMany="true">
        <db-attribute-pair source="id" target="clientID"/>
    </db-relationship>

On 2019-02-12 10:33 a.m., Ken Anderson wrote:
So, I don’t know if Cayenne does this, but WebObjects used to create phantom 
objects too…

The reason it did it was because there was a mandatory to-one relationship in 
the model, where the primary key of the source of the relationship was also the 
primary key of the related object.

This is not a good modeling technique (the mandatory to-one should have it’s 
own primary key). Does your model have this particular issue?

On Feb 11, 2019, at 10:05 AM, Andrew Willerding <[email protected]> 
wrote:

Hi,

Sorry for this long post item but I'm struggling with strange issue I haven't 
encountered before with Cayenne and hopefully I'm providing enough detail to 
get some insight into what my issue is.

A new database object is somehow being created without my explicit creation and 
I don't understand how or why it is happening.  Below is the output from the 
cayenne log that will correspond to the code extractions underneath it.

The **first** insert of NotifyEvent is the one I'm intending to create and it 
works correctly.  There are a number of data updates/retrievals underneath it 
as I'm accessing some of the objects that will be associated with the dependent 
NotifyQueue objects I wish to connect to the NotifyEvent.  It's the 
***second*** NotifyEvent insertion with all null values is the one I don't 
understand how or where it's being inadvertently created in my code.

2019-02-11,09:38:28:058,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,INSERT INTO 
NotifyEvent (DTCompleted, DTStart, DTStopBy, clientID, createdDT, 
creatorContactID, defaultLanguage, description, durationMS, isTemplate, 
lockedToMinUserLevel, notes, notifyAppID, notifyAttachments, notifyBody, 
notifyContactID, notifyGroupID, notifyMessageID, notifyRepeatCount, 
notifyRepeatCronValue, notifyRepeatInterval, notifyRepeatMaxTimes, 
notifySubject, params, priority, recipientCountNotified, scheduleID, 
scriptName, statusID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2019-02-11,09:38:28:060,INFO ,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,[bind: 1->DTCompleted:NULL, 2->DTStart:2019-02-11T10:00:15.043278, 
3->DTStopBy:NULL, 4->clientID:201, 5->createdDT:2019-02-11T09:38:11.230615, 6->creatorContactID:200, 7->defaultLanguage:'EN', 
8->description:'Callista Support created 2019-...', 9->durationMS:0, 10->isTemplate:'false', 11->lockedToMinUserLevel:0, 12->notes:'', 
13->notifyAppID:2, 14->notifyAttachments:'', 15->notifyBody:'', 16->notifyContactID:NULL, 17->notifyGroupID:221, 18->notifyMessageID:1, 
19->notifyRepeatCount:0, 20->notifyRepeatCronValue:';* * * * *  /scripts/script.sh', 21->notifyRepeatInterval:0, 22->notifyRepeatMaxTimes:0, 
23->notifySubject:'', 24->params:'', 25->priority:0, 26->recipientCountNotified:0, 27->scheduleID:NULL, 28->scriptName:'', 29->statusID:1]
2019-02-11,09:38:28:061,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,Generated PK: 
NotifyEvent.id = 18
2019-02-11,09:38:28:061,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,=== updated 1 
row.
2019-02-11,09:38:28:061,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,UPDATE Client 
SET lastUpdateDT = ? WHERE id = ?
2019-02-11,09:38:28:062,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,[batch bind: 
1->lastUpdateDT:2019-02-11T09:38:28.044136, 2->id:201]
2019-02-11,09:38:28:062,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,=== updated 1 
row.
2019-02-11,09:38:28:062,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,UPDATE Contact 
SET lastUpdateDT = ? WHERE id = ?
2019-02-11,09:38:28:062,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,[batch bind: 
1->lastUpdateDT:2019-02-11T09:38:28.045692, 2->id:200]
2019-02-11,09:38:28:063,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,=== updated 1 
row.
2019-02-11,09:38:28:064,DEBUG,[http-nio-8080-exec-129],org.apache.cayenne.access.DataRowStore,postSnapshotsChangeEvent:
 [SnapshotEvent] source: org.apache.cayenne.access.DataRowStore@5b5cf1ec, 
modified 2 id(s), indirectly modified 5 id(s)
2019-02-11,09:38:28:068,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,+++ 
transaction committed.
2019-02-11,09:38:28:068,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,--- 
transaction started.
2019-02-11,09:38:28:069,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,SELECT 
t0.notifyDetail, t0.statusID, t0.contactID, t0.notifyTypeID, t0.id FROM 
ContactCommunication t0 WHERE t0.contactID = ? [bind: 1->contactID:240]
2019-02-11,09:38:28:070,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,=== returned 3 
rows. - took 1 ms.
2019-02-11,09:38:28:070,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,+++ 
transaction committed.
2019-02-11,09:38:28:073,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,--- 
transaction started.
2019-02-11,09:38:28:074,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,INSERT INTO 
NotifyEvent (DTCompleted, DTStart, DTStopBy, clientID, createdDT, 
creatorContactID, defaultLanguage, description, durationMS, isTemplate, 
lockedToMinUserLevel, notes, notifyAppID, notifyAttachments, notifyBody, 
notifyContactID, notifyGroupID, notifyMessageID, notifyRepeatCount, 
notifyRepeatCronValue, notifyRepeatInterval, notifyRepeatMaxTimes, 
notifySubject, params, priority, recipientCountNotified, scheduleID, 
scriptName, statusID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2019-02-11,09:38:28:074,INFO ,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,[bind: 1->DTCompleted:NULL, 2->DTStart:NULL, 3->DTStopBy:NULL, 
4->clientID:NULL, 5->createdDT:NULL, 6->creatorContactID:NULL, 7->defaultLanguage:NULL, 8->description:NULL, 9->durationMS:NULL, 
10->isTemplate:NULL, 11->lockedToMinUserLevel:NULL, 12->notes:NULL, 13->notifyAppID:NULL, 14->notifyAttachments:NULL, 15->notifyBody:NULL, 
16->notifyContactID:NULL, 17->notifyGroupID:NULL, 18->notifyMessageID:NULL, 19->notifyRepeatCount:NULL, 20->notifyRepeatCronValue:NULL, 
21->notifyRepeatInterval:NULL, 22->notifyRepeatMaxTimes:NULL, 23->notifySubject:NULL, 24->params:NULL, 25->priority:NULL, 
26->recipientCountNotified:NULL, 27->scheduleID:NULL, 28->scriptName:NULL, 29->statusID:NULL]
2019-02-11,09:38:28:080,INFO 
,[http-nio-8080-exec-129],org.apache.cayenne.log.JdbcEventLogger,*** error.
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 
Column 'DTStart' cannot be null
     at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native 
Method) ~[?:?]
     at 
jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
 ~[?:?]
     at 
jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 ~[?:?]
     at java.lang.reflect.Constructor.newInstance(Constructor.java:488) ~[?:?]


Here's the extract of code that I'm executing that generates the first 
successful notifyEvent object and is now trying to create a number of objects 
that are dependent on it when it executes the 
NotifyQueue.createNotifyQueueItemsForContact method.

                 notifyEvent.setNotifyRepeatCronValue(";* * * * * 
/scripts/script.sh");

                 notifyEvent.getObjectContext().commitChanges();

                 listSelectedNotifyQueueItems.clear();
                 if (listAllNotifyQueueItems.isEmpty()) {
                     for (Contact listContact : listContacts) {
listAllNotifyQueueItems.addAll(NotifyQueue.createNotifyQueueItemsForContact(notifyEvent,
 listContact, listNotifyTypes, 0));
                     }
                 }

Here is the NotifyQueue.createNotifyQueueItemsForContact code extract with some 
of my debug output statements...  The oc.committChanges() triggers the 
exception that appears in the debug.

     public static List<NotifyQueue> createNotifyQueueItemsForContact(NotifyEvent 
notifyEvent, Contact contact, List<NotifyType> listToNotifyType, int priority) {
         HashMap<String, NotifyQueue> result = new HashMap<>();
         ObjectContext oc = notifyEvent.getObjectContext();
         if (oc.hasChanges()){
             System.out.println("OC HAS CHANGES!!!");
             for (Object modifiedObject : oc.modifiedObjects()) {
                 System.out.println("Modified object->" + modifiedObject);
             }
         }

         for (NotifyType notifyType : listToNotifyType) {
             if (notifyType.isEmail()) {
                 if (!contact.getEmail().isEmpty()
                         && !result.containsKey(contact.getEmail())) {
                     if (contact.isNotifyActive(contact.getEmail())) {
                         NotifyQueue item = oc.newObject(NotifyQueue.class);
                         item.setAttemptCount(0);
                         // item.setDTStart(notifyEvent.getDTStart());
item.setClient(User.getLoggedInUser().getClient());
                         item.setNotifyEvent(notifyEvent);
System.out.println("***NotifyEvent-"+ notifyEvent.getDTStart());
                         item.setNotifyType(notifyType);
                         item.setNotifyContact(contact);
item.setNotifyRecipient(contact.getEmail());
                         item.setPriority(priority);
item.setStatusID(EnumNotifyStatus.CREATING.toShort());
         if (oc.hasChanges()){
             System.out.println("OC HAS CHANGES!!!");
             for (Object modifiedObject : oc.modifiedObjects()) {
                 System.out.println("Modified object->" + modifiedObject);
             }
         }
                         oc.commitChanges();
                         result.put(item.getNotifyRecipient(), item);
                     }
                 }

And this is what appears in my Console from the System.out statements.  There 
isn't an object in the OC has changes that references the second NotifyEvent 
object creation with all it's null values so I don't understand where it's 
being created and the intended notifyEvent object has the non null value of 
DTStart.

***NotifyEvent-2019-02-11T10:00:15.043278
OC HAS CHANGES!!!
Modified object->Name
Modified object->CCT Inc.
Modified object->Email
Modified object->CCT Support created 2019-02-11 09:38:28(18)
2019-02-11,09:38:28:072,DEBUG,[http-nio-8080-exec-129],app,ORMCayenne 
getObjectContext() retrieved for current thread
Feb 11, 2019 9:38:28 AM com.vaadin.server.DefaultErrorHandler doDefault
SEVERE:
org.apache.cayenne.CayenneRuntimeException: [v.4.1.M2 Jul 11 2018 14:31:15] 
Commit Exception

Any help would be greatly appreciated.

Thanks,

Andrew


Reply via email to