You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by Reinout van Schouwen <re...@gmail.com> on 2009/07/22 12:34:09 UTC

Different DataContext

Hi all,

I hope someone can help me with the following issue. I'm using Cayenne
with Databinder and Wicket for my application. In my model, multiple
'PersName' objects can be associated to one 'Person'. But whenever I
try to associate a newly created PersName with a Person, I get a
CayenneRuntimeException:

org.apache.cayenne.CayenneRuntimeException: [v.2.0.4 October 12 2007]
Cannot set object as destination of relationship person because it is
in a different DataContext
     at org.apache.cayenne.CayenneDataObject.willConnect(CayenneDataObject.java:340)
     at org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneDataObject.java:290)
     at nl.huygensinstituut.bia.domain.auto._PersName.setPerson(_PersName.java:69)
     at nl.huygensinstituut.bia.PersonInfoPanel$2.onSubmit(PersonInfoPanel.java:102)
     at org.apache.wicket.markup.html.form.Form.delegateSubmit(Form.java:1351)
     at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:810)
     at java.lang.reflect.Method.invoke(Method.java:616)
     at org.apache.wicket.RequestListenerInterface.invoke(RequestListenerInterface.java:183)
     at org.apache.wicket.request.target.component.listener.ListenerInterfaceRequestTarget.processEvents(ListenerInterfaceRequestTarget.java:73)
     at org.apache.wicket.request.AbstractRequestCycleProcessor.processEvents(AbstractRequestCycleProcessor.java:91)
     at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1220)
     at org.apache.wicket.RequestCycle.step(RequestCycle.java:1297)
     at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1399)
     at org.apache.wicket.RequestCycle.request(RequestCycle.java:529)
     at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:356)
     at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:201)
(jetty frames snipped)

Here's a snippet of the failing code:

    DataContext mycontext = Databinder.getContext();
    person = ObjectFactory.getInstance().getPerson(parameters.getInt("personid"),
mycontext);
// ObjectFactory is a singleton. getPerson method executes
DataObjectUtils.objectForPK(context, Person.class, id);

    final PersName nameObj = (PersName) persNameForm.getModelObject();
// PersName extends CayenneDataObject
    persNameForm.add(new Button("submitpersname", new ResourceModel("Save")) {
      @Override
      public void onSubmit() {

        if (nameObj.getPerson() == null && person == null) {
          final Person auxiliary = ObjectFactory.getInstance().createPerson();
          auxiliary.setSex(Person.SEX_UNKNOWN);
          nameObj.setPerson(auxiliary);
        } else {
          nameObj.setPerson(person); // <-- line 102 where the
exception is triggered. 'person'
        }
        super.onSubmit();
      }
    });

Thanks for any advice!

-- 
Reinout van Schouwen
http://vanschouwen.info/

Re: Different DataContext

Posted by Reinout van Schouwen <re...@gmail.com>.
John,

2009/7/22 John Armstrong <si...@gmail.com>:
> Rather then pull the context from the object I always pull from the
> thread I am executing within:
(...)
> Using the ThreadObjectContext() solved all of my context disconnects.

Thanks for the advice, but I believe I shouldn't circumvent Databinder
(the thin layer between Wicket and Cayenne) unless absolutely
necessary.
Perhaps the problem lies with Databinder-- I've posted a question on
their forum[1] but received no reply as of yet.

[1] http://databinder.net/forum/viewtopic.php?f=1&t=369

-- 
Reinout van Schouwen
http://vanschouwen.info/

Re: Different DataContext

Posted by John Armstrong <si...@gmail.com>.
Rather then pull the context from the object I always pull from the
thread I am executing within:

	public static ObjectContext getCayenneContext() {
		try {
			ObjectContext context = DataContext.getThreadObjectContext();
			return context;
		} catch (IllegalStateException ex) {
			ObjectContext context = DataContext.createDataContext();
			DataContext.bindThreadObjectContext(context);
			return context;
		}
	}

This gives me reliable access to a common context for all requests
within a thread(request). Its fairly easy to create objects ad hoc and
then attach them to the session when your ready to commit. You can
also easily detach the object and reattach it when your ready to
commit it (and do comparisons etc).

Using the ThreadObjectContext() solved all of my context disconnects.

John-

