Re: Cross data map relationships

Andrus Adamchik <[email protected]> Tue, 14 Oct 2025 17:53:37 -0400
Newsgroups gmane.comp.java.cayenne.user
Message-ID <[email protected]>
See my follow up email :)=20

> On Oct 14, 2025, at 5:51=E2=80=AFPM, Ricardo Parada =
<[email protected]> wrote:
>=20
> Andrus,
>=20
> What should I do then with the entity resolver?
>=20
> I created it like you said but it=E2=80=99s still not being used.
>=20
> Thank you
> Ricardo Parada
>=20
>=20
>=20
>=20
>> On Oct 14, 2025, at 5:33=E2=80=AFPM, Andrus Adamchik =
<[email protected]> wrote:
>>=20
>> =EF=BB=BF
>>>=20
>>> I then save the first  data map and it throws a =
NullPointerException. =20
>>=20
>> Before save, try this to make sure entities can find each other =
across DataMaps:
>>=20
>> EntityResolver namespace =3D new EntityResolver(List.of(mainMap, =
errorsMap));
>>=20
>>> (I avoided creating data nodes and the project in this code to keep =
things simple and illustrate the NullPointerException)
>>=20
>> 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.
>>=20
>> Andrus
>>=20
>>=20
>>> On Oct 14, 2025, at 5:23=E2=80=AFPM, Ricardo Parada =
<[email protected]> wrote:
>>>=20
>>> Here is a very minimal test of what I am seeing.
>>>=20
>>> Two data maps: Main and Errors.
>>>=20
>>> I have an APP_USER DbTable in the Main data map and an APP_ERROR =
DbTable in the Errors data map.
>>>=20
>>> Then I have a to-many relationship and inverse to one between these =
two.
>>>=20
>>> APP_USER <->> APP_ERROR
>>>=20
>>> I then simply create the ObjEntity, ObjAttribute and ObjRelationship =
objects programmatically.
>>>=20
>>> I then save the first  data map and it throws a =
NullPointerException. =20
>>>=20
>>> Here is the isolated test:
>>>=20
>>> (I avoided creating data nodes and the project in this code to keep =
things simple and illustrate the NullPointerException)
>>>=20
>>> package play.cay.utils.conversion;
>>>=20
>>> import java.io.PrintWriter;
>>> import java.sql.Types;
>>>=20
>>> 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;
>>>=20
>>> public class DataMapTest {
>>>=20
>>>  public static void main(String[] args) {
>>>      // Create DataMaps
>>>      DataMap mainMap =3D new DataMap("Main");
>>>      DataMap errorsMap =3D new DataMap("Errors");
>>>=20
>>>      // -------------------- DB Entities --------------------
>>>=20
>>>      // APP_USER DbEntity
>>>      DbEntity appUserDb =3D new DbEntity("APP_USER");
>>>      DbAttribute appUserIdDbAttr =3D 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();
>>>=20
>>>      // APP_ERROR DbEntity
>>>      DbEntity appErrorDb =3D new DbEntity("APP_ERROR");
>>>      DbAttribute appErrorIdDbAttr =3D 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));
>>>=20
>>>      // Add DbEntities to respective maps
>>>      mainMap.addDbEntity(appUserDb);
>>>      errorsMap.addDbEntity(appErrorDb);
>>>=20
>>>      // -------------------- DB Relationships --------------------
>>>=20
>>>      // APP_ERROR -> APP_USER (to-one)
>>>      DbRelationship toUserRel =3D new DbRelationship("appUser");
>>>      toUserRel.setSourceEntity(appErrorDb);
>>>      toUserRel.setTargetEntityName(appUserDb);
>>>      toUserRel.setToMany(false);
>>>      toUserRel.addJoin(new DbJoin(toUserRel, "APP_USER_ID", "ID"));
>>>      appErrorDb.addRelationship(toUserRel);
>>>=20
>>>      // APP_USER ->> APP_ERROR (to-many)
>>>      DbRelationship errorsRel =3D new DbRelationship("errors");
>>>      errorsRel.setSourceEntity(appUserDb);
>>>      errorsRel.setTargetEntityName(appErrorDb);
>>>      errorsRel.setToMany(true);
>>>      errorsRel.addJoin(new DbJoin(errorsRel, "ID", "APP_USER_ID"));
>>>      appUserDb.addRelationship(errorsRel);
>>>=20
>>>      // -------------------- ObjEntities --------------------
>>>=20
>>>      // APP_USER ObjEntity
>>>      ObjEntity appUserObj =3D 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));
>>>=20
>>>      // APP_ERROR ObjEntity
>>>      ObjEntity appErrorObj =3D new ObjEntity("AppError");
>>>      appErrorObj.setDbEntity(appErrorDb);
>>>      appErrorObj.addAttribute(new ObjAttribute("id", =
"java.lang.Integer", appErrorObj));
>>>      appErrorObj.addAttribute(new ObjAttribute("errorMessage", =
"java.lang.String", appErrorObj));
>>>=20
>>>      // Add ObjEntities to respective maps
>>>      mainMap.addObjEntity(appUserObj);
>>>      errorsMap.addObjEntity(appErrorObj);
>>>=20
>>>      // -------------------- ObjRelationships --------------------
>>>=20
>>>      // AppError =C3=A2=C2=86=C2=92 AppUser (to-one)
>>>      ObjRelationship appUserRel =3D new ObjRelationship("appUser");
>>>      appUserRel.setSourceEntity(appErrorObj);
>>>      appUserRel.setTargetEntityName(appUserObj); // sets target name
>>>      appUserRel.setDbRelationshipPath("appUser");
>>>      appErrorObj.addRelationship(appUserRel);
>>>=20
>>>      // AppUser =C3=A2=C2=86=C2=92 AppError (to-many)
>>>      ObjRelationship errorsRelObj =3D new ObjRelationship("errors");
>>>      errorsRelObj.setSourceEntity(appUserObj);
>>>      errorsRelObj.setTargetEntityName(appErrorObj); // sets target =
name
>>>      errorsRelObj.setDbRelationshipPath("errors");
>>>      appUserObj.addRelationship(errorsRelObj);
>>>=20
>>>      PrintWriter stdout =3D new PrintWriter(System.out, true);
>>>      XMLEncoder encoder =3D new XMLEncoder(stdout, "\t", "11");
>>>      EmptyConfigurationNodeVisitor visitor =3D new =
EmptyConfigurationNodeVisitor();
>>>=20
>>>      stdout.println(mainMap.getName());
>>>      stdout.println();
>>>      encoder.nested(mainMap, visitor);
>>>=20
>>>      stdout.println();
>>>      stdout.println();
>>>=20
>>>      stdout.println(errorsMap.getName());
>>>      stdout.println();
>>>      encoder.nested(errorsMap, visitor);
>>>=20
>>>  }
>>> }
>>>=20
>>>=20
>>>=20
>>>>=20
>>>>> On Oct 14, 2025, at 3:29=E2=80=AFPM, Ricardo Parada =
<[email protected]> wrote:
>>>>=20
>>>> =EF=BB=BFHello,
>>>>=20
>>>> I wrote a converter to convert our eomodels from EOF to =
Cayenne-project.xml and data maps .map.xml
>>>>=20
>>>> So far so good. However, I seem to be running into a problem for =
cross data map relationships.
>>>>=20
>>>> I=E2=80=99m using 5.0-M1.
>>>>=20
>>>> When I=E2=80=99m creating the ObjRelationship I call:
>>>>=20
>>>> objRel.setTargetEntityName(targetObjEntity);
>>>>=20
>>>> If I then call objRel.getTargetEntityName() it returns the correct =
target entity name. =20
>>>>=20
>>>> However, if I call objRel.getTargetEntity() it returns null.
>>>>=20
>>>> 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.
>>>>=20
>>>> 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.
>>>>=20
>>>> Is this a bug in 5.0-M1 or am I missing something when creating my =
ObjRelationship programmatically.
>>>>=20
>>>> I could put all eomodels that have cross eomodel relationships into =
the same data map to avoid this problem.
>>>>=20
>>>> 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.
>>>>=20
>>>> Thank you all in advance.
>>>> Ricardo Parada
>>=20