Re: Cross data map relationships
Ricardo Parada <[email protected]> Tue, 14 Oct 2025 17:51:31 -0400
| Newsgroups | gmane.comp.java.cayenne.user |
|---|---|
| Message-ID | <[email protected]> |
Andrus, What should I do then with the entity resolver? I created it like you said but it=E2=80=99s still not being used. Thank you Ricardo Parada > 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 Dat= aMaps: >=20 > EntityResolver namespace =3D new EntityResolver(List.of(mainMap, errorsMap= )); >=20 >> (I avoided creating data nodes and the project in this code to keep thing= s 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 C= ayenneRuntime, 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]= LID> 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 i= n 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 obje= cts 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 thing= s 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]> w= rote: >>>=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 d= ata 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 targe= t 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 t= he 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 X= ML 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 ObjRe= lationship programmatically. >>>=20 >>> I could put all eomodels that have cross eomodel relationships into the s= ame data map to avoid this problem. >>>=20 >>> But when I create it in Cayenne Modeler 4.3.3 it seems to work. I see th= e obj-relationship in the XML have target correctly set. >>>=20 >>> Thank you all in advance. >>> Ricardo Parada >=20