Udostępnij za pośrednictwem


Tip 24 – How to get the ObjectContext from an Entity

Customers often ask how to get from an Entity back to the ObjectContext .

Now generally we don’t recommend trying this. But sometimes you really need a way to get to the ObjectContext.

For example if you are in method and all you have is the Entity, and you need the ObjectContext perhaps to do some extra queries etc.

One option is to change the method signature so callers have to pass in the ObjectContext whenever this method is called. Unfortunately changing the signature like that is not always possible, especially if you are implementing some persistent ignorant interface, a Repository for example or  if doing so causes cascading changes all over your code base, yuck.

Another option is to put the ObjectContext in a thread local variable. Similar to the way HttpContext.Current works.

But both of these solutions might not be available to you…

Caveats:

Before I get to the solution a couple of important Caveats are in order:

Caveat #1: This solution only works if the Entity has at least one relationship.

Caveat #2: This solution won’t demonstrate ideal performance characteristics, because although we are just getting the Context, it calls a number of intermediary methods that involve some lookups / calculations:

Caveat #3: This won’t work with Detached entities. Although surprisingly it does work with NoTracking queries, you might have thought that NoTracking entities are essentially Detached, but that is not strictly true. Even though NoTracking queries aren’t tracked, relationship loading still works for then, and that is what we use.

Caveats CHECK…

You’ve been warned!

Workaround:

The solution relies on a single extension method:

public static ObjectContext GetContext(
this IEntityWithRelationships entity
)
{
if (entity == null)
       throw new ArgumentNullException("entity");

var relationshipManager = entity.RelationshipManager;

var relatedEnd = relationshipManager.GetAllRelatedEnds()
.FirstOrDefault();

if (relatedEnd == null)
throw new Exception("No relationships found");

var query = relatedEnd.CreateSourceQuery() as ObjectQuery;

if (query == null)
throw new Exception("The Entity is Detached");

return query.Context;
}

How does it work?

Well in .NET 3.5 all entities with relationships implement IEntityWithRelationships, in fact even in EF4 if you have a ChangeTracking Proxy for a POCO Entity the proxy implements IEntityWithRelationships too.

From there you can access the RelationshipManager and get the first RelatedEnd, it doesn’t matter which end we choose, because we don’t care about the actual end, it is just a means to an end.

From the RelatedEnd you create, but not execute, an ObjectQuery to load the related Entity(s). If you get null it is because the Entity is detached from the ObjectContext and as I said in the Caveats you are out of luck.

Finally from the query you can get the ObjectContext.

With this extension in place you simply do this:

ObjectContext context = myEntity.GetContext();

You probably want your strongly typed Context… well that is no problem either:

MyContext context = myEntity.GetContext() as MyContext;

Easy Peasy Lemon Squeazy.

This is 24th post in my ongoing series of Entity Framework Tips.

Comments

  • Anonymous
    June 08, 2009
    PingBack from http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx
  • Anonymous
    June 11, 2009
    Hi,Will the next release (.NET 4??) of Entity Framework provide this in a more fundamental fashion.Maybe as a property like EntityObject.ObjectContext?
  • Anonymous
    June 11, 2009
    BingoWe are thinking about adding something, probably a static method on ObjectContexti.e.ObjectContext context = ObjectContext.GetContext(entity);But we need to weigh that up against a lot of other competing ideas, so it might not make it.Alex
  • Anonymous
    September 11, 2009
    Thanks a lot for your tips.I realy enjoy your blog.Easy Peasy is not not sometimes easy ;-)
  • Anonymous
    December 28, 2009
    A related issue is that once an entity is detached from context, it loses all the relationship. This is due to the fact that the relationships are tightly coupled to EF. Hopefully EF2 addresses this in a more POCO-friendly fashion.
  • Anonymous
    November 16, 2010
    I have been trying a way to do this for nearly TWO DAYS now and finally came upon your post - AND IT WORKS!!! Thank-you, thank-you, thank-you.My scenaria...I have a bunch of navigation properties that each have the TypeConverter attribute attached to the relevant partial classes to be able to perform combobox lookups in a PropertyGrid. I needed to be able to find out the ObjectContext from the context.Instance passed in at GetStandardValues so I could do the lookup.My initial solution was to create a static property in my application that returned the ObjectContext but after lots of reading on EF4 (I am new to it) I have come to the conclusion it is not wise to keep the ObjectContext alive for the life of the application.So I wanted to create an ObjectContext per form and dispose it when the form closes, but then had no way to access the same ObjectContext for lookup queries for the navigation properties.  And I could not create a new one as you get the good old "different contexts" when a user selects a different item from the combobox.But... Now all is working perfect. You solution is perfect. Thanks BIG time :)
  • Anonymous
    April 12, 2011
    Thanks a lot.Getting the context of an entity was pretty useful to me, to be able to see if the underlying objectcontext has been disposed (and then handle it accordingly). Thanks for the article.