You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by Jonathan Bélisle <jo...@rcda.ca> on 2006/07/23 15:37:15 UTC

Moving object between DataContext

Hi, here is my problem.

I have a DataObject da1 registered with DataContext dc1.
I perform modification on da1. It's persistence state becomes MODIFIED.

Now I want to move da1 to DataContext dc2 and keep it's state MODIFIED 
so that when I do dc2.commitChanges(); da1 get written to the database.

Using dc2.localObject(da1.getObjectId(), da1) doesn't work because it's 
set the persistence state to COMMITTED and loose
track of witch properties were modified.
Even if I do da1.setPersistanceState(PersistenceState.MODIFIED) after 
localObject() da1 does not get written to the database on the next 
commit because dc2 thinks that no properties were modified.

Anybody know how to do that, a workaround ?

Thanks in advance, Jonathan.





Re: Re: Re: Moving object between DataContext

Posted by Michael Gentry <bl...@gmail.com>.
Oh yeah, a couple other options ...

Put your getUser() etc queries in the model and then call them:

http://cwiki.apache.org/confluence/display/CAYDOC/NamedQuery
http://cwiki.apache.org/confluence/display/CAYDOC/Queries+Stored+in+DataMap

Put getUser(DataContext dc, ...) in UserDataObject.java

/dev/mrg


