Re: Question about optionality in one-to-one relationships
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 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 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 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 >>> 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 > 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 REQUIRED_RELATIONSHIPS = List.of( >> #foreac
Re: Question about optionality in one-to-one relationships
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 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 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 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 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 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 >> 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? >>> >>>
Re: Question about optionality in one-to-one relationships
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 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 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 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 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 > 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 > > 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
Re: Question about optionality in one-to-one relationships
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 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 > 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 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 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 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 >> 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 >> >> 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