You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by Malcolm Edgar <ma...@zurich.com.au> on 2006/03/27 04:58:13 UTC
DataContext scope in web apps
Hi All,
I am finding that with the Cayenne web app design pattern where the
DataContext has session scope, it is easy to add objects to the
DataContext when building up an object graph for display. If these objects
aren't explicity committed by request it is easy to have them carried
forward in the session DataContext, and have them committed in a
subsequent but unrelated request.
While though careful programming I think I can avoid such issues, but I am
looking for a more easier way of dealing with this. A couple of concepts
include:
1. Using a request scope DataContext
With this I was thinking of a DataContext servlet filter which creates a
new thread local DataContext for each request. If the user does not
explicitly commit changes in the data context, at the end of the request
it will go out of scope and be garbage collected.
Issues with this appoarch could be performance cost of creating a
DataContext for each request (I dont know if this is an issue), and the
loss of the session scope caching benefits the DataContext provides.
2. Using nested DataContext with a request scope
The other idea is to create a nested DataContext from the parent session
DataContext and bind this current thread. I imagine this would give you
the benefits of session scope caching, but still enable you to throw away
uncommitted data context objects at the end of the request. I don't know
if it is any faster to create nested data contexts.
Does anyone have any experience with these patterns or have any comments?
regards Malcolm Edgar
----
This email is intended for the named recipient only. It may contain information which is confidential, commercially sensitive, or copyright. If you are not the intended recipient you must not reproduce or distribute any part of the email, disclose its contents, or take any action in reliance. If you have received this email in error, please contact the sender and delete the message. It is your responsibility to scan this email and any attachments for viruses and other defects.
To the extent permitted by law, Zurich and its associates will not be liable for any loss or damage arising in any way from this communication including any file attachments. We may monitor email you send to us, either as a reply to this email or any email you send to us, to confirm our systems are protected and for compliance with company policies. Although we take reasonable precautions to protect the confidentiality of our email systems, we do not warrant the confidentiality or security of email or attachments we receive.
Re: DataContext scope in web apps
Posted by Cris Daniluk <cr...@gmail.com>.
We also do this (automatically via a ServletFilter, interceptor, etc). In
the pre-nested DataContext world, if I have a page that spans multiple
requests, I create a new DataContext that does not automatically rollback
each request, and bind that to the thread, rather than the session default.
A token in the form links the flow to the new DataContext. Then, if the user
somehow gets objects in a bad state and goes on to other parts of the
application, the clean DataContext is used. A wrapper object for the Action
or whatever seemlessly takes care of this when a token is present.
I imagine with nested contexts, I would do something similar - it is even
conceivable to me to do all write operations in a nested DataContext,
regardless of how many requests it may take. I haven't explored the new code
in depth, but such a design should let you delegate the actual db
commit/rollback to a separate processor within your application, opening up
all sorts of interesting possibilities.
Cris
On 3/27/06, Bryan Lewis <br...@maine.rr.com> wrote:
>
> Andrus Adamchik wrote:
>
> > 3. Another possibility - if you never ever carry uncommitted state
> > across requests, you can setup a filter that does
> > DataContext.rollbackChanges() at the end of the request. This is a
> > variation of the request-scope context, only preserving caching
> > benefits.
>
> We do a similar thing in our Tapestry apps, mimicking what we used to do
> in WebObjects. Every time a new page is requested -- our base Page
> class provides a getPage(name) method -- we do the rollbackChanges().
> We seldom have workflow that spans more than one page.
>
>
Re: DataContext scope in web apps
Posted by Bryan Lewis <br...@maine.rr.com>.
Andrus Adamchik wrote:
> 3. Another possibility - if you never ever carry uncommitted state
> across requests, you can setup a filter that does
> DataContext.rollbackChanges() at the end of the request. This is a
> variation of the request-scope context, only preserving caching
> benefits.
We do a similar thing in our Tapestry apps, mimicking what we used to do
in WebObjects. Every time a new page is requested -- our base Page
class provides a getPage(name) method -- we do the rollbackChanges().
We seldom have workflow that spans more than one page.
Re: DataContext scope in web apps
Posted by Mike Kienenberger <mk...@gmail.com>.
On 3/27/06, Mike Kienenberger <mk...@gmail.com> wrote:
> I'm happy to post the code if anyone's interested. It depends only on
> Cayenne and javax.servlet classes.
Since there's been some interest in this, here is a copy of my
DataContextManagerFilter.java class.
Re: DataContext scope in web apps
Posted by Mike Kienenberger <mk...@gmail.com>.
On 3/27/06, Andrus Adamchik <an...@objectstyle.org> wrote:
> 3. Another possibility - if you never ever carry uncommitted state
> across requests, you can setup a filter that does
> DataContext.rollbackChanges() at the end of the request. This is a
> variation of the request-scope context, only preserving caching
> benefits.
This is how I'm doing it as well.
I have a session-scoped DataContext and I assign it to thread-local in
my first servlet filter. At the post-processing stage (insuring that
it's also the last piece of code executed per request), I remove the
thread-local, and I validate that the DataContext has no new objects,
no modified objects, and no deleted objects. If it does, I log each
object as an error and rollback the context. For now, I also throw
an error since this is still in the dev stages and it's a bug to be in
this state.
I'm happy to post the code if anyone's interested. It depends only on
Cayenne and javax.servlet classes.
Re: DataContext scope in web apps
Posted by Andrus Adamchik <an...@objectstyle.org>.
Ok, makes sense.
> Adding an auto rollback option to the Cayenne web filter be a good, as
> would a topic should in the Wiki doco.
Agreed. We may add this to the standard Cayenne filter, with the
rollback flag flipped on or off via the init-param in web.xml.
Andrus
On Mar 29, 2006, at 9:50 AM, Malcolm Edgar wrote:
>
> Hi Andrus,
>
> the use case is, I have a new User data object which has a Address
> data
> object property:
>
> public Address extends CayenneDataObject {
> ..
> }
>
> public User extends CayenneDataObject {
> public getAddress(); { .. }
> public setAddress(Address address) { .. };
> ..
> }
>
> I am using a CayenneForm to create a new User and Address object in
> one
> post. To add the Address object to the User object, the User object
> must
> be registered with the DataContext for the relationship lookups.
>
> With an invalid post all the submitted values must be validated before
> creating a new User object, otherwise an invalid User object is
> added to
> the session DataContext.
>
> I think the approach people advocate of always rolling back at the
> end of
> each request sounds like a good practice for most use cases. The
> multi-page workflows could be handled by a separate DataContext
> session.
>
> Adding an auto rollback option to the Cayenne web filter be a good, as
> would a topic should in the Wiki doco.
>
> regards Malcolm Edgar
>
>
>
>
> Andrus Adamchik <an...@objectstyle.org>
> 27/03/2006 05:32 PM
> Please respond to
> cayenne-user@incubator.apache.org
>
>
> To
> cayenne-user@incubator.apache.org
> cc
>
> Subject
> Re: DataContext scope in web apps
>
>
>
>
>
>
> Hi Malcolm,
>
> I understand your question is also somewhat related to CAY-483 issue
> that you opened recently.
>
>> I am finding that with the Cayenne web app design pattern where the
>> DataContext has session scope, it is easy to add objects to the
>> DataContext when building up an object graph for display.
>
> Can you give an example. How can you add a new *persistent* object
> that you don't want to commit? Is it only due to a programming error?
>
>> 1. Using a request scope DataContext
>>
>> With this I was thinking of a DataContext servlet filter which
>> creates a
>> new thread local DataContext for each request. If the user does not
>> explicitly commit changes in the data context, at the end of the
>> request
>> it will go out of scope and be garbage collected.
>>
>> Issues with this appoarch could be performance cost of creating a
>> DataContext for each request (I dont know if this is an issue), and
>> the
>> loss of the session scope caching benefits the DataContext provides.
>
> That's a possibility. There is very little overhead in new context
> creation. There may (or may not) be a performance degradation due to
> the loss of DataContext-level caching. This is application dependent.
> Context cache saves you from doing extra DB trips for previously
> resolved to-one and to-many relationships... also for the cached
> queries if you use them.
>
>
>> 2. Using nested DataContext with a request scope
>>
>> The other idea is to create a nested DataContext from the parent
>> session
>> DataContext and bind this current thread. I imagine this would give
>> you
>> the benefits of session scope caching, but still enable you to
>> throw away
>> uncommitted data context objects at the end of the request. I
>> don't know
>> if it is any faster to create nested data contexts.
>
> As you know nested DataContexts is a new feature, so we don't have
> any empiric data on its performance (would love to get your
> feedback). Performance overhead it adds is due to the fact that
> select and commit operations have to travel through an extra
> processing point in the stack. I would say it is appropriate for an
> editor form that supposedly accesses/modifies no more than a few
> [dozens] of objects; and not appropriate for a search page that may
> access thousands of objects.
>
> 3. Another possibility - if you never ever carry uncommitted state
> across requests, you can setup a filter that does
> DataContext.rollbackChanges() at the end of the request. This is a
> variation of the request-scope context, only preserving caching
> benefits.
>
> Andrus
>
>
>
>
>
>
>
> ----
> This email is intended for the named recipient only. It may contain
> information which is confidential, commercially sensitive, or
> copyright. If you are not the intended recipient you must not
> reproduce or distribute any part of the email, disclose its
> contents, or take any action in reliance. If you have received this
> email in error, please contact the sender and delete the message.
> It is your responsibility to scan this email and any attachments
> for viruses and other defects.
> To the extent permitted by law, Zurich and its associates will not
> be liable for any loss or damage arising in any way from this
> communication including any file attachments. We may monitor email
> you send to us, either as a reply to this email or any email you
> send to us, to confirm our systems are protected and for compliance
> with company policies. Although we take reasonable precautions to
> protect the confidentiality of our email systems, we do not warrant
> the confidentiality or security of email or attachments we receive.
Re: DataContext scope in web apps
Posted by Malcolm Edgar <ma...@zurich.com.au>.
Hi Andrus,
the use case is, I have a new User data object which has a Address data
object property:
public Address extends CayenneDataObject {
..
}
public User extends CayenneDataObject {
public getAddress(); { .. }
public setAddress(Address address) { .. };
..
}
I am using a CayenneForm to create a new User and Address object in one
post. To add the Address object to the User object, the User object must
be registered with the DataContext for the relationship lookups.
With an invalid post all the submitted values must be validated before
creating a new User object, otherwise an invalid User object is added to
the session DataContext.
I think the approach people advocate of always rolling back at the end of
each request sounds like a good practice for most use cases. The
multi-page workflows could be handled by a separate DataContext session.
Adding an auto rollback option to the Cayenne web filter be a good, as
would a topic should in the Wiki doco.
regards Malcolm Edgar
Andrus Adamchik <an...@objectstyle.org>
27/03/2006 05:32 PM
Please respond to
cayenne-user@incubator.apache.org
To
cayenne-user@incubator.apache.org
cc
Subject
Re: DataContext scope in web apps
Hi Malcolm,
I understand your question is also somewhat related to CAY-483 issue
that you opened recently.
> I am finding that with the Cayenne web app design pattern where the
> DataContext has session scope, it is easy to add objects to the
> DataContext when building up an object graph for display.
Can you give an example. How can you add a new *persistent* object
that you don't want to commit? Is it only due to a programming error?
> 1. Using a request scope DataContext
>
> With this I was thinking of a DataContext servlet filter which
> creates a
> new thread local DataContext for each request. If the user does not
> explicitly commit changes in the data context, at the end of the
> request
> it will go out of scope and be garbage collected.
>
> Issues with this appoarch could be performance cost of creating a
> DataContext for each request (I dont know if this is an issue), and
> the
> loss of the session scope caching benefits the DataContext provides.
That's a possibility. There is very little overhead in new context
creation. There may (or may not) be a performance degradation due to
the loss of DataContext-level caching. This is application dependent.
Context cache saves you from doing extra DB trips for previously
resolved to-one and to-many relationships... also for the cached
queries if you use them.
> 2. Using nested DataContext with a request scope
>
> The other idea is to create a nested DataContext from the parent
> session
> DataContext and bind this current thread. I imagine this would give
> you
> the benefits of session scope caching, but still enable you to
> throw away
> uncommitted data context objects at the end of the request. I
> don't know
> if it is any faster to create nested data contexts.
As you know nested DataContexts is a new feature, so we don't have
any empiric data on its performance (would love to get your
feedback). Performance overhead it adds is due to the fact that
select and commit operations have to travel through an extra
processing point in the stack. I would say it is appropriate for an
editor form that supposedly accesses/modifies no more than a few
[dozens] of objects; and not appropriate for a search page that may
access thousands of objects.
3. Another possibility - if you never ever carry uncommitted state
across requests, you can setup a filter that does
DataContext.rollbackChanges() at the end of the request. This is a
variation of the request-scope context, only preserving caching
benefits.
Andrus
----
This email is intended for the named recipient only. It may contain information which is confidential, commercially sensitive, or copyright. If you are not the intended recipient you must not reproduce or distribute any part of the email, disclose its contents, or take any action in reliance. If you have received this email in error, please contact the sender and delete the message. It is your responsibility to scan this email and any attachments for viruses and other defects.
To the extent permitted by law, Zurich and its associates will not be liable for any loss or damage arising in any way from this communication including any file attachments. We may monitor email you send to us, either as a reply to this email or any email you send to us, to confirm our systems are protected and for compliance with company policies. Although we take reasonable precautions to protect the confidentiality of our email systems, we do not warrant the confidentiality or security of email or attachments we receive.
Re: DataContext scope in web apps
Posted by Andrus Adamchik <an...@objectstyle.org>.
Hi Malcolm,
I understand your question is also somewhat related to CAY-483 issue
that you opened recently.
> I am finding that with the Cayenne web app design pattern where the
> DataContext has session scope, it is easy to add objects to the
> DataContext when building up an object graph for display.
Can you give an example. How can you add a new *persistent* object
that you don't want to commit? Is it only due to a programming error?
> 1. Using a request scope DataContext
>
> With this I was thinking of a DataContext servlet filter which
> creates a
> new thread local DataContext for each request. If the user does not
> explicitly commit changes in the data context, at the end of the
> request
> it will go out of scope and be garbage collected.
>
> Issues with this appoarch could be performance cost of creating a
> DataContext for each request (I dont know if this is an issue), and
> the
> loss of the session scope caching benefits the DataContext provides.
That's a possibility. There is very little overhead in new context
creation. There may (or may not) be a performance degradation due to
the loss of DataContext-level caching. This is application dependent.
Context cache saves you from doing extra DB trips for previously
resolved to-one and to-many relationships... also for the cached
queries if you use them.
> 2. Using nested DataContext with a request scope
>
> The other idea is to create a nested DataContext from the parent
> session
> DataContext and bind this current thread. I imagine this would give
> you
> the benefits of session scope caching, but still enable you to
> throw away
> uncommitted data context objects at the end of the request. I
> don't know
> if it is any faster to create nested data contexts.
As you know nested DataContexts is a new feature, so we don't have
any empiric data on its performance (would love to get your
feedback). Performance overhead it adds is due to the fact that
select and commit operations have to travel through an extra
processing point in the stack. I would say it is appropriate for an
editor form that supposedly accesses/modifies no more than a few
[dozens] of objects; and not appropriate for a search page that may
access thousands of objects.
3. Another possibility - if you never ever carry uncommitted state
across requests, you can setup a filter that does
DataContext.rollbackChanges() at the end of the request. This is a
variation of the request-scope context, only preserving caching
benefits.
Andrus
Re: DataContext scope in web apps
Posted by Andrus Adamchik <an...@objectstyle.org>.
> But I mention the pattern because one thing I've been considering
> doing in one particularly complicated workflow is to have an
> accumulator object graph that never actually gets committed, but
> when the user saves or changes something a new datacontext is
> derived from it. A bit expensive on memory and processing, but
> probably an easy way to achieve what would otherwise be quite a
> complicated algorithm. Maybe this is something you could consider.
I am eager to explore nested contexts for complex workflows with the
ability to roll back sub-flows in memory without rolling back the
entire thing. In fact nested contexts were designed with such
scenario in mind.
Andrus
On Mar 27, 2006, at 8:08 AM, Craig Turner wrote:
> Malcolm Edgar wrote:
>> I am finding that with the Cayenne web app design pattern where
>> the DataContext has session scope, it is easy to add objects to
>> the DataContext when building up an object graph for display. If
>> these objects aren't explicity committed by request it is easy to
>> have them carried forward in the session DataContext, and have
>> them committed in a subsequent but unrelated request.
>
> In the past I have had problems where the user will fail validation
> on one screen, move to another, attempt a save, and then run into
> problems because objects from the old screen are still sitting in
> the datacontext.
>
> I get around this these days by using different DataContexts for
> different flows. Each subsystem in my app is associated with a
> different 'workflow' in the engine, and each workflow has its own
> DataContext. I've been very happy with this pattern. And if there
> are situations where one updating can have flow-on-effects to
> another, then I get that workflow to reset the affected workflows
> so that they'll be built up from scratch again if the user returns
> to those screens. As my app is a webapp this is acceptable usage -
> in fact I've been very happy with this pattern.
>
> One of the advantages of cayenne over EOF (at least in my
> experience) is that you can remove things from the graph after
> adding them, which makes it nice as a hacky object-graph-on-demand
> even for things that you'll never persist to the database. But I
> find that using multiple datacontexts I rarely need to remove
> things from the graph.
>
> But I mention the pattern because one thing I've been considering
> doing in one particularly complicated workflow is to have an
> accumulator object graph that never actually gets committed, but
> when the user saves or changes something a new datacontext is
> derived from it. A bit expensive on memory and processing, but
> probably an easy way to achieve what would otherwise be quite a
> complicated algorithm. Maybe this is something you could consider.
>
> - C
>
Re: DataContext scope in web apps
Posted by Craig Turner <cr...@synect.com>.
Malcolm Edgar wrote:
> I am finding that with the Cayenne web app design pattern where the
> DataContext has session scope, it is easy to add objects to the
> DataContext when building up an object graph for display. If these objects
> aren't explicity committed by request it is easy to have them carried
> forward in the session DataContext, and have them committed in a
> subsequent but unrelated request.
In the past I have had problems where the user will fail validation on
one screen, move to another, attempt a save, and then run into problems
because objects from the old screen are still sitting in the datacontext.
I get around this these days by using different DataContexts for
different flows. Each subsystem in my app is associated with a different
'workflow' in the engine, and each workflow has its own DataContext.
I've been very happy with this pattern. And if there are situations
where one updating can have flow-on-effects to another, then I get that
workflow to reset the affected workflows so that they'll be built up
from scratch again if the user returns to those screens. As my app is a
webapp this is acceptable usage - in fact I've been very happy with this
pattern.
One of the advantages of cayenne over EOF (at least in my experience) is
that you can remove things from the graph after adding them, which makes
it nice as a hacky object-graph-on-demand even for things that you'll
never persist to the database. But I find that using multiple
datacontexts I rarely need to remove things from the graph.
But I mention the pattern because one thing I've been considering doing
in one particularly complicated workflow is to have an accumulator
object graph that never actually gets committed, but when the user saves
or changes something a new datacontext is derived from it. A bit
expensive on memory and processing, but probably an easy way to achieve
what would otherwise be quite a complicated algorithm. Maybe this is
something you could consider.
- C