You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by Kevin Menard <km...@servprise.com> on 2008/03/04 18:24:39 UTC

Bug in child contexts?

Hi,

This seems like such a basic question that I probably shouldn¹t have to ask,
but I want to verify intended behavior versus a bug.  Since Cayenne doesn¹t
allow one to associate two data objects from distinct contexts, we use local
object.

So, I have something similar to the following:

ObjectContext customerContext;
Customer customer = customerContext.newObject(Customer.class);

ObjectContext childContext = customerContext.createChildDataContext();
BillingInfo bi = childContext.newObject(BillingInfo.class);

The bi instance is created in its own context so that if the user doesn¹t
commit the page, I can toss the data without affecting the customer context.
If the user does save the form, then I want to do something like
bi.setCustomer(customer);  However, they¹re in different contexts, so that
doesn¹t work.  Additionally, bi has relationships to other entities in
childContext.  So, in this case, I use localObject to pull customer into
childContext, set the relationship, commit, and go on my merry way.

The problem is that calling customer.getBillingInfo() now returns billing
info associated with the child context.  I thought that they would be HOLLOW
objects resolved with the customer¹s context, but it appears due to caching
I now have a situation that Cayenne normally won¹t allow: two related
objects in different contexts.

Is this the way it¹s supposed to work for child contexts or have I run into
a bug?  Either way, I¹ll need to fix it.  I just need to know which codebase
to work with.

Thanks,
Kevin

Re: Bug in child contexts?

Posted by Michael Gentry <bl...@gmail.com>.
What you describe is not functioning the way I would've expected (or
at least hoped).  I did some testing on nested ECs before and ran into
a few glitches, but never completely isolated the reason why.

/dev/mrg

On Tue, Mar 4, 2008 at 12:24 PM, Kevin Menard <km...@servprise.com> wrote:
> Hi,
>
>  This seems like such a basic question that I probably shouldn¹t have to ask,
>  but I want to verify intended behavior versus a bug.  Since Cayenne doesn¹t
>  allow one to associate two data objects from distinct contexts, we use local
>  object.
>
>  So, I have something similar to the following:
>
>  ObjectContext customerContext;
>  Customer customer = customerContext.newObject(Customer.class);
>
>  ObjectContext childContext = customerContext.createChildDataContext();
>  BillingInfo bi = childContext.newObject(BillingInfo.class);
>
>  The bi instance is created in its own context so that if the user doesn¹t
>  commit the page, I can toss the data without affecting the customer context.
>  If the user does save the form, then I want to do something like
>  bi.setCustomer(customer);  However, they¹re in different contexts, so that
>  doesn¹t work.  Additionally, bi has relationships to other entities in
>  childContext.  So, in this case, I use localObject to pull customer into
>  childContext, set the relationship, commit, and go on my merry way.
>
>  The problem is that calling customer.getBillingInfo() now returns billing
>  info associated with the child context.  I thought that they would be HOLLOW
>  objects resolved with the customer¹s context, but it appears due to caching
>  I now have a situation that Cayenne normally won¹t allow: two related
>  objects in different contexts.
>
>  Is this the way it¹s supposed to work for child contexts or have I run into
>  a bug?  Either way, I¹ll need to fix it.  I just need to know which codebase
>  to work with.
>
>  Thanks,
>  Kevin
>

Re: Bug in child contexts?

Posted by Kevin Menard <km...@servprise.com>.
Ahh.  Turns out it was a problem in my code.  Sorry for the false alarms.

I had extended CayenneDataObject's addToManyTarget because I wanted to
suppress duplicates from appearing in the list.  Something there is failing
to work properly.  I'll have to sort all that out.

Thanks again,
Kevin 


On 3/4/08 10:16 PM, "Kevin Menard" <km...@servprise.com> wrote:

> I just wrote a small test case here using Artist and Painting and it works
> as you describe and as I would expect.  So, either there's a funky cache
> thing going on or my code is borked.  I'm not entirely ruling out the
> latter, but it is fairly simplistic in nature.


Re: Bug in child contexts?

