Re: Cross data map relationships
Ricardo Parada <[email protected]> Tue, 14 Oct 2025 19:13:24 -0400
| Newsgroups | gmane.comp.java.cayenne.user |
|---|---|
| Message-ID | <[email protected]> |
Hi Andrus, I asked ChatGPT and it suggested adding the following two lines in addition t= o creating the EntityResolver as you suggested.=20 var namespace =3D 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.=20= Thank you Ricardo Parada > On Oct 14, 2025, at 5:54=E2=80=AFPM, Andrus Adamchik <[email protected]>= wrote: >=20 > =EF=BB=BFSee my follow up email :) >=20 >> On Oct 14, 2025, at 5:51=E2=80=AFPM, Ricardo Parada <[email protected]= LID> 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]= om> 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 D= ataMaps: >>>=20 >>> EntityResolver namespace =3D new EntityResolver(List.of(mainMap, errorsM= ap)); >>>=20 >>>> (I avoided creating data nodes and the project in this code to keep thi= ngs simple and illustrate the NullPointerException) >>>=20 >>> BTW, if you have a single DataNode, don't bother creating it in the mode= l. 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 proje= ct. >>>=20 >>> Andrus >>>=20 >>>=20 >>>> On Oct 14, 2025, at 5:23=E2=80=AFPM, Ricardo Parada <[email protected]= VALID> 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 DbTabl= e 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 ob= jects 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 thi= ngs 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, appUs= erDb)); >>>> appUserDb.addAttribute(new DbAttribute("EMAIL", Types.VARCHAR, appU= serDb)); >>>> appUserDb.getPrimaryKeyGenerator(); >>>>=20 >>>> // APP_ERROR DbEntity >>>> DbEntity appErrorDb =3D new DbEntity("APP_ERROR"); >>>> DbAttribute appErrorIdDbAttr =3D new DbAttribute("ID", Types.INTEGE= R, appErrorDb); >>>> appErrorDb.addAttribute(appErrorIdDbAttr); >>>> appErrorDb.addAttribute(new DbAttribute("APP_USER_ID", Types.INTEGE= R, appErrorDb)); >>>> appErrorDb.addAttribute(new DbAttribute("ERROR_MESSAGE", Types.VARC= HAR, 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.lan= g.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 EmptyConfigurationNod= eVisitor(); >>>>=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-projec= t.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 tar= get 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 fo= r the target entity name in the data map corresponding to the source ObjEnti= ty. 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 th= e 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 Obj= Relationship programmatically. >>>>>=20 >>>>> I could put all eomodels that have cross eomodel relationships into th= e 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 t= he obj-relationship in the XML have target correctly set. >>>>>=20 >>>>> Thank you all in advance. >>>>> Ricardo Parada >>>=20 >=20