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