Re: toMany relationship returning null

From: Andrus Adamchik (andru..bjectstyle.org)
Date: Thu Sep 08 2005 - 14:29:47 EDT

  • Next message: Gili: "Re: toMany relationship returning null"

    Gili, you are trying to solve the problems that are not there. You
    are welcome to use this as your own custom template, but you'll be
    better off by just registering your objects.

    A.

    On Sep 8, 2005, at 2:25 PM, Gili 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:29:51 EDT