In previous post I left to the reader the task to build a LoadByKey extension method to make it easy loading entities by key in project with entity framework, I think that is quite interesting to spent a little bit on in. First of all I suggest you to read this post about metadata and Entity Framework, this post suggested me this solution.

1 public static T LoadByKey<T>(this ObjectContext context, params Object[] keyValue) 2 { 3 EntityType type = (from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace) 4 where meta.BuiltInTypeKind == BuiltInTypeKind.EntityType 5 select meta) 6 .OfType<EntityType>() 7 .Where(e => e.Name == typeof(T).Name).Single(); 8 IEnumerable<KeyValuePair<string, object>> entityKeyValues = 9 type.KeyMembers.Select((k, i) => new KeyValuePair<string, object>(k.Name, keyValue[i])); 10 11 EntityKey key = new EntityKey(context.GetType().Name + "." + typeof(T).Name, entityKeyValues); 12 return (T)context.GetObjectByKey(key); 13 }

In line 3 I begin a query to load the EntityType object related to the type of object I need to load. The System.Data.Metadata.Edm namespace is a place where you can find plenty of information about how your data is structured. I simply query the MetadataWorkspace getting the items of type DataSpace.CSpace or the Conceptual Model. The Conceptual model can be tricky to use, to familiarize with it I suggest you to use LINQPad to run the query of line 3, you get this result (all properties collapsed)

image

Now you can simply suppose that KeyMembers property of an entityType contains all the KeyProperties, if you expand it you will see this result

image

YATTA! This permits me to find name/s of key properties and I can use LINQ to create desidered EntityKey (line 8-11)

IEnumerable<KeyValuePair<string, object>> entityKeyValues = type.KeyMembers.Select((k, i) => new KeyValuePair<string, object>(k.Name, keyValue[i])); EntityKey key = new EntityKey(context.GetType().Name + "." + typeof(T).Name, entityKeyValues);

Ok, this code could be made more efficient avoiding the call to GetType and Metadata for each call, you can use static variables or you can use cache to store the list of KeyProperty for each object in a dictionary or similar structure. Now you can use this code to load entities knowing their keys

Order_Details c = context.LoadByKey<Order_Details>(10248, 11); Console.WriteLine(c.UnitPrice); Customers cust = context.LoadByKey<Customers>("ALFKI"); Console.WriteLine(cust.ContactTitle);

It works for entities with single property key as well as entities like Order_Details that have multiple keys; in this scenario you should pay a lot of attention to the order in witch the keys are declared to avoid confusion.

alk.

Tags:

5 Responses to “Extension method to add LoadByKey to EntityFrameworks context”

  1. I need something similar in VB.NET. Can you post an example in VB? Having some difficult converting.

  2. It is more difficult to have the same result for visual basic, because it is less expressive with lambda function, but you could include extension functions in a c# project and use it in vb with no problem.

    Alk.

  3. How about a version that takes an EntityObject type that is not known at compile time?

  4. If you do not know the object at compile time it would be really difficult. You can create a different version of the function just removing the T parameter that accepts a Type parameter that you can specify at run-time, But I never tried :)

    Alk.

  5. I removed and added EntityObject entityObject to method sig and replaced typeof(T) with entityObject.GetType() and it seems to work. Thanks!