I'm not fond of introducing a dependency on ToManyList since this
class could change in the future. I suppose you could get around that
with some kind of ToManyListFactory.
You're still going to have the issue that you can't call
addTo/removeFrom while the object is unregistered since any objects
added won't be properly registered when the object finally is
registered, so I still think you're better off using "return (null ==
value) ? Collections.EmptyList : value" in your getList method
instead.
-Mike
On 9/8/05, Gili <cowwo..bs.darktech.org> wrote:
>
> You are quite right. Mike and I discussed this on IRC. The new patch
> initializes ToManyList references instead. As far as I can tell, this
> will fix the problems you mention. Are there other problems that we need
> to be aware of? Any idea on how to improve this patch further?
>
> Gili
>
> Andrus Adamchik wrote:
> > There *is* a difference in registered and unregistered DataObject
> > behavior, period. This patch doesn't change that, it doesn't solve
> > anything, and instead introduces an inconsistency by adding an
> > immutable collection of the wrong type to the mix. Won't help you if
> > you call "addToXyz" down the line and get an
> > UnsupportedOperationException.
> >
> > -1 for the patch.
> >
> > Andrus
> >
> >
> >
> > On Sep 8, 2005, at 1:28 PM, Gili wrote:
> >
> >>
> >> I've attached a patch which fixes this, in case anyone is
> >> interested. Because we do this initialization in the template I think
> >> there will be extremely little overhead (since we know ahead of time
> >> which relationships are toMany). What do the rest of you think?
> >>
> >> Gili
> >>
> >> Mike Kienenberger wrote:
> >>
> >>> Moving this to dev.
> >>> Actually, I wonder if the behavior is consistent even between NEW and
> >>> other objects in other states.
> >>> I'm thinking a toMany relationship will always return null if the
> >>> relationship hasn't been initialized, regardless of whether the DO is
> >>> registered or not.
> >>> So null really means that the object's toMany relationship hasn't been
> >>> initialized, and maybe that's a bad way to handle it since the methods
> >>> are "add/remove/get" rather than "set/get"
> >>> On 9/8/05, Mike Kienenberger <mkienen..mail.com> wrote:
> >>>
> >>>> I'd be "-0" on a patch for this.
> >>>>
> >>>> It'd add overhead because each DataObject would have to iterate over
> >>>> the ObjEntity's attributes to determine if the value should be set to
> >>>> EMPTY_LIST.
> >>>>
> >>>> Since I almost never work with DOs outside of a DataContext, I have no
> >>>> issues with the DO returning null in those cases, and I consider it
> >>>> useful to throw an error if I try to read a toMany relationship from
> >>>> an unregistered object.
> >>>>
> >>>> On the other hand, if people who actually perform a lot of work on
> >>>> unregistered objects think this makes sense, I have no compelling
> >>>> reasons against it, either. I can understand the claim that the
> >>>> behavior isn't consistent between registered and unregistered objects.
> >>>>
> >>>> On 9/8/05, Gili <cowwo..bs.darktech.org> wrote:
> >>>>
> >>>>
> >>>>> That is possible. As far as I can tell, referencing
> >>>>> Collections.EMPTY_LIST consumes as much resources as pointing to
> >>>>> null.
> >>>>> Is there any reason we don't initialize delegates' lists to
> >>>>> Collections.EMPTY_LIST? I could contribute a patch if necessary, but
> >>>>> does this sound reasonable to everyone?
> >>>>>
> >>>>> Gili
> >>>>>
> >>>>> Eric Schneider wrote:
> >>>>>
> >>>>>
> >>>>>> Gili,
> >>>>>>
> >>>>>> Sounds like the object was never registered, or somehow it's
> >>>>>> persistence state is transient. Normally, toMany relationships
> >>>>>> will
> >>>>>> always return an empty List if there are no related objects.
> >>>>>>
> >>>>>> Eric
> >>>>>>
> >>>>>> On Sep 7, 2005, at 4:02 PM, Gili wrote:
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>> I'm expecting a toMany relationship to return an empty list if
> >>>>>>> empty and it seems to return null. Is this by design (I can't
> >>>>>>> seem to
> >>>>>>> find it documented anywhere). Does this mean I have to check
> >>>>>>> for both
> >>>>>>> null or an empty list everywhere in my code or is there an
> >>>>>>> easier way?
> >>>>>>>
> >>>>>>> Thanks,
> >>>>>>> Gili
> >>>>>>> --
> >>>>>>> http://www.desktopbeautifier.com/
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>> --
> >>>>> http://www.desktopbeautifier.com/
> >>>>>
> >>>>>
> >>>>
> >>>>
> >>
> >> --
> >> http://www.desktopbeautifier.com/
> >> Index: cayenne/src/cayenne/resources/dotemplates/superclass.vm
> >> ===================================================================
> >> RCS file: /cvsroot/cayenne/cayenne/src/cayenne/resources/
> >> dotemplates/superclass.vm,v
> >> retrieving revision 1.10
> >> diff -u -r1.10 superclass.vm
> >> --- cayenne/src/cayenne/resources/dotemplates/superclass.vm 20 Nov
> >> 2004 19:51:09 -0000 1.10
> >> +++ cayenne/src/cayenne/resources/dotemplates/superclass.vm 8 Sep
> >> 2005 17:15:45 -0000
> >>.. -3,6 +3,7 @@
> >>
> >> #end
> >> #if( ${classGen.isContainingListProperties()} )
> >> +import java.util.Collections;
> >> import java.util.List;
> >>
> >> #end
> >>.. -13,6 +14,15 @@
> >> */
> >> public class ${classGen.superPrefix}${classGen.className} extends
> >> $classGen.superClassName {
> >>
> >> +## Create constructor
> >> + public ${classGen.superPrefix}${classGen.className}() {
> >> +#foreach( $rel in ${classGen.Entity.DeclaredRelationships} )
> >> +#if( $rel.ToMany )
> >> + writeProperty("${rel.Name}", Collections.EMPTY_LIST);
> >> +#end
> >> +#end
> >> + }
> >> +
> >> ## Create property names
> >> #foreach( $attr in ${classGen.Entity.DeclaredAttributes} )
> >> #set( $classGen.Prop = $attr.Name )## let controller know about
> >> current property
> >>
> >
> >
>
> --
> http://www.desktopbeautifier.com/
>
>
> #if( ${classGen.isUsingPackage()} )
> package ${classGen.packageName};
>
> #end
> #if( ${classGen.isContainingListProperties()} )
> import java.util.List;
> import org.objectstyle.cayenne.access.ToManyList;
>
> #end
> /** Class ${classGen.superPrefix}${classGen.className} was generated by Cayenne.
> * It is probably a good idea to avoid changing this class manually,
> * since it may be overwritten next time code is regenerated.
> * If you need to make any customizations, please use subclass.
> */
> public class ${classGen.superPrefix}${classGen.className} extends $classGen.superClassName {
>
> ## Create constructor
> public ${classGen.superPrefix}${classGen.className}() {
> #foreach( $rel in ${classGen.Entity.DeclaredRelationships} )
> #if( $rel.ToMany )
> #set( $classGen.Prop = $rel.Name )## let controller know about current property
> writeProperty("${rel.Name}", new ToManyList(this, ${classGen.propAsConstantName}_PROPERTY));
> #end
> #end
> }
>
> ## Create property names
> #foreach( $attr in ${classGen.Entity.DeclaredAttributes} )
> #set( $classGen.Prop = $attr.Name )## let controller know about current property
> public static final String ${classGen.propAsConstantName}_PROPERTY = "${attr.Name}";
> #end
> #foreach( $rel in ${classGen.Entity.DeclaredRelationships} )
> #set( $classGen.Prop = $rel.Name )## let controller know about current property
> public static final String ${classGen.propAsConstantName}_PROPERTY = "${rel.Name}";
> #end
>
> #if( $classGen.Entity.DbEntity )
> #foreach( $idAttr in ${classGen.Entity.DbEntity.PrimaryKey} )
> #set( $classGen.Prop = $idAttr.Name )## let controller know about current property
> public static final String ${classGen.propAsConstantName}_PK_COLUMN = "${idAttr.Name}";
> #end
> #end
>
> ## Create attribute set/get methods
> #foreach( $attr in ${classGen.Entity.DeclaredAttributes} )
> #set( $classGen.Prop = $attr.Name )## let controller know about current property
> #if ("true" != "${classGen.getEntity().isReadOnly()}")
> public void set${classGen.cappedProp}($classGen.formatJavaType(${attr.Type}) $classGen.formatVariableName(${attr.Name})) {
> writeProperty("${attr.Name}", $classGen.formatVariableName(${attr.Name}));
> }
> #end
> public $classGen.formatJavaType(${attr.Type}) get${classGen.cappedProp}() {
> return ($classGen.formatJavaType(${attr.Type}))readProperty("${attr.Name}");
> }
>
>
> #end
> ##
> ## Create list add/remove/get methods
> #foreach( $rel in ${classGen.Entity.DeclaredRelationships} )
> #set( $classGen.Prop = $rel.Name )## let controller know about current property
> #if( $rel.ToMany )
> #if ( ! $rel.ReadOnly )
> public void addTo${classGen.cappedProp}($classGen.formatJavaType(${rel.TargetEntity.ClassName}) obj) {
> addToManyTarget("${rel.name}", obj, true);
> }
> public void removeFrom${classGen.cappedProp}($classGen.formatJavaType(${rel.TargetEntity.ClassName}) obj) {
> removeToManyTarget("${rel.name}", obj, true);
> }
> #end
> public List get${classGen.cappedProp}() {
> return (List)readProperty("${rel.name}");
> }
> #else
> #if ( !${classGen.getEntity().isReadOnly()} && !$rel.ReadOnly )
> public void set${classGen.cappedProp}($classGen.formatJavaType(${rel.TargetEntity.ClassName}) $classGen.formatVariableName(${rel.name})) {
> setToOneTarget("${rel.name}", $classGen.formatVariableName(${rel.name}), true);
> }
> #end
>
> public $classGen.formatJavaType(${rel.TargetEntity.ClassName}) get${classGen.cappedProp}() {
> return ($classGen.formatJavaType(${rel.TargetEntity.ClassName}))readProperty("${rel.name}");
> }
> #end
>
>
> #end
> }
>
>
>
This archive was generated by hypermail 2.0.0 : Thu Sep 08 2005 - 14:35:20 EDT