Re: Cross data map relationships
Andrus Adamchik <[email protected]> Tue, 14 Oct 2025 17:33:28 -0400
| Newsgroups | gmane.comp.java.cayenne.user |
|---|---|
| Message-ID | <[email protected]> |
> I then save the first data map and it throws a NullPointerException. =20= Before save, try this to make sure entities can find each other across = DataMaps: EntityResolver namespace =3D 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=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