Sometimes rather than writing this:
var customer = ctx.Customers.First(c => c.ID == 5);
You would rather write something like this:
var customer = ctx.Customers.GetCustomerById(5);
In .NET 4.0 this would be trivial to do by modifying the T4 templates that do code gen. You would simply produce an extension method for each EntityType, something like this:
public static Customer GetCustomerById( this ObjectQuery<T> query, int Id ) { return query.First(c => c.ID == Id); }
This is fine, but is there a way to support this without resorting to a method for each Type?
There is indeed an approach that is more general purpose, it isn’t type safe, but it work great nevertheless.
The core to the idea is to use eSQL to build a query. This function will work in both 3.5 and 4.0:
public static T Get<T, K>(this ObjectQuery<T> query, K key) { //Get the EntityType EntityType entityType = query.Context.MetadataWorkspace .GetCSpaceEntityType<T>(); if (entityType.KeyMembers.Count != 1) throw new Exception("You need to pass all the keys"); //Build the ESQL string eSQL = string.Format("it.{0} = @{0}", entityType.KeyMembers[0].Name); //Execute the query return query.Where( eSQL, new ObjectParameter(entityType.KeyMembers[0].Name, key) ).First(); }
So how does it work?
And we are done.
Now you can write this:
Customer c = ctx.Customers.Get(5);
Now a word of warning, this method isn’t type safe, so this will compile:
Customer c = ctx.Customers.Get(“Some Random String”);
Even though Customer has an integer key. You will only notice the error at runtime when the eSQL is parsed.
This doesn’t support compound keys, but it would be pretty easy to add more overloads that accept more parameters.
I’ll leave that as an exercise for the reader!
This is 25th post in my ongoing series of Entity Framework Tips.