Posted by Kevin Menard <km...@servprise.com>.
I just wrote a small test case here using Artist and Painting and it works
as you describe and as I would expect.  So, either there's a funky cache
thing going on or my code is borked.  I'm not entirely ruling out the
latter, but it is fairly simplistic in nature.

-- 
Kevin


On 3/4/08 12:59 PM, "Andrus Adamchik" <an...@objectstyle.org> wrote:

> 
> On Mar 4, 2008, at 7:24 PM, Kevin Menard wrote:
> 
>> So, in this case, I use localObject to pull customer into
>> childContext, set the relationship, commit, and go on my merry way.
> 
> This is the correct way and AFAIK it should work. Could you post a bit
> longer code example, that shows localObject call as well as the
> problem? Just to doublecheck that you are not swapping a customer
> reference somewhere, before we start digging the DataContext code.
> 
> Andrus
> 


Re: Bug in child contexts?

Posted by Kevin Menard <km...@servprise.com>.
On 3/4/08 12:59 PM, "Andrus Adamchik" <an...@objectstyle.org> wrote:

> 
> On Mar 4, 2008, at 7:24 PM, Kevin Menard wrote:
> 
>> So, in this case, I use localObject to pull customer into
>> childContext, set the relationship, commit, and go on my merry way.
> 
> This is the correct way and AFAIK it should work. Could you post a bit
> longer code example, that shows localObject call as well as the
> problem? Just to doublecheck that you are not swapping a customer
> reference somewhere, before we start digging the DataContext code.

Sure. This code is from a T4 webapp.  There are two page classes at play
here.  One is a base class using template methods to consolidate logic for
two semi-related pages.  I've removed the portions that clearly are not
relevant:

public abstract class AccountCreationPage extends ApplicationPage
{
    @Persist
    public abstract Addressable getAddressable();
    public abstract void setAddressable(final Addressable a);


    @Override
    public void pageBeginRender(final PageEvent event)
    {
        // If the address hasn't been set for this instance already, then
set it
        // to the customer's first shipping info address.
        if (null == getAddressable())
        {
            final ObjectContext objectContext =
getVisit().getCustomerDataContext().createChildDataContext();

            final Addressable addressable = (Addressable)
objectContext.newObject(getAddressableClass());
            final Address address =
addressable.getObjectContext().newObject(Address.class);

            addressable.setAddress(address);

            setAddressable(addressable);
        }
    }

    public void add(final IRequestCycle cycle)
    {
        // Grab the billing/shipping info and put the customer into the same
context to
        // make relationship operations easier.
        final Addressable a = getAddressable();
        final Customer c = (Customer)
a.getObjectContext().localObject(getVisit().getCustomer().getObjectId(),
null);

        // Associate the billing/shipping info with the customer.
        addToCustomer(c, a);

        // Commit the changes to the DB.
        c.getObjectContext().commitChanges();
    }
}


public abstract class AddShippingInfo extends AccountCreationPage
{
    @Override
    protected void addToCustomer(final Customer c, final Addressable a)
    {
        c.addToShippingInfo((ShippingInfo) a);
        c.setDefaultShippingInfo((ShippingInfo) a);
    }
}


In the debugger, right after the commit of c, I can see both the local
customer and the session-persisted one (stored in the Visit).  These two
customers have different contexts.  The session one has
"customerDataContext" and the local one has "childContext."  Calling
getShippingInfo() on either returns ShippingInfo instances registered with
"childContext."  It should be noted that the initial state is no shipping
info persisted or otherwise associated with the customer.  So, all shipping
info are in the same context, but they're not necessarily the same as the
customer.

(Apologies for switching from billing to shipping info.  They're of the same
structure and I just realized I changed on you.)

Thanks,
Kevin


Re: Bug in child contexts?

Posted by Andrus Adamchik <an...@objectstyle.org>.
On Mar 4, 2008, at 7:24 PM, Kevin Menard wrote:

> So, in this case, I use localObject to pull customer into
> childContext, set the relationship, commit, and go on my merry way.

This is the correct way and AFAIK it should work. Could you post a bit  
longer code example, that shows localObject call as well as the  
problem? Just to doublecheck that you are not swapping a customer  
reference somewhere, before we start digging the DataContext code.

Andrus