Avoiding Unnecessary (and Destructive) Cascading Updates on Related Entity

2 views
Skip to first unread message

johnny....@gmail.com

unread,
Apr 25, 2008, 12:00:31 PM4/25/08
to nhusers
Hi. I've asked this before but didn't get any replies, so I'll
rephrase.

If I have a related entity but only know the key of the entity how do
I avoid an update on the related entity's table.

For example, lets say I have 2 entities (from Northwind).

Territory
-----------
Id
Description
RegionId FK

Region
----------
Id
Description

Region contains multiple Territories. The Territory entity has a
Region property.

Let's say, for the sake of argument, I have a TerritoryRepository.

If I want to add/update a Territory but I only know the RegionId, how
do I do the SaveOrUpdate of Territory without prefetching Region.

Territory territory = new Territory("Some Territory", new
Region(regionId);
TerritoryRepository.SaveOrUpdate(territory);

This has the effect of blanking the Region Description because a
cascading UPDATE on Region is called but the Region entity doesn't
have Description set (only Id).

What's the pattern for this scenario? It's pretty common to have to
add/update entities only knowing the key id (perhaps from a dropdown
list).

Thanks, Johnny


Ayende Rahien

unread,
Apr 25, 2008, 12:12:59 PM4/25/08
to nhu...@googlegroups.com
var t = Get<Territory>(territoryId) ?? new Territory();

johnny....@gmail.com

unread,
Apr 25, 2008, 4:04:37 PM4/25/08
to nhusers
I'm not entirely sure I understand, I'm afraid to say.

I'm *assuming* that you are indicating that I should fetch the related
entity (from where?) if I have the ID, otherwise create a new entity.
I'm assuming you mean

var r = Get<Region>(regionId) ?? new Region();

2 things.

One, where does that code go? If it's inside the Territory entity (in
the Region property) then that means that the entity needs to know
about the repository (effectively). Otherwise, it'd be in the service/
client code:

Territory territory = new Territory("Some Territory",
RegionRepository.Get(regionId) ?? new Region();
TerritoryRepository.SaveOrUpdate(territory);

Which leads me to point 2: I'm trying to avoid a prefetch of the
Region, since I know the region ID and I don't need to touch the
Region table, only the Territory table, so the prefetch is a bit/
completely unnecessary and expensive.

Thanks.

On Apr 25, 5:12 pm, "Ayende Rahien" <aye...@ayende.com> wrote:
> var t = Get<Territory>(territoryId) ?? new Territory();
>
> On Fri, Apr 25, 2008 at 7:00 PM, johnny.recip...@gmail.com <

Ben Scheirman

unread,
Apr 30, 2008, 4:53:54 PM4/30/08
to nhu...@googlegroups.com
You need to fetch the region before adding it to the Territory.

var region = _session.Get<Region>(regionId);  //returns the existing region

var t  = new Territory() { Name="my territory", Region = region };
_session.SaveOrUpdate(t); 

You're probably worried about the extra query here, but with session caching it hasn't ever caused me a problem.  (it's likely that the region might already be in the cache).

johnny....@gmail.com

unread,
May 1, 2008, 6:15:02 AM5/1/08
to nhusers
Thanks. It seems unnecessary but if that's the way it works, then
that's the way it works.

I ended up being a bit more brutal about holding references to
entities outside of an aggregate, so instead of holding a reference to
the entity, I'll just keep hold of EntityId in quite a few cases,
where it's not necessary for me to access the related entity very
often.

Cheers.

On Apr 30, 9:53 pm, "Ben Scheirman" <subdigi...@gmail.com> wrote:
> You need to fetch the region before adding it to the Territory.
>
> var region = _session.Get<Region>(regionId); //returns the existing region
>
> var t = new Territory() { Name="my territory", Region = region };
> _session.SaveOrUpdate(t);
>
> You're probably worried about the extra query here, but with session caching
> it hasn't ever caused me a problem. (it's likely that the region might
> already be in the cache).
>
> On Fri, Apr 25, 2008 at 3:04 PM, johnny.recip...@gmail.com <

Ayende Rahien

unread,
May 1, 2008, 6:22:01 AM5/1/08
to nhu...@googlegroups.com
Please note that you can use Load(id), which would return an entity instance but will not hit the DB

Ben Scheirman

unread,
May 1, 2008, 2:30:16 PM5/1/08
to nhu...@googlegroups.com
in the words of kyle baley... "sweet jayzus!"

how is it possible that I never knew that?

Ken Egozi

unread,
May 2, 2008, 12:02:10 AM5/2/08
to nhu...@googlegroups.com

Ayende Rahien

unread,
May 2, 2008, 5:57:00 AM5/2/08
to nhu...@googlegroups.com
Get() will return the object or a null, if it doesn't exists. As such, it must hit the DB (or at least the cache) to ensure that the object exists.
Load() will return the object or throw if it doesn't exists. As such, it can return a proxy without hitting the DB, letting you get an exception at a later date because the object doesn't exists.

session.Save( new Order { Customer = session.Load<Customer>(1) });

Will result in a single INSERT statement, for example.

Ben Scheirman

unread,
May 2, 2008, 11:49:01 AM5/2/08
to nhu...@googlegroups.com
There's no mapping constraint on this right?  Or does your class have to be lazy?

John Chapman

unread,
May 5, 2008, 7:16:22 AM5/5/08
to nhu...@googlegroups.com
Ben,

Yes, you're class needs to be marked as lazy.  Obviously you can't get this behavior without a proxy.  Something which can cause problems if your object model uses inheritance, which i am sure you knew.

John Chapman

Sent from my iPhone

Ben Scheirman

unread,
May 5, 2008, 5:24:40 PM5/5/08
to nhu...@googlegroups.com
Yeah, about 5 seconds after I sent that I thought about it more.  Duh!

;)
Reply all
Reply to author
Forward
0 new messages