On Wed, Jul 22, 2009 at 7:18 AM, Mike Kienenberger<mk...@gmail.com> wrote:
> To assign relationships between objects, they have to be in the same
> context.  As Emanuele stated, it's hard to say what the best practice
> for wicket is since we haven't used it.
>
> In my web applications, I have typically either used a new DataContext
> per request, or reused the same DataContext for the lifetime of the
> session.   It will depend on your needs.   Sometimes I have created a
> "read-only" shared DataContext to store data that never or rarely
> changes, and then used localObject to copy a reference of that static
> data into my non-read-only DataContext.
>
>
> On Wed, Jul 22, 2009 at 9:47 AM, Reinout van Schouwen<re...@gmail.com> wrote:
>> Hi,
>>
>> 2009/7/22 Mike Kienenberger <mk...@gmail.com>:
>>> If you know that Person is not in a modified state, you can make a
>>> local copy of Person in your nameObj's data context.
>>
>> Thanks, Mike and Emanuele, getting the object context from the nameObj
>> indeed solves the problem.
>>
>> Is this something to be aware of at all times? I.e. when creating a
>> link between two objects, is it best practice to retrieve the
>> datacontext from either one, and handle both objects from that
>> context?
>>
>> --
>> Reinout van Schouwen
>> http://vanschouwen.info/
>>
>

Re: Different DataContext

Posted by Mike Kienenberger <mk...@gmail.com>.
To assign relationships between objects, they have to be in the same
context.  As Emanuele stated, it's hard to say what the best practice
for wicket is since we haven't used it.

In my web applications, I have typically either used a new DataContext
per request, or reused the same DataContext for the lifetime of the
session.   It will depend on your needs.   Sometimes I have created a
"read-only" shared DataContext to store data that never or rarely
changes, and then used localObject to copy a reference of that static
data into my non-read-only DataContext.


On Wed, Jul 22, 2009 at 9:47 AM, Reinout van Schouwen<re...@gmail.com> wrote:
> Hi,
>
> 2009/7/22 Mike Kienenberger <mk...@gmail.com>:
>> If you know that Person is not in a modified state, you can make a
>> local copy of Person in your nameObj's data context.
>
> Thanks, Mike and Emanuele, getting the object context from the nameObj
> indeed solves the problem.
>
> Is this something to be aware of at all times? I.e. when creating a
> link between two objects, is it best practice to retrieve the
> datacontext from either one, and handle both objects from that
> context?
>
> --
> Reinout van Schouwen
> http://vanschouwen.info/
>

Re: Different DataContext

Posted by Emanuele Maiarelli <ev...@yahoo.it>.
and i will look into localObjects solution, this might lead to less concurrency problems...





________________________________
Da: Emanuele Maiarelli <ev...@yahoo.it>
A: user@cayenne.apache.org; reinout@gmail.com
Inviato: Mercoledì 22 luglio 2009, 15:56:59
Oggetto: Re: Different DataContext

You welcome Reinout,

    I'm not familiar with Apache Wicket, and honeslty i'd like frameworks will handle all ThreadLocal/contexts issues... 
and in the case of Wicket im not sure if there's a better way than the one i suggested







________________________________
Da: Reinout van Schouwen <re...@gmail.com>
A: user@cayenne.apache.org
Inviato: Mercoledì 22 luglio 2009, 15:47:01
Oggetto: Re: Different DataContext

Hi,

2009/7/22 Mike Kienenberger <mk...@gmail.com>:
> If you know that Person is not in a modified state, you can make a
> local copy of Person in your nameObj's data context.

Thanks, Mike and Emanuele, getting the object context from the nameObj
indeed solves the problem.

Is this something to be aware of at all times? I.e. when creating a
link between two objects, is it best practice to retrieve the
datacontext from either one, and handle both objects from that
context?

-- 
Reinout van Schouwen
http://vanschouwen.info/


      

Re: Different DataContext

Posted by Emanuele Maiarelli <ev...@yahoo.it>.
You welcome Reinout,

    I'm not familiar with Apache Wicket, and honeslty i'd like frameworks will handle all ThreadLocal/contexts issues... 
and in the case of Wicket im not sure if there's a better way than the one i suggested







________________________________
Da: Reinout van Schouwen <re...@gmail.com>
A: user@cayenne.apache.org
Inviato: Mercoledì 22 luglio 2009, 15:47:01
Oggetto: Re: Different DataContext

Hi,

2009/7/22 Mike Kienenberger <mk...@gmail.com>:
> If you know that Person is not in a modified state, you can make a
> local copy of Person in your nameObj's data context.

