Hi Nikita, Thank you very much for the pointers. I will amend my templates to emulate cayenne and use the metadata comments for any custom behaviour. Thank you for that pull request.
Best regards, Riccardo > On 11 Jan 2024, at 17:36, Nikita Timofeev <ntimof...@objectstyle.com> wrote: > > Hi Riccardo, > > I don't quite remember my advice there. In Modeler this metadata goes just > as a comment to entity/attribute/relationship. So you could set > something in the comment and get access to this information via > metadataUtils in the template (via > `metadataUtils.getComment(relationship)`). > > Also I checked Cayenne logic and it turns out that Cayenne itself doesn't > use this `isMandatory()` method in ObjRelationship. It uses logic here [1], > in short it checks the combination of > `isSourceIndependentFromTargetChange()` flags and `isMandatory()` on > underlying db relationships. You could probably use something similar to it > in your template, though it could be a bit challenging to reproduce in full. > > [1] > https://github.com/apache/cayenne/blob/master/cayenne/src/main/java/org/apache/cayenne/BaseDataObject.java#L565-L591 > > > On Thu, Jan 11, 2024 at 4:17 PM Riccardo De Menna <deme...@tuorlo.net> > wrote: > >> 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 >>>>>>>>> >>>>>>>>> >>>>>>> >>>>>>> >>>> >>> >> >> > > -- > Best regards, > Nikita Timofeev