[cf-orm-dev] EntityMerge VS EntitySave

131 views
Skip to first unread message

Simon

unread,
Apr 19, 2010, 7:58:30 PM4/19/10
to cf-orm-dev
Hello,

Does anyone has experience in using EntityMerge and EntitySave.

The question is simple, why should we use EntitySave and not always
EntityMerge ?

My components are simple:
- user has unidirectional many-to-one relation with company.
- group has unidirectional one-to-many relation with company.
- group has an array collection users: a many-to-many relation with
user

As you can see I don't use bidirectional relations.

---------------------------- CFCs BEGIN
----------------------------

component persistent="true" table="um_group" output="false"
{
/* PROPERTIES */
property name="grp_id" column="grp_id" type="numeric" ormtype="int"
fieldtype="id" generator="native";
property name="grp_code" column="grp_code" type="string"
ormtype="string";
property name="grp_name" column="grp_name" type="string"
ormtype="string";
property name="grp_desc" column="grp_desc" type="string"
ormtype="string";
property name="grp_status" column="grp_status" type="numeric"
ormtype="short";
property name="grp_sys" column="grp_sys" type="numeric"
ormtype="byte";

/* RELATIONS */
property name="users" fieldtype="many-to-many" cfc="um_user"
fkColumn="grp_id"
linktable="um_user_group_link" InverseJoinColumn="usr_id"
type="array" lazy="true" cascade="save-update"
notnull="false"
remotingfetch="true" singularname="user"
default="[]";

/* FUNCTIONS */
public void function setUsers(required array newUsers)
{
variables.users = [];
if (arraylen(arguments.newUsers) gt 0){
for (i = 1; i <= arraylen(arguments.newUsers); i++ ){
newUser = arguments.newUsers[i];
this.addUser(newUser);
}
}
}

component persistent="true" table="um_user" output="false"
{
/* PROPERTIES */
property name="usr_id" column="usr_id" type="numeric" ormtype="int"
fieldtype="id" generator="native";
property name="usr_email" column="usr_email" type="string"
ormtype="string";
property name="usr_pwd" column="usr_pwd" type="string"
ormtype="string";
property name="usr_salt" column="usr_salt" type="string"
ormtype="string" insert="false" update="false";
property name="usr_first_name" column="usr_first_name" type="string"
ormtype="string";
property name="usr_last_name" column="usr_last_name" type="string"
ormtype="string";
property name="usr_status" column="usr_status" type="numeric"
ormtype="short";
property name="usr_job_title" column="usr_job_title" type="string"
ormtype="string";
property name="usr_phone" column="usr_phone" type="string"
ormtype="string";
property name="usr_fax" column="usr_fax" type="string"
ormtype="string";
property name="usr_mobile" column="usr_mobile" type="string"
ormtype="string";
property name="usr_title" column="usr_title" type="string"
ormtype="string";

/* RELATIONS */
property name="company" fieldtype="many-to-one" fkcolumn="cpy_id"
cfc="um_company"
notnull="false" remotingfetch="true"
inverse="true"
cascade="save-update" lazy="true";

/* FUNCTIONS */
/**@hint Override setCompany to Handle the Null problem with Flex*/
public function setCompany(required any newCompany)
{
if (IsInstanceOf(arguments.newCompany,"um_company")){
variables.company = arguments.newCompany;
//arguments.newCompany.addUser(this); Used only if Bidirectional
}
else{
variables.company = JavaCast("Null", "");//If Null is acceptable,
if not, set a default company.
}
}

component persistent="true" table="um_company" output="false"
{
/* PROPERTIES */
property name="cpy_id" column="cpy_id" type="numeric" ormtype="int"
fieldtype="id" generator="native";
property name="cpy_code" column="cpy_code" type="string"
ormtype="string" length="10";
property name="cpy_name" column="cpy_name" type="string"
ormtype="string" length="50";

/* RELATIONS */
property name="groups" fieldtype="one-to-many" fkColumn="cpy_id"
cfc="um_group"
type="array" lazy="true" singularname="group"
remotingfetch="true" cascade="all";

---------------------------- CFCs END ----------------------------


From Flex, I load a group with his collection of users, and add a new
user to the group, then call an update function:

remote um_group function updateum_group(um_group item)
{
entitysave(item);
return item;
}

And got the following error message:

Unable to invoke CFC - a different object with the same identifier
value was already associated with the session: [um_user#5]
Root cause :org.hibernate.NonUniqueObjectException: a different object
with the same identifier value was already associated with the
session: [um_user#5]

I solve the problem and my object get persisted in the database by
changing my update function to :

remote um_group function updateum_group(um_group item)
{
entitymerge(item);
return item;
}

So why should we use EntitySave and not always EntityMerge ?

Thanks,

Simon

--
You received this message because you are subscribed to the Google Groups "cf-orm-dev" group.
To post to this group, send email to cf-or...@googlegroups.com.
To unsubscribe from this group, send email to cf-orm-dev+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/cf-orm-dev?hl=en.

Brian Kotek

unread,
Apr 19, 2010, 8:36:36 PM4/19/10
to cf-or...@googlegroups.com
I believe the main difference is that when using merge(), Hibernate is forced to query and build the object graph again in order to copy the values over from the detached entity. Also, merge doesn't update the original (detached) object, but instead *returns* an updated and session-attached object.

On an unrelated note, you're going to want to be VERY careful with how you're doing this. Be aware that any time you return a user to Flex, BlazeDS will load and serialize the ENTIRE object graph (because you have remotingfetch=true). That means a user will load its groups, which will each load ALL of their related users, and then all of THEIR related groups, and so on. If the set of users and groups gets large this will cause serious problems.

Brian

Simon

unread,
Apr 20, 2010, 8:56:28 PM4/20/10
to cf-orm-dev
Hi Brian,

Thanks for your answers.

Your comment about "remotefetching=true" is very interesting and I
will create an another discussion for that.

Regarding the entityMerge: I'm confused...

You said:
"Hibernate is forced to query and build the object graph again". Do
you mean to query the database?

Because I don't have the same understanding, regarding the hibernate
doc:
http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/objectstate.html#d0e1318
"the merged objects state overrides the persistent entity state in the
persistence context"

First, let's make a statement: Because we are in the context of RIA,
Flex in this case, all object send back from Flex to CF are object
detached from the Hibernate session (hibernate session lives only
inside one CF request). In this particular context my question make
sense: should we always use entityMerge when dealing with Flex,
detached objects?

EntityMerge will override the object (and his related objects) in the
database = That's what we want.

EntitySave will not work because the object is detached (unknown by
the hibernate session). So somehow we will need to reload it first
from the database to the new hibernate session, then assign it the new
value (object coming back from flex) and finally use entitySave.
> > cf-orm-dev+...@googlegroups.com<cf-orm-dev%2Bunsu...@googlegroups.com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/cf-orm-dev?hl=en.
>
> --
> You received this message because you are subscribed to the Google Groups "cf-orm-dev" group.
> To post to this group, send email to cf-or...@googlegroups.com.
> To unsubscribe from this group, send email to cf-orm-dev+...@googlegroups.com.
> For more options, visit this group athttp://groups.google.com/group/cf-orm-dev?hl=en.

Brian Kotek

unread,
Apr 20, 2010, 9:15:26 PM4/20/10
to cf-or...@googlegroups.com
On Tue, Apr 20, 2010 at 8:56 PM, Simon <mail.sim...@gmail.com> wrote:

Regarding the entityMerge: I'm confused...

You said:
"Hibernate is forced to query and build the object graph again". Do
you mean to query the database?

Because I don't have the same understanding, regarding the hibernate
doc:
http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/objectstate.html#d0e1318
"the merged objects state overrides the persistent entity state in the
persistence context"


Well, you asked whether you should ALWAYS use EntityMerge(). I would say not unless you need to, because if there is not an entity already in the persistence context, Hibernate has to create one.
 
First, let's make a statement: Because we are in the context of RIA,
Flex in this case, all object send back from Flex to CF are object
detached from the Hibernate session (hibernate session lives only
inside one CF request). In this particular context my question make
sense: should we always use entityMerge when dealing with Flex,
detached objects?


When dealing with objects from a Flex application, yes, it can be very useful to use EntityMerge() since anything you send back to the server will be detached.

Hope that helps,

Brian

Simon

unread,
Apr 20, 2010, 10:30:08 PM4/20/10
to cf-orm-dev

I was focusing on updating, that's right.

It make much more sense now, thanks Brian.

Simon



On Apr 21, 11:15 am, Brian Kotek <brian...@gmail.com> wrote:
> On Tue, Apr 20, 2010 at 8:56 PM, Simon <mail.simonlen...@gmail.com> wrote:
>
> > Regarding the entityMerge: I'm confused...
>
> > You said:
> > "Hibernate is forced to query and build the object graph again". Do
> > you mean to query the database?
>
> > Because I don't have the same understanding, regarding the hibernate
> > doc:
>
> >http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/htm...
Reply all
Reply to author
Forward
0 new messages