Thanks, Mike and Emanuele, getting the object context from the nameObj
indeed solves the problem.

Is this something to be aware of at all times? I.e. when creating a
link between two objects, is it best practice to retrieve the
datacontext from either one, and handle both objects from that
context?

-- 
Reinout van Schouwen
http://vanschouwen.info/



      

Re: Different DataContext

Posted by Reinout van Schouwen <re...@gmail.com>.
Hi,

2009/7/22 Mike Kienenberger <mk...@gmail.com>:
> If you know that Person is not in a modified state, you can make a
> local copy of Person in your nameObj's data context.

Thanks, Mike and Emanuele, getting the object context from the nameObj
indeed solves the problem.

Is this something to be aware of at all times? I.e. when creating a
link between two objects, is it best practice to retrieve the
datacontext from either one, and handle both objects from that
context?

-- 
Reinout van Schouwen
http://vanschouwen.info/

Re: Different DataContext

Posted by Mike Kienenberger <mk...@gmail.com>.
If you know that Person is not in a modified state, you can make a
local copy of Person in your nameObj's data context.   (If person is
modified, then you will lose those changes in the nameObj dataContext,
which still may not be a problem unless person is in a NEW state)  I
don't remember if there's a convenience method for it in 2.0, but for
1.1 the code was:

       localPerson = getLocalObject(nameObj.getDataContext(), person);

	public static DataObject getLocalObject(DataContext context, DataObject obj)
	{
		if (null == obj)  return null;
		
		if (obj.getDataContext() != context)
		{
			List localObjectList = context.localObjects(Arrays.asList(new
Object[] { obj } ));
			return (DataObject)localObjectList.get(0);
		}
		return obj;
	}


http://cayenne.apache.org/doc20/api/cayenne/org/apache/cayenne/access/DataContext.html#localObjects(java.util.List)

http://cayenne.apache.org/doc20/api/cayenne/org/apache/cayenne/access/DataContext.html#localObject(org.apache.cayenne.ObjectId,%20org.apache.cayenne.Persistent)

Glancing through the 2.0 api docs, it looks like you can use the above
localObject() and create modified and new state objects as well.
However, I don't recommend doing so because having the object marked
as modified or new in two separate contexts is going to cause problems
when you commit the second context.  As long as you know that person
is not a new object, localObjects() is still your best bet -- or
localObject() with a null prototype.



On Wed, Jul 22, 2009 at 7:42 AM, Emanuele Maiarelli<ev...@yahoo.it> wrote:
> I think the problem is there:
>
>    DataContext mycontext = Databinder.getContext();
>    person = ObjectFactory.getInstance().getPerson(parameters.getInt("personid"),
> mycontext);
>
> 'mycontext' isn't the same context of the one ObjectFactory is using , u should share the same context between
> Wicket and your Singleton.
>
> I hope this will solve,
>
>
>
>
>
>
>
>
> ________________________________
> Da: Reinout van Schouwen <re...@gmail.com>
> A: user@cayenne.apache.org
> Inviato: Mercoledì 22 luglio 2009, 13:32:29
> Oggetto: Re: Different DataContext
>
> Hello Emanuele,
>
> Thanks for your reply.
>
> 2009/7/22 Emanuele Maiarelli <ev...@yahoo.it>:
>
>>  i'm not an apache Wicket expert, but the Exception its obiusvly casted by
>> the fact that ur application is casting objects into different DataContexts.
>
> Yes, but I have no idea how that could happen.
>
>>  What happen if u steps into
> (...)
>
> This part of the code works fine. It's the 'else' case that causes the
> exception.
>
> Regards,
>
> --
> Reinout van Schouwen
> http://vanschouwen.info/
>
>
>
>

Re: Different DataContext

Posted by Emanuele Maiarelli <ev...@yahoo.it>.
I think the problem is there:

    DataContext mycontext = Databinder.getContext();
    person = ObjectFactory.getInstance().getPerson(parameters.getInt("personid"),
mycontext);

'mycontext' isn't the same context of the one ObjectFactory is using , u should share the same context between 
Wicket and your Singleton.

I hope this will solve,








________________________________
Da: Reinout van Schouwen <re...@gmail.com>
A: user@cayenne.apache.org
Inviato: Mercoledì 22 luglio 2009, 13:32:29
Oggetto: Re: Different DataContext

Hello Emanuele,

