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&apos;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

Reply via email to