Hi, on the child side of a FK relation I want to map both the parent entity and the FK field itself. Example: Order { ID, CustomerID }, Customer { ID, Name }

My Order entity shold look like:

class Order { int CustomerID; Customer Customer; }

This is important as I am migration from Linq2Sql which generates classes following this pattern. I could do:

public int CustomerID { get {return Customer.ID; }}

However this is not an option as this would fetch the Customer from the database even if only his ID is required. How would I map this scenario?

thanks, tobi


Updated at 31.07.2010 18:10:43

Great! I thought only NHibernate hat that feature but you have it too. I currently have:

public int CalendarID
        {
            get { return Calendar.Key.Value.GetValue<int>(0); }
            set { Calendar = Query.Single<Calendar>(Key.Create(typeof(Calendar), value)); }
        }

which is working fine as it seems. Would you recommend this solution to others or could it be improved?

tobi


Updated at 02.08.2010 14:38:35

Ok, I wasn't seeing the fetch in sql profiler because the property was already loaded by previous code...

get { return GetReferenceKey(TypeInfo.Fields["Calendar"]).Value.GetValue<int>(0); }

I misunderstood your first post: I thought that entities are always lazily loaded even if you get a reference to them or access their ID property. That is how it works in NHibernate: Only accesses to non-key properties trigger a load from the database. Look at the code snippet in http://ayende.com/Blog/archive/2009/04/ ... ng-by.aspx. The call to Load never goes to the database. Might be a nice feature in DO.NET...

Now, how do I assign the CalendarID eg. write the setter without loading the entity from the database? This is important because I am migrating from L2S which allows to do that so I was relying on it.


Updated at 02.08.2010 18:59:25

I agree with both your an Ayendes reasoning. There are tradeoffs involved when picking the solution. I think there are situations where you would never want a proxy and situations where you can afford it. Why don't you just make it configurable? Then you would make all those NH user quiet who probably are laughing because you don't have their nice feature.

I personally would opt for proxies to increase performance and ease development.

This thread was imported from our support forum. The original discussion may contain more detailed answer.

asked Jul 31 '10 at 14:05

tobi's gravatar image

tobi
13556

edited Sep 03 '10 at 15:48

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412


One Answer:

I'm going to surprise you :) :

  • If you create a property of Entity type, it is always lazy in DO. So no additional (pre)fetches will happen by default. Take a look at SQL Server Profiler trace. That's one of advantages of having different internal Entity state representation.

  • On the other hand, key of this Customer will be fetched on Order fetch. To get its Key, use Session.Services.Get<directpersistentaccessor>().GetReferenceKey method.


Forgot to add: to ensure Order.Customer is loaded along with some query returning Order objects, use: 1) either .Select(order => new {order, customer = order.Customer}) - in this case it will be fetched along with your query (btw, and will be available via order.Customer) 2) or use .Prefetch method(s) - this is described in Manual.


We use different approach, and actually there is strong reasoning about this. Read my comments to this post of Ayende:

Frankly speaking, I just didn't want to argue about this - our view on this issue seems completely opposite. Earlier we had an argue with Oren about exactly the same case:

As far as I remember, there was a continuation via e-mail, but anyway, the idea is clear. Few more posts:

Some consequences related to DO4:

  • If DO creates Entity instance, it is always of correct type, even with polymorphic queries / properties.

  • We may return a removed instance (entity.IsRemoved==true) for non-polymorphic property (= hierarchy with just one type), although this is fully up to us. I.e. if instance is really removed, you can get null as well, if this is already known there is no such instance.

  • Note that accessing Entity.IsRemoved property may lead to entity state loading.

  • On contrary, accessing Entity.Key property never leads to state loading.

  • The best way to check if entity is removed is to invoke EntityExtensions.IsRemoved() extension method - is checks for null as well.


See this comment as well, it describes some consequences of returning base type's proxy instead of proxy of correct type:


Actually, I can't imagine what we must do if Entity of wrong type is replaced by correct one, when type becomes known:

  • Must the old entity stop working at all?

  • Must it still work? If so, how to sync the changes between it and the actual one?

  • Finally, I strongly dislike violation of identity principal here: while e1!=e1, e1.Key==e1.Key for these entities, and IMHO, that's deeply wrong.

Actually, there is a good solution of this problem: don't use inheritance, if you want to avoid this. Or, more precisely, use hierarchies with just one type. It's precisely known there are no any trade-offs in this case. But if there is inheritance, you'll anyway get some of them.


Btw, today he published one more good post: http://ayende.com/Blog/archive/2010/08/ ... witch.aspx

How this is applied to this case? Well, inheritance is a leaky abstraction in case with databases. In fact, it's simulated, but not supported directly, so you must be aware about possible side effects of this.


And concerning supporting proxy-related features of NH: this is pretty far from concepts we're implementing. Such things can be done, but: a) Likely, not many people will really use them; the alternative is already available, so "doing this in NH way" is just one more approach b) We're trying to avoid the case when concept gets "dissolved" in features during implementation. So "fitting well" is one more factor we consider.

answered Jul 31 '10 at 15:48

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

No, this should be improved to the solution I proposed: you're reading Calendar field here, which may (at least, in many cases) lead to lazy fetch of Calendar instance.

(Jul 31 '10 at 15:48) Alex Yakunin Alex%20Yakunin's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×573
×12
×11
×3

Asked: Jul 31 '10 at 14:05

Seen: 3,724 times

Last updated: Sep 03 '10 at 15:48

powered by OSQA