Thanks for your reply.

2009/7/22 Emanuele Maiarelli <ev...@yahoo.it>:

>  i'm not an apache Wicket expert, but the Exception its obiusvly casted by
> the fact that ur application is casting objects into different DataContexts.

Yes, but I have no idea how that could happen.

>  What happen if u steps into
(...)

This part of the code works fine. It's the 'else' case that causes the
exception.

Regards,

-- 
Reinout van Schouwen
http://vanschouwen.info/



      

Re: Different DataContext

Posted by Reinout van Schouwen <re...@gmail.com>.
Hello Emanuele,

Thanks for your reply.

2009/7/22 Emanuele Maiarelli <ev...@yahoo.it>:

>  i'm not an apache Wicket expert, but the Exception its obiusvly casted by
> the fact that ur application is casting objects into different DataContexts.

Yes, but I have no idea how that could happen.

>  What happen if u steps into
(...)

This part of the code works fine. It's the 'else' case that causes the
exception.

Regards,

-- 
Reinout van Schouwen
http://vanschouwen.info/

Re: Different DataContext

Posted by Emanuele Maiarelli <ev...@yahoo.it>.
Hi Reinout,

 i'm not an apache Wicket expert, but the Exception its obiusvly casted by the fact that ur application is casting objects into different DataContexts.
 
 What happen if u steps into
          final Person auxiliary = ObjectFactory.getInstance().createPerson();
          auxiliary.setSex(Person.SEX_UNKNOWN);
          nameObj.setPerson(auxiliary);
?
 
 




________________________________
Da: Reinout van Schouwen <re...@gmail.com>
A: user@cayenne.apache.org
Inviato: Mercoledì 22 luglio 2009, 12:34:09
Oggetto: Different DataContext

Hi all,

I hope someone can help me with the following issue. I'm using Cayenne
with Databinder and Wicket for my application. In my model, multiple
'PersName' objects can be associated to one 'Person'. But whenever I
try to associate a newly created PersName with a Person, I get a
CayenneRuntimeException:

org.apache.cayenne.CayenneRuntimeException: [v.2.0.4 October 12 2007]
Cannot set object as destination of relationship person because it is
in a different DataContext
     at org.apache.cayenne.CayenneDataObject.willConnect(CayenneDataObject.java:340)
     at org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneDataObject.java:290)
     at nl.huygensinstituut.bia.domain.auto._PersName.setPerson(_PersName.java:69)
     at nl.huygensinstituut.bia.PersonInfoPanel$2.onSubmit(PersonInfoPanel.java:102)
     at org.apache.wicket.markup.html.form.Form.delegateSubmit(Form.java:1351)
     at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:810)
     at java.lang.reflect.Method.invoke(Method.java:616)
     at org.apache.wicket.RequestListenerInterface.invoke(RequestListenerInterface.java:183)
     at org.apache.wicket.request.target.component.listener.ListenerInterfaceRequestTarget.processEvents(ListenerInterfaceRequestTarget.java:73)
     at org.apache.wicket.request.AbstractRequestCycleProcessor.processEvents(AbstractRequestCycleProcessor.java:91)
     at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1220)
     at org.apache.wicket.RequestCycle.step(RequestCycle.java:1297)
     at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1399)
     at org.apache.wicket.RequestCycle.request(RequestCycle.java:529)
     at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:356)
     at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:201)
(jetty frames snipped)

Here's a snippet of the failing code:

    DataContext mycontext = Databinder.getContext();
    person = ObjectFactory.getInstance().getPerson(parameters.getInt("personid"),
mycontext);
// ObjectFactory is a singleton. getPerson method executes
DataObjectUtils.objectForPK(context, Person.class, id);

    final PersName nameObj = (PersName) persNameForm.getModelObject();
// PersName extends CayenneDataObject
    persNameForm.add(new Button("submitpersname", new ResourceModel("Save")) {
      @Override
      public void onSubmit() {

        if (nameObj.getPerson() == null && person == null) {
          final Person auxiliary = ObjectFactory.getInstance().createPerson();
          auxiliary.setSex(Person.SEX_UNKNOWN);
          nameObj.setPerson(auxiliary);
        } else {
          nameObj.setPerson(person); // <-- line 102 where the
exception is triggered. 'person'
        }
        super.onSubmit();
      }
    });

Thanks for any advice!

-- 
Reinout van Schouwen
http://vanschouwen.info/