Extension method to add LoadByKey to EntityFrameworks context

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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 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)

1
2
3
 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

1
2
3
4
5
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: Entity Framework .NET Framework.