Hi Andrus,

I asked ChatGPT and it suggested adding the following two lines in addition to 
creating the EntityResolver as you suggested. 

var namespace = new EntityResolver(List.of(mainMap, errorsMap));
mainMap.setNamespace(namespace);
errorsMap.setNamespace(namespace);

Now it is generating the target attribute for the relationships in the XML. 

Thank you
Ricardo Parada




> On Oct 14, 2025, at 5:54 PM, Andrus Adamchik <[email protected]> wrote:
> 
> See my follow up email :)
> 
>> On Oct 14, 2025, at 5:51 PM, Ricardo Parada <[email protected]> wrote:
>> 
>> Andrus,
>> 
>> What should I do then with the entity resolver?
>> 
>> I created it like you said but it’s still not being used.
>> 
>> Thank you
>> Ricardo Parada
>> 
>> 
>> 
>> 
>>>> On Oct 14, 2025, at 5:33 PM, Andrus Adamchik <[email protected]> wrote:
>>> 
>>> 
>>>> 
>>>> I then save the first  data map and it throws a NullPointerException.  
>>> 
>>> Before save, try this to make sure entities can find each other across 
>>> DataMaps:
>>> 
>>> EntityResolver namespace = new EntityResolver(List.of(mainMap, errorsMap));
>>> 
>>>> (I avoided creating data nodes and the project in this code to keep things 
>>>> simple and illustrate the NullPointerException)
>>> 
>>> BTW, if you have a single DataNode, don't bother creating it in the model. 
>>> It is much simpler and cleaner to just assign a DataSource when creating a 
>>> CayenneRuntime, and Cayenne will use it to handle all DataMaps in the 
>>> project.
>>> 
>>> Andrus
>>> 
>>> 
>>>> On Oct 14, 2025, at 5:23 PM, Ricardo Parada <[email protected]> 
>>>> wrote:
>>>> 
>>>> Here is a very minimal test of what I am seeing.
>>>> 
>>>> Two data maps: Main and Errors.
>>>> 
>>>> I have an APP_USER DbTable in the Main data map and an APP_ERROR DbTable 
>>>> in the Errors data map.
>>>> 
>>>> Then I have a to-many relationship and inverse to one between these two.
>>>> 
>>>> APP_USER <->> APP_ERROR
>>>> 
>>>> I then simply create the ObjEntity, ObjAttribute and ObjRelationship 
>>>> objects programmatically.
>>>> 
>>>> I then save the first  data map and it throws a NullPointerException.  
>>>> 
>>>> Here is the isolated test:
>>>> 
>>>> (I avoided creating data nodes and the project in this code to keep things 
>>>> simple and illustrate the NullPointerException)
>>>> 
>>>> package play.cay.utils.conversion;
>>>> 
>>>> import java.io.PrintWriter;
>>>> import java.sql.Types;
>>>> 
>>>> import org.apache.cayenne.configuration.EmptyConfigurationNodeVisitor;
>>>> import org.apache.cayenne.map.DataMap;
>>>> import org.apache.cayenne.map.DbAttribute;
>>>> import org.apache.cayenne.map.DbEntity;
>>>> import org.apache.cayenne.map.DbJoin;
>>>> import org.apache.cayenne.map.DbRelationship;
>>>> import org.apache.cayenne.map.ObjAttribute;
>>>> import org.apache.cayenne.map.ObjEntity;
>>>> import org.apache.cayenne.map.ObjRelationship;
>>>> import org.apache.cayenne.util.XMLEncoder;
>>>> 
>>>> public class DataMapTest {
>>>> 
>>>> public static void main(String[] args) {
>>>>     // Create DataMaps
>>>>     DataMap mainMap = new DataMap("Main");
>>>>     DataMap errorsMap = new DataMap("Errors");
>>>> 
>>>>     // -------------------- DB Entities --------------------
>>>> 
>>>>     // APP_USER DbEntity
>>>>     DbEntity appUserDb = new DbEntity("APP_USER");
>>>>     DbAttribute appUserIdDbAttr = new DbAttribute("ID", Types.INTEGER, 
>>>> appUserDb);
>>>>     appUserIdDbAttr.setPrimaryKey(true);
>>>>     appUserDb.addAttribute(appUserIdDbAttr);
>>>>     appUserDb.addAttribute(new DbAttribute("NAME", Types.VARCHAR, 
>>>> appUserDb));
>>>>     appUserDb.addAttribute(new DbAttribute("EMAIL", Types.VARCHAR, 
>>>> appUserDb));
>>>>     appUserDb.getPrimaryKeyGenerator();
>>>> 
>>>>     // APP_ERROR DbEntity
>>>>     DbEntity appErrorDb = new DbEntity("APP_ERROR");
>>>>     DbAttribute appErrorIdDbAttr = new DbAttribute("ID", Types.INTEGER, 
>>>> appErrorDb);
>>>>     appErrorDb.addAttribute(appErrorIdDbAttr);
>>>>     appErrorDb.addAttribute(new DbAttribute("APP_USER_ID", Types.INTEGER, 
>>>> appErrorDb));
>>>>     appErrorDb.addAttribute(new DbAttribute("ERROR_MESSAGE", 
>>>> Types.VARCHAR, appErrorDb));
>>>> 
>>>>     // Add DbEntities to respective maps
>>>>     mainMap.addDbEntity(appUserDb);
>>>>     errorsMap.addDbEntity(appErrorDb);
>>>> 
>>>>     // -------------------- DB Relationships --------------------
>>>> 
>>>>     // APP_ERROR -> APP_USER (to-one)
>>>>     DbRelationship toUserRel = new DbRelationship("appUser");
>>>>     toUserRel.setSourceEntity(appErrorDb);
>>>>     toUserRel.setTargetEntityName(appUserDb);
>>>>     toUserRel.setToMany(false);
>>>>     toUserRel.addJoin(new DbJoin(toUserRel, "APP_USER_ID", "ID"));
>>>>     appErrorDb.addRelationship(toUserRel);
>>>> 
>>>>     // APP_USER ->> APP_ERROR (to-many)
>>>>     DbRelationship errorsRel = new DbRelationship("errors");
>>>>     errorsRel.setSourceEntity(appUserDb);
>>>>     errorsRel.setTargetEntityName(appErrorDb);
>>>>     errorsRel.setToMany(true);
>>>>     errorsRel.addJoin(new DbJoin(errorsRel, "ID", "APP_USER_ID"));
>>>>     appUserDb.addRelationship(errorsRel);
>>>> 
>>>>     // -------------------- ObjEntities --------------------
>>>> 
>>>>     // APP_USER ObjEntity
>>>>     ObjEntity appUserObj = new ObjEntity("AppUser");
>>>>     appUserObj.setDbEntity(appUserDb);
>>>>     appUserObj.addAttribute(new ObjAttribute("id", "java.lang.Integer", 
>>>> appUserObj));
>>>>     appUserObj.addAttribute(new ObjAttribute("name", "java.lang.String", 
>>>> appUserObj));
>>>>     appUserObj.addAttribute(new ObjAttribute("email", "java.lang.String", 
>>>> appUserObj));
>>>> 
>>>>     // APP_ERROR ObjEntity
>>>>     ObjEntity appErrorObj = new ObjEntity("AppError");
>>>>     appErrorObj.setDbEntity(appErrorDb);
>>>>     appErrorObj.addAttribute(new ObjAttribute("id", "java.lang.Integer", 
>>>> appErrorObj));
>>>>     appErrorObj.addAttribute(new ObjAttribute("errorMessage", 
>>>> "java.lang.String", appErrorObj));
>>>> 
>>>>     // Add ObjEntities to respective maps
>>>>     mainMap.addObjEntity(appUserObj);
>>>>     errorsMap.addObjEntity(appErrorObj);
>>>> 
>>>>     // -------------------- ObjRelationships --------------------
>>>> 
>>>>     // AppError → AppUser (to-one)
>>>>     ObjRelationship appUserRel = new ObjRelationship("appUser");
>>>>     appUserRel.setSourceEntity(appErrorObj);
>>>>     appUserRel.setTargetEntityName(appUserObj); // sets target name
>>>>     appUserRel.setDbRelationshipPath("appUser");
>>>>     appErrorObj.addRelationship(appUserRel);
>>>> 
>>>>     // AppUser → AppError (to-many)
>>>>     ObjRelationship errorsRelObj = new ObjRelationship("errors");
>>>>     errorsRelObj.setSourceEntity(appUserObj);
>>>>     errorsRelObj.setTargetEntityName(appErrorObj); // sets target name
>>>>     errorsRelObj.setDbRelationshipPath("errors");
>>>>     appUserObj.addRelationship(errorsRelObj);
>>>> 
>>>>     PrintWriter stdout = new PrintWriter(System.out, true);
>>>>     XMLEncoder encoder = new XMLEncoder(stdout, "\t", "11");
>>>>     EmptyConfigurationNodeVisitor visitor = new 
>>>> EmptyConfigurationNodeVisitor();
>>>> 
>>>>     stdout.println(mainMap.getName());
>>>>     stdout.println();
>>>>     encoder.nested(mainMap, visitor);
>>>> 
>>>>     stdout.println();
>>>>     stdout.println();
>>>> 
>>>>     stdout.println(errorsMap.getName());
>>>>     stdout.println();
>>>>     encoder.nested(errorsMap, visitor);
>>>> 
>>>> }
>>>> }
>>>> 
>>>> 
>>>> 
>>>>> 
>>>>>> On Oct 14, 2025, at 3:29 PM, Ricardo Parada <[email protected]> wrote:
>>>>> 
>>>>> Hello,
>>>>> 
>>>>> I wrote a converter to convert our eomodels from EOF to 
>>>>> Cayenne-project.xml and data maps .map.xml
>>>>> 
>>>>> So far so good. However, I seem to be running into a problem for cross 
>>>>> data map relationships.
>>>>> 
>>>>> I’m using 5.0-M1.
>>>>> 
>>>>> When I’m creating the ObjRelationship I call:
>>>>> 
>>>>> objRel.setTargetEntityName(targetObjEntity);
>>>>> 
>>>>> If I then call objRel.getTargetEntityName() it returns the correct target 
>>>>> entity name.  
>>>>> 
>>>>> However, if I call objRel.getTargetEntity() it returns null.
>>>>> 
>>>>> I debugged the code and I can see that getTargetEntity() is looking for 
>>>>> the target entity name in the data map corresponding to the source 
>>>>> ObjEntity. And it does not find it and returns null for that reason.
>>>>> 
>>>>> As a result of that, when I call encodeAsXML() on objRel I see that the 
>>>>> XML is missing the target attribute in the obj-relationship xml tag.
>>>>> 
>>>>> Is this a bug in 5.0-M1 or am I missing something when creating my 
>>>>> ObjRelationship programmatically.
>>>>> 
>>>>> I could put all eomodels that have cross eomodel relationships into the 
>>>>> same data map to avoid this problem.
>>>>> 
>>>>> But when I create it in Cayenne Modeler 4.3.3 it seems to work. I see the 
>>>>> obj-relationship in the XML have target correctly set.
>>>>> 
>>>>> Thank you all in advance.
>>>>> Ricardo Parada
>>> 
> 

Reply via email to