On 7/24/06, Michael Gentry <bl...@gmail.com> wrote:
> I'm still not 100% certain your workflow/etc, but here are some thoughts.
>
> Cayenne doesn't really have a disconnect/reconnect feature, which
> sounds a bit like something Hibernate would have.  The Cayenne
> DataContext is a work area to manage your objects.  Anything you
> change in it is, conceptually, part of a transaction of changes you
> want committed to the database.  If you need two different
> transactions, you can use two DataContexts or possibly even a nested
> DataContext if that fits your workflow.  Also, you could make your
> method look more like:
>
>    public doSomething() {
>       UserDataObject udo= m_userService.getUserXXX(...);
>       udo.setXXX(...);
>       udo.setXXX(...);
>       udo.setXXX(...);
>
>       m_userService.saveUser(uod);
>
>       AppointementDataObject ado=
> m_appointementService.getAppointemetXXX(...);
>       ado.setXXX(...);
>       ado.setXXX(...);
>       ado.setXXX(...);
>    }
>
> You could also have your service layer receive as a parameter the
> DataContext to use in which to load/save, which would give you more
> flexibility.
>
> In all my years of using WebObjects, which includes EOF and is very
> similar to Cayenne, I've never needed to disconnect/reconnect my
> database objects.  Even using Tapestry/Cayenne, which is a lot like
> WebObjects, I've not needed to do that.  I think if you tweak your
> pattern a bit you'll find it can work very well for you.
>
> /dev/mrg
>
>
>
> On 7/23/06, Jonathan Bélisle <jo...@rcda.ca> wrote:
> > I need the second DataContext for the following reasons :
> >
> > I have a service class for business logic.
> > It's the service class that is responsible for accessing the database.
> > The UI layer calls the service class and gets a DataObject or a list of
> > DataObjects.
> > The UI Layer perform some modification on the objects and then call
> > the service to save the data and perform extra work.
> >
> > For this to work, the dataobjects returned by the service must have a
> > datacontext or I won't be able
> > to modified the relationships in the UI layer.
> > The second DataContext is needed when I call the service to save the
> > data. I need to be sure that there is no other object in the dataContext
> > that will be saved on commitChanges except the ones pass to the method.
> >
> > Class UserService {
> >
> >     public UserDataObject getUserXXX(...) {
> >         List results=
> > DataContext.getThreadDataContext().performQuery(new
> > SelectQuery(User.class.....);
> >         ...
> >        return (UserDataObject) result.get(x);
> >     }
> >
> >     public void saveUser(UserDataObject udo) {
> >         DataContext writeDc= DataContext.createDataContext();
> >         udo= writeDc.localObject(udo.getObjectId(), udo);
> >
> >           ... Perform extra work, send email, log, extra validation,  ...
> >
> >          writeContext.commitChanges();
> >     }
> > }
> >
> > Class UIWebPage {
> >
> >     public doSomething() {
> >        UserDataObject udo= m_userService.getUserXXX(...);
> >        udo.setXXX(...);
> >        udo.setXXX(...);
> >        udo.setXXX(...);
> >
> >        AppointementDataObject ado=
> > m_appointementService.getAppointemetXXX(...);
> >        ado.setXXX(...);
> >        ado.setXXX(...);
> >        ado.setXXX(...);
> >
> >        m_userService.saveUser(uod);
> >     }
> > }
> >
> > If i don't use another dataContext in saveUser, the appointement will
> > get saved too.
> > What i really would like to be able to do, is to be able to
> > disconnect/reconnect the dataObjects.
> > This way, the service disconnect the dataObjects before returning them
> > to the client and reconnect them when saving them.
> > Is it possible with cayenne ?
> > I have tried unregister/register the objects but you cannot modify the
> > relationships when there is no dataContext.
> > I also need cayenne to be able to update only the modified properties
> > when i reconnect them, not all the properties.
> >
> > I've been struggling with this issue for a while. Can someone help me on
> > this.
> > I'm using cayenne in a project where multiple UI access the service
> > layer; Tapestry and Swing.
> >
> > Jonathan.
> >
> >
> > Michael Gentry wrote:
> > > At the risk of asking silly questions, why do you need the second
> > > DataContext?  If you do need the second one, could you wait until you
> > > pull the object into the second context to do the setters?  (So the
> > > second context sets modified correctly.)
> > >
> > > Your comment about Cayenne not thinking an object is modified is
> > > correct.  If you have:
> > >
> > > if (object.getFirstName().equals("Michael"))
> > > {
> > >    object.setFirstName("michael");
> > >    object.setFirstName("Michael");
> > > }
> > >
> > > You essentially haven't modified the object and Cayenne figures this out.
> > >
> > > Thanks,
> > >
> > > /dev/mrg
> > >
> > >
> > > On 7/23/06, Jonathan Bélisle <jo...@rcda.ca> wrote:
> > >> Hi, here is my problem.
> > >>
> > >> I have a DataObject da1 registered with DataContext dc1.
> > >> I perform modification on da1. It's persistence state becomes MODIFIED.
> > >>
> > >> Now I want to move da1 to DataContext dc2 and keep it's state MODIFIED
> > >> so that when I do dc2.commitChanges(); da1 get written to the database.
> > >>
> > >> Using dc2.localObject(da1.getObjectId(), da1) doesn't work because it's
> > >> set the persistence state to COMMITTED and loose
> > >> track of witch properties were modified.
> > >> Even if I do da1.setPersistanceState(PersistenceState.MODIFIED) after
> > >> localObject() da1 does not get written to the database on the next
> > >> commit because dc2 thinks that no properties were modified.
> > >>
> > >> Anybody know how to do that, a workaround ?
> > >>
> > >> Thanks in advance, Jonathan.
> > >>
> > >>
> > >>
> > >>
> > >>
> > >
> > >
> > >
> >
> >
> >
>

Re: Re: Moving object between DataContext

Posted by Michael Gentry <bl...@gmail.com>.
I'm still not 100% certain your workflow/etc, but here are some thoughts.

Cayenne doesn't really have a disconnect/reconnect feature, which
sounds a bit like something Hibernate would have.  The Cayenne
DataContext is a work area to manage your objects.  Anything you
change in it is, conceptually, part of a transaction of changes you
want committed to the database.  If you need two different
transactions, you can use two DataContexts or possibly even a nested
DataContext if that fits your workflow.  Also, you could make your
method look more like:

   public doSomething() {
      UserDataObject udo= m_userService.getUserXXX(...);
      udo.setXXX(...);
      udo.setXXX(...);
      udo.setXXX(...);

      m_userService.saveUser(uod);

      AppointementDataObject ado=
m_appointementService.getAppointemetXXX(...);
      ado.setXXX(...);
      ado.setXXX(...);
      ado.setXXX(...);
   }

You could also have your service layer receive as a parameter the
DataContext to use in which to load/save, which would give you more
flexibility.

In all my years of using WebObjects, which includes EOF and is very
similar to Cayenne, I've never needed to disconnect/reconnect my
database objects.  Even using Tapestry/Cayenne, which is a lot like
WebObjects, I've not needed to do that.  I think if you tweak your
pattern a bit you'll find it can work very well for you.

/dev/mrg



On 7/23/06, Jonathan Bélisle <jo...@rcda.ca> wrote:
> I need the second DataContext for the following reasons :
>
> I have a service class for business logic.
> It's the service class that is responsible for accessing the database.
> The UI layer calls the service class and gets a DataObject or a list of
> DataObjects.
> The UI Layer perform some modification on the objects and then call
> the service to save the data and perform extra work.
>
> For this to work, the dataobjects returned by the service must have a
> datacontext or I won't be able
> to modified the relationships in the UI layer.
> The second DataContext is needed when I call the service to save the
> data. I need to be sure that there is no other object in the dataContext
> that will be saved on commitChanges except the ones pass to the method.
>
> Class UserService {
>
>     public UserDataObject getUserXXX(...) {
>         List results=
> DataContext.getThreadDataContext().performQuery(new
> SelectQuery(User.class.....);
>         ...
>        return (UserDataObject) result.get(x);
>     }
>
>     public void saveUser(UserDataObject udo) {
>         DataContext writeDc= DataContext.createDataContext();
>         udo= writeDc.localObject(udo.getObjectId(), udo);
>
>           ... Perform extra work, send email, log, extra validation,  ...
>
>          writeContext.commitChanges();
>     }
> }
>
> Class UIWebPage {
>
>     public doSomething() {
>        UserDataObject udo= m_userService.getUserXXX(...);
>        udo.setXXX(...);
>        udo.setXXX(...);
>        udo.setXXX(...);
>
>        AppointementDataObject ado=
> m_appointementService.getAppointemetXXX(...);
>        ado.setXXX(...);
>        ado.setXXX(...);
>        ado.setXXX(...);
>
>        m_userService.saveUser(uod);
>     }
> }
>
> If i don't use another dataContext in saveUser, the appointement will
> get saved too.
> What i really would like to be able to do, is to be able to
> disconnect/reconnect the dataObjects.
> This way, the service disconnect the dataObjects before returning them
> to the client and reconnect them when saving them.
> Is it possible with cayenne ?
> I have tried unregister/register the objects but you cannot modify the
> relationships when there is no dataContext.
> I also need cayenne to be able to update only the modified properties
> when i reconnect them, not all the properties.
>
> I've been struggling with this issue for a while. Can someone help me on
> this.
> I'm using cayenne in a project where multiple UI access the service
> layer; Tapestry and Swing.
>
> Jonathan.
>
>
> Michael Gentry wrote:
> > At the risk of asking silly questions, why do you need the second
> > DataContext?  If you do need the second one, could you wait until you
> > pull the object into the second context to do the setters?  (So the
> > second context sets modified correctly.)
> >
> > Your comment about Cayenne not thinking an object is modified is
> > correct.  If you have:
> >
> > if (object.getFirstName().equals("Michael"))
> > {
> >    object.setFirstName("michael");
> >    object.setFirstName("Michael");
> > }
> >
> > You essentially haven't modified the object and Cayenne figures this out.
> >
> > Thanks,
> >
> > /dev/mrg
> >
> >
> > On 7/23/06, Jonathan Bélisle <jo...@rcda.ca> wrote:
> >> Hi, here is my problem.
> >>
> >> I have a DataObject da1 registered with DataContext dc1.
> >> I perform modification on da1. It's persistence state becomes MODIFIED.
> >>
> >> Now I want to move da1 to DataContext dc2 and keep it's state MODIFIED
> >> so that when I do dc2.commitChanges(); da1 get written to the database.
> >>
> >> Using dc2.localObject(da1.getObjectId(), da1) doesn't work because it's
> >> set the persistence state to COMMITTED and loose
> >> track of witch properties were modified.
> >> Even if I do da1.setPersistanceState(PersistenceState.MODIFIED) after
> >> localObject() da1 does not get written to the database on the next
> >> commit because dc2 thinks that no properties were modified.
> >>
> >> Anybody know how to do that, a workaround ?
> >>
> >> Thanks in advance, Jonathan.
> >>
> >>
> >>
> >>
> >>
> >
> >
> >
>
>
>

Re: Moving object between DataContext

Posted by Jonathan Bélisle <jo...@rcda.ca>.
I need the second DataContext for the following reasons :

I have a service class for business logic.
It's the service class that is responsible for accessing the database.
The UI layer calls the service class and gets a DataObject or a list of 
DataObjects.
The UI Layer perform some modification on the objects and then call
the service to save the data and perform extra work.

For this to work, the dataobjects returned by the service must have a 
datacontext or I won't be able
to modified the relationships in the UI layer.
The second DataContext is needed when I call the service to save the 
data. I need to be sure that there is no other object in the dataContext
that will be saved on commitChanges except the ones pass to the method.

Class UserService {

    public UserDataObject getUserXXX(...) {
        List results= 
DataContext.getThreadDataContext().performQuery(new 
SelectQuery(User.class.....);
        ...
       return (UserDataObject) result.get(x);
    }

    public void saveUser(UserDataObject udo) {
        DataContext writeDc= DataContext.createDataContext();
        udo= writeDc.localObject(udo.getObjectId(), udo);
   
          ... Perform extra work, send email, log, extra validation,  ...

         writeContext.commitChanges();
    }
}

Class UIWebPage {

    public doSomething() {
       UserDataObject udo= m_userService.getUserXXX(...);
       udo.setXXX(...);
       udo.setXXX(...);
       udo.setXXX(...);

       AppointementDataObject ado= 
m_appointementService.getAppointemetXXX(...);
       ado.setXXX(...);
       ado.setXXX(...);
       ado.setXXX(...);

       m_userService.saveUser(uod);
    }
}

If i don't use another dataContext in saveUser, the appointement will 
get saved too.
What i really would like to be able to do, is to be able to 
disconnect/reconnect the dataObjects.
This way, the service disconnect the dataObjects before returning them 
to the client and reconnect them when saving them.
Is it possible with cayenne ?
I have tried unregister/register the objects but you cannot modify the 
relationships when there is no dataContext.
I also need cayenne to be able to update only the modified properties 
when i reconnect them, not all the properties.

I've been struggling with this issue for a while. Can someone help me on 
this.
I'm using cayenne in a project where multiple UI access the service 
layer; Tapestry and Swing.

Jonathan.


Michael Gentry wrote:
> At the risk of asking silly questions, why do you need the second
> DataContext?  If you do need the second one, could you wait until you
> pull the object into the second context to do the setters?  (So the
> second context sets modified correctly.)
>
> Your comment about Cayenne not thinking an object is modified is
> correct.  If you have:
>
> if (object.getFirstName().equals("Michael"))
> {
>    object.setFirstName("michael");
>    object.setFirstName("Michael");
> }
>
> You essentially haven't modified the object and Cayenne figures this out.
>
> Thanks,
>
> /dev/mrg
>
>
> On 7/23/06, Jonathan Bélisle <jo...@rcda.ca> wrote:
>> Hi, here is my problem.
>>
>> I have a DataObject da1 registered with DataContext dc1.
>> I perform modification on da1. It's persistence state becomes MODIFIED.
>>
>> Now I want to move da1 to DataContext dc2 and keep it's state MODIFIED
>> so that when I do dc2.commitChanges(); da1 get written to the database.
>>
>> Using dc2.localObject(da1.getObjectId(), da1) doesn't work because it's
>> set the persistence state to COMMITTED and loose
>> track of witch properties were modified.
>> Even if I do da1.setPersistanceState(PersistenceState.MODIFIED) after
>> localObject() da1 does not get written to the database on the next
>> commit because dc2 thinks that no properties were modified.
>>
>> Anybody know how to do that, a workaround ?
>>
>> Thanks in advance, Jonathan.
>>
>>
>>
>>
>>
>
>
>



Re: Moving object between DataContext

Posted by Michael Gentry <bl...@gmail.com>.
At the risk of asking silly questions, why do you need the second
DataContext?  If you do need the second one, could you wait until you
pull the object into the second context to do the setters?  (So the
second context sets modified correctly.)

Your comment about Cayenne not thinking an object is modified is
correct.  If you have:

if (object.getFirstName().equals("Michael"))
{
    object.setFirstName("michael");
    object.setFirstName("Michael");
}

You essentially haven't modified the object and Cayenne figures this out.

Thanks,

/dev/mrg


On 7/23/06, Jonathan Bélisle <jo...@rcda.ca> wrote:
> Hi, here is my problem.
>
> I have a DataObject da1 registered with DataContext dc1.
> I perform modification on da1. It's persistence state becomes MODIFIED.
>
> Now I want to move da1 to DataContext dc2 and keep it's state MODIFIED
> so that when I do dc2.commitChanges(); da1 get written to the database.
>
> Using dc2.localObject(da1.getObjectId(), da1) doesn't work because it's
> set the persistence state to COMMITTED and loose
> track of witch properties were modified.
> Even if I do da1.setPersistanceState(PersistenceState.MODIFIED) after
> localObject() da1 does not get written to the database on the next
> commit because dc2 thinks that no properties were modified.
>
> Anybody know how to do that, a workaround ?
>
> Thanks in advance, Jonathan.
>
>
>
>
>