“Local” Queries

Quite some time ago I wrote a blog post about the fact that EF queries execute at the database rather than locally which means that if you add an object to the context or you modify an object already attached to the context, then a query won’t be based on the local data.

Earlier today another blogger called this a “disappointing behavior” . Since I hate for the EF to disappoint folks, I thought I’d whip up a small extension method to help:

public static IEnumerable<T> Local<T>(this ObjectContext context,

                                     string entitySetName) where T : class

{

   return from stateEntry in context.ObjectStateManager

                            .GetObjectStateEntries(EntityState.Added |

              EntityState.Modified |

                                                           EntityState.Unchanged)

           where stateEntry.Entity != null && stateEntry.EntitySet.Name == entitySetName

  select stateEntry.Entity as T;

}

To use this, you just need to supply the type and the entity set name:

foreach (Customer c in ctx.Local<Customer>("Customers"))

{

    Console.WriteLine(c.ContactName);

}

In .Net 4.0 we will be adding a new type ObjectSet<T> which inherits from ObjectQuery<T> and provides methods for things like adding, attaching, deleting, etc. entities to the entity set which it represents. The default codegen will put instances of ObjectSet<T> on the context rather than ObjectQuery<T>. So, once .Net 4.0 ships we can change the extension method to:

public static IEnumerable<T> Local<T>(this ObjectSet<T> objectSet) where T : class

{

   return from stateEntry in objectSet.Context.ObjectStateManager

  .GetObjectStateEntries(EntityState.Added |

                                                              EntityState.Modified |

                                                              EntityState.Unchanged)

           where stateEntry.Entity != null && stateEntry.EntitySet == objectSet.EntitySet

           select stateEntry.Entity as T;

}

And then you won’t need to specify either the type or the entity set name but rather call the extension method on the object set so that you get a nicer usage pattern:

foreach (Customer c in ctx.Customers.Local())

{

    Console.WriteLine(c.ContactName);

}

- Danny