Hi Nikita, I stumbled upon a discussion thread in which you advertised a pull request to allow the use of metadataUtils via cgen to access comments. Can you tell me how to use it? Works with modeler as well?
Thank you in advance, Riccardo > On 11 Jan 2024, at 09:22, Riccardo De Menna <deme...@tuorlo.net> wrote: > > Hi all, > > After looking into the source code I think that the method that determines > if, at class generation time, a relationship is mandatory, is the following > from org.apache.cayenne.map.DbRelationship: > > @Override > public boolean isMandatory() { > for (DbJoin join : getJoins()) { > if (join.getSource().isMandatory()) { > return true; > } > } > return false; > } > > It seems to me that there are a lot of cases where such a method would give a > wrong result. Not only my one-to-one case but in general in any situation > where the left side of a join is a meaningful value there could be other > reasons for it being mandatory, and not just because we are trying to tell > the relationship is mandatory. Not only, the most obvious missfire is on the > toMany side of a one-to-many relationship where there would most likely be a > PK on the left side of the join that is mandatory by design. > > Wouldn’t it be more appropriate to have a flag in the modeler with which to > mark relationships as mandatory for these specific cases? > > Is there an easy workaround? > > Regards, > Riccardo > >> On 11 Jan 2024, at 00:02, Riccardo De Menna <deme...@tuorlo.net> wrote: >> >> Hi Michael, >> >> I’m aware of what ToDepPK does and the validation methods. I fact my problem >> is that I have a whole bunch of code that forwards validation from vaadin to >> cayenne back and forth and it depends on me telling it which attributes and >> relationship are mandatory. >> >> What I can’t seem to figure out is why this particular setup which is NOT a >> mandatory relationship returns true to isMandatory() at class generation. >> Because of this unexpected behaviour, my generated classes flag that >> relationship as mandatory and trigger validation exceptions when they >> shouldn’t. >> >> I was hoping that someone was familiar with the inner workings of the class >> generation templates and that I just have a typo somewhere. >> >> Regards, >> Riccardo >> >> >>> On 10 Jan 2024, at 15:46, Michael Gentry <blackn...@gmail.com> wrote: >>> >>> Hi Riccardo, >>> >>> There is also a validateForSave() that might be easier (handles inserts and >>> updates). >>> >>> mrg >>> >>> >>> On Wed, Jan 10, 2024 at 8:34 AM Michael Gentry <blackn...@gmail.com> wrote: >>> >>>> Hi Riccardo, >>>> >>>> The To Dep PK checkbox on the DbEntity isn't really intended to say "this >>>> relationship is required" (that is a by-product). It is designed to assign >>>> a PK from one entity to another. >>>> >>>> Perhaps use a Pre-Persist Callback (ObjEntity tab) to verify the shipment >>>> has a shipment number? >>>> >>>> >>>> https://cayenne.apache.org/docs/4.1/cayenne-guide/#types-of-lifecycle-events >>>> >>>> You could also use validateForInsert() I think, but you should also maybe >>>> do a validateForUpdate() if you go down that path. >>>> >>>> mrg >>>> >>>> >>>> On Wed, Jan 10, 2024 at 6:50 AM Riccardo De Menna <deme...@tuorlo.net> >>>> wrote: >>>> >>>>> Hi Michael, >>>>> >>>>>> Try deselecting the "To Dep PK" checkbox on the relationship >>>>>> in SHIPMENT_NUMBER -> SHIPMENT. >>>>> >>>>> I tryed both ToDep directions but they don’t seem to affect the result. >>>>>> >>>>>> I can see how having that checked would make the relationship required >>>>>> because it ties SHIPMENT_NUMBER's PK to SHIPMENT's PK, therefore a >>>>>> SHIPMENT_NUMBER shouldn't exist without a corresponding SHIPMENT and it >>>>>> sounds like you want it to be separate. >>>>> >>>>> But I do expect the reverse relationship to be required… As I undrestood >>>>> it, I would set ToDepPK on the SHIPMENT_NUMBER side and keep it off on the >>>>> SHIPMENT side. I want to be able to generate numbers before having to link >>>>> them to shipments but I also expect shipments non to exist without a >>>>> number. >>>>> >>>>> BTW, as I said to Nikita, if I forcefully ignore the flag and manually >>>>> bypass my validation code depending on it, the ObjectContext does not seem >>>>> to complain about it and does commit the save. >>>>> >>>>> I assume it’s just the flag being marked as mandatory for some other side >>>>> condition but I still don’t know what to use in the template as a reliable >>>>> replacement. >>>>> >>>>> Riccardo >>>>> >>>>>> >>>>>> mrg >>>>>> >>>>>> >>>>>> On Wed, Jan 10, 2024 at 12:10 AM Riccardo De Menna <deme...@tuorlo.net> >>>>>> wrote: >>>>>> >>>>>>> Hi Michael, >>>>>>> >>>>>>> Thank you for helping. Yes… you modeled exactly what I described down >>>>> to >>>>>>> the delete rules. I imported your files in modeler and run class >>>>> generation >>>>>>> but I still get the relationship (TO_SHIP in your model) to appear as >>>>>>> mandatory. Could it be an issue in class generation? >>>>>>> >>>>>>> This is a little VE snippet I use in my template to output a static >>>>> list >>>>>>> of mandatory relationships. >>>>>>> >>>>>>> #foreach( $rel in ${object.DeclaredRelationships} ) >>>>>>> #if (${rel.isMandatory()} && !${rel.ToMany} ) >>>>>>> #set($bar = >>>>>>> >>>>> $requiredRelationships.add("${stringUtils.capitalizedAsConstant($rel.Name)}_PROPERTY")) >>>>>>> #end >>>>>>> #end >>>>>>> public static final List<String> REQUIRED_RELATIONSHIPS = List.of( >>>>>>> #foreach( $rel in ${requiredRelationships} ) >>>>>>> ${rel}#if(!$foreach.last),#end >>>>>>> #end >>>>>>> ); >>>>>>> >>>>>>> And contrary to what I would expect, I get this in my superclass: >>>>>>> >>>>>>> public static final List<String> REQUIRED_RELATIONSHIPS = List.of( >>>>>>> TO_SHIP_PROPERTY >>>>>>> ); >>>>>>> >>>>>>> Riccardo De Menna >>>>>>> >>>>>>> >>>>>>>> On 10 Jan 2024, at 01:20, Michael Gentry <blackn...@gmail.com> wrote: >>>>>>>> >>>>>>>> Hi Riccardo, >>>>>>>> >>>>>>>> I may have completely misunderstood your intention, but here is my >>>>> first >>>>>>>> cut for a model: >>>>>>>> >>>>>>>> cayenne-o2o.xml: >>>>>>>> <?xml version="1.0" encoding="utf-8"?> >>>>>>>> <domain xmlns="http://cayenne.apache.org/schema/10/domain" >>>>>>>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >>>>>>>> xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain >>>>>>>> https://cayenne.apache.org/schema/10/domain.xsd" >>>>>>>> project-version="10"> >>>>>>>> <map name="datamap"/> >>>>>>>> </domain> >>>>>>>> >>>>>>>> datamap.map.xml: >>>>>>>> <?xml version="1.0" encoding="utf-8"?> >>>>>>>> <data-map xmlns="http://cayenne.apache.org/schema/10/modelMap" >>>>>>>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >>>>>>>> xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap >>>>>>>> https://cayenne.apache.org/schema/10/modelMap.xsd" >>>>>>>> project-version="10"> >>>>>>>> <property name="defaultLockType" value="1"/> >>>>>>>> <property name="defaultPackage" value="org.test"/> >>>>>>>> <db-entity name="SHIPMENT"> >>>>>>>> <db-attribute name="ID" type="BIGINT" isPrimaryKey="true" >>>>>>> isMandatory="true" >>>>>>>> /> >>>>>>>> </db-entity> >>>>>>>> <db-entity name="SHIPMENT_NUMBER"> >>>>>>>> <db-attribute name="ID" type="BIGINT" isPrimaryKey="true" >>>>>>> isMandatory="true" >>>>>>>>> >>>>>>>> <info:property xmlns:info="http://cayenne.apache.org/schema/10/info" >>>>>>> name= >>>>>>>> "comment" value="This ID is the same as SHIPMENT's ID."/> >>>>>>>> </db-attribute> >>>>>>>> <db-attribute name="NUM" type="INTEGER"> >>>>>>>> <info:property xmlns:info="http://cayenne.apache.org/schema/10/info" >>>>>>> name= >>>>>>>> "comment" value="This is the shipment number."/> >>>>>>>> </db-attribute> >>>>>>>> </db-entity> >>>>>>>> <obj-entity name="Shipment" className="org.test.Shipment" lock-type= >>>>>>>> "optimistic" dbEntityName="SHIPMENT"/> >>>>>>>> <obj-entity name="ShipmentNumber" className="org.test.ShipmentNumber" >>>>>>>> lock-type="optimistic" dbEntityName="SHIPMENT_NUMBER"> >>>>>>>> <obj-attribute name="num" type="java.lang.Integer" >>>>>>> db-attribute-path="NUM"/> >>>>>>>> </obj-entity> >>>>>>>> <db-relationship name="toShipNum" source="SHIPMENT" >>>>>>> target="SHIPMENT_NUMBER" >>>>>>>>> >>>>>>>> <db-attribute-pair source="ID" target="ID"/> >>>>>>>> </db-relationship> >>>>>>>> <db-relationship name="toShip" source="SHIPMENT_NUMBER" >>>>> target="SHIPMENT" >>>>>>>> toDependentPK="true"> >>>>>>>> <db-attribute-pair source="ID" target="ID"/> >>>>>>>> </db-relationship> >>>>>>>> <obj-relationship name="toShipNum" source="Shipment" >>>>>>> target="ShipmentNumber" >>>>>>>> deleteRule="Cascade" db-relationship-path="toShipNum"/> >>>>>>>> <obj-relationship name="toShip" source="ShipmentNumber" >>>>> target="Shipment" >>>>>>>> deleteRule="Deny" db-relationship-path="toShip"/> >>>>>>>> </data-map> >>>>>>>> >>>>>>>> Copy/Paste these files somewhere, then try loading them up into your >>>>> 4.2 >>>>>>>> Modeler and see if it is close. >>>>>>>> >>>>>>>> mrg >>>>>>>> >>>>>>>> >>>>>>>> On Tue, Jan 9, 2024 at 9:54 AM Riccardo De Menna <deme...@tuorlo.net> >>>>>>> wrote: >>>>>>>> >>>>>>>>> Hi, >>>>>>>>> >>>>>>>>> Can someone help me understand something? >>>>>>>>> >>>>>>>>> I’m trying to model a one-to-one relationship between two entities >>>>> but I >>>>>>>>> can’t seem to get the relationship to be optional. >>>>>>>>> >>>>>>>>> In my specific case I need to model an entity representing shipments >>>>>>> with >>>>>>>>> a postal service. Each shipment needs to have a number taken from a >>>>>>>>> range/group that is pre-assigned by the postal service. >>>>>>>>> >>>>>>>>> Thus I created a SHIPMENT_NUMBER entity with just an INTEGER >>>>> attribute >>>>>>> and >>>>>>>>> then used that attribute to build the relationship with the SHIPMENT >>>>>>>>> entity. Possibly with “To dep PK” as well. >>>>>>>>> >>>>>>>>> I want the relationship to be optional so that I can generate >>>>>>>>> SHIPMENT_NUMBER as many as I want and populate them with the numbers >>>>>>>>> assigned by the postal service and only later, when the real >>>>> SHIPMENT is >>>>>>>>> actually needed/created, link it with the number in a one-to-one >>>>>>> fashion. >>>>>>>>> >>>>>>>>> I’m not sure why, but my class generated content always shows the >>>>>>>>> relationship as mandatory. >>>>>>>>> >>>>>>>>> Coming from the WebObjects world, I'm used to a modeler that >>>>> explicitly >>>>>>>>> shows checkboxes for isMandatory on relationships like with the >>>>>>> attributes. >>>>>>>>> Here in Cayenne it seems that optionality is implicitly determined >>>>>>> based on >>>>>>>>> the design. >>>>>>>>> >>>>>>>>> Have I misunderstood something? Is my design flawed? >>>>>>>>> >>>>>>>>> Any tip is appreciated. >>>>>>>>> >>>>>>>>> Regards, >>>>>>>>> Riccardo >>>>>>> >>>>>>> >>>>> >>>>> >> >