Welcome to MSDN Blogs Sign in | Join | Help
New EF blogger – Craig Lee

Short one this time.

Craig Lee, a colleague of mine who works on the tools team, has just started blogging. He already has a number of posts, including an interesting one on keyboard shortcuts.

Enjoy.

Tip 26 – How to avoid database queries using Stub Entities

What are Stub Entities?

A stub entity is a partially populated entity that stands in for the real thing.

For example this:

Category c = new Category {ID = 5};

is a stub entity.

It has only the ID populated, which indicates this is a stub for Category 5.

When are Stub Entities Useful?

Stub Entities are useful whenever you don’t really need to know everything about an entity, primarily because by using them you can avoid superfluous queries, but also because they are a lot easier to use than EntityKey.

Here are some examples:

Scenario 1 - Building a relationship using a Stub Entity:

This is probably the most common use of Stub Entities, lets say you want to build a relationship between a new product and an existing category, if you know the existing category has ID = 5, by default you would do this:

Product p = new Product {
     Name = “Bovril”,
     Category = ctx.Categories.First(c => c.ID == 5)
};
ctx.AddToProducts(p);
ctx.SaveChanges();

But this does a database query for the category, which is superfluous if all you are doing is building a relationship. You don’t need the whole entity, you already know all you need (the ID), so you can rewrite this to use a Stub Entity:

Category category = new Category { ID = 5};
//see tips 13 and 16 if you don’t like the string here!
ctx.AttachTo(“Categories”,category);

Product product = new Product {
     Name = “Bovril”,
     Category = category
};
ctx.AddToProducts(product);
ctx.SaveChanges();

And as a result you save a database query.

Note: You can use this approach to build new relationships via collections too.

Scenario 2 – Delete using a Stub Entity:

The standard way to do a delete looks like this:

Category category = ctx.Categories.First(c => c.ID == 5);
ctx.DeleteObject(category);
ctx.SaveChanges();

The first line is a query, to get an ‘full’ entity, but you can do a delete with a simple stub if the entity has no references to other entities:

Category category = new Category { ID = 5 };
ctx.AttachTo(“Categories”,category);
ctx.DeleteObject(category);
ctx.SaveChanges();

Again using a stub saves a query.

Scenario 3 – Delete a Stub Entity with References

If however the entity you want to delete has a reference (i.e. a product has a Category) the Entity Framework needs to know* about the reference in order to delete. Now if you do a query to get the entity you want to delete the EF gets this extra information automatically using a feature called relationship span.

But again we want to save the query, by using a stub entity we can tell the EF about the relationship using, you guessed it, another stub entity:

Product product = new Product {
     ID = 5, 
     Category = new Category { ID = 5 }
}
;
ctx.AttachTo(“Products”,product);
ctx.DeleteObject(product);
ctx.SaveChanges();

And here by using two stub entities, we’ve again saved a query

* In .NET 4.0 is you use FK associations, this no longer true. The Entity Framework will happily delete without knowing about the references. As Roger Jennings would say hoorah.

Scenario 4 – Delete a Entity with a Timestamp

If an entity has a column used in concurrency token, generally this is a timestamp, you need to provide that value too, when you create the stub:

Order order = new Order{
      OrderNo = 3425,
      Timestamp = timestamp,
      Customer = new Customer { ID = 7}
};
ctx.AttachTo(“Orders”, order);
ctx.DeleteObject(order);

Used a stub, saved a query.

Scenario 5 – Update an Entity

If you want to update an entity, you just need to attach something that represents the original version of the entity, and again that is where stubs come in:

Person person = new Person{
      ID = 65,
      Firstname = “Jo”,
      Surname = “Andrews”
};
ctx.AttachTo(“People”, person);
person.Surname = “James”; // Yes my wife took my surname!
ctx.SaveChanges();

Used a stub check, saved a query check!

Summary

5 scenarios and 5 saved queries so as you can see Stub Entities are super useful.

Not only do they save database queries, which will make your apps perform and scale better. They also make your code more readable compared to the EntityKey alternatives.

The general pattern for using them is pretty simple too:

  1. Construct a stub Entity with the fields you need.
  2. Attach the stub Entity
  3. Do what you need to (Build Relationship, Delete, Update etc)

Let me know if you have any questions.

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

Wrapping Providers

For well over a year now I've been talking about how it is possible with EF to write a provider that sits between the EF and the native database provider.

There are lots of reasons why you might do this. Here are some examples, you could write a:

  • Tracing Provider
  • Auditing Provider
  • Caching Provider
  • Query Optimizing / Query Substitution Provider
  • Distributed Query Provider????
  • etc

Well Jarek has put his money where my mouth was ;)

He is a team mate on the EF team and he has just released two sample wrapping providers, one that does tracing and one that does caching using Velocity (cool), here on Code Gallery.

If you want to find out more go check out his blog post

Tip 25 – How to Get Entities by key the easy way

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?

General Purpose Solution

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?

  1. It uses the GetCSpaceEntityType<T>() extension method I wrote in Tip 13, to get the EntityType for T.
  2. Once we have the EntityType we check that we have the right number of parameters, i.e. this method only accepts one key value, so the EntityType in question must have a simple single column key.
  3. Then we generate a piece of eSQL to modify the where clause of the query. For example if you are looking for a customer and the key is ID we will generated “it.ID = @ID”.
  4. Next we create an ObjectParameter for the parameter we referenced in the above eSQL, the value of the parameter comes from the methods key parameter.
  5. Finally we execute the query and get the First() result. In 4.0 you should change this to use Single() but that isn’t supported in 3.5.

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.

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.

Tip 23 – How to fake Enums in EF 4

As of right now Enums are not in EF4.

Now we will be listening to your feedback about Beta1, and making some adjustments, so you never know, but at the moment it doesn’t look like they will be supported.

Yesterday though I came up with a workaround that, while a bit of work, is pretty interesting.

Workaround

To get this working you need .NET 4.0 and you need to use POCO classes.

Imagine you have an Enum like this:

public enum Priority

   High,
   Medium,
   Low
}

First step is to create a ComplexType with just one property, something like this:

<ComplexType Name="PriorityWrapper" >
          <Property Type="Int32" Name="Value" Nullable="false" />
</ComplexType>

Then if you want to have a property in an Entity that returns an Enum instead use the wrapping ComplexType.

As I said this only works in POCO. The reason is you need to do some interesting things in your PriorityWrapper complex type class:

public class PriorityWrapper
{
   private Priority _t; 
   public int Value {
      get {
         return (int) _t;
      }
      set {
        
_t = (Priority) value;
      }
   }
   public Priority EnumValue
   {
      get {
         return _t;
      }
      set {
         _t = value;
      }
   }
}

Notice it has a Value property of type int just like the ComplexType definition, but it also has a way to set and get the Priority too via the EnumValue property.

Now we have this class we can use it in our POCO entities, so for example imagine you have a Task entity:

public class Task
{
    public virtual int Id { get; set; }
    public virtual PriorityWrapper Priority { get; set; }
    public virtual string Title{ get; set;}
}

The next step is interesting, add some implicit conversion between PriorityWrapper and Priority:

public static implicit operator PriorityWrapper(Priority p) 
{
   return new PriorityWrapper { EnumValue = p };
}

public static implicit operator Priority(PriorityWrapper pw)
{
   if (pw == null) return Priority.High;
   else return pw.EnumValue;
}

With these implicit conversions in place you gain the illusion that the Priority property on the Task class is actually a Priority.

For example you can do this:

Task task  = new Task {
   Id = 5,
   Priority = Priority.High,
   Title = “Write Tip 23”
};

Rather than this needing to do this:

Task task  = new Task {
   Id = 5,
   Priority = new PriorityWrapper {EnumValue = Priority.High },
   Title = “Write Tip 23”
};

And this:

if (task.Priority == Priority.High)

Rather than this:

if (task.Priority.EnumValue == Priority.High)

But what about queries?

You can even use this enum in queries:

var highPriority =
            from task in ctx.Task
            where task.Priority.Value == (int) Priority.High
            select task;

Cool huh?

Now this is not as good as if we natively supported enums, but it is not that far off, especially from the perspective of someone programming against your entities.

Enjoy.

This is 23rd post in my ongoing series of Entity Framework Tips.

Ordering of Commands – What do you think?

Some of our customers write code like this:

ctx.AddToCustomers(customer);
ctx.AddToProducts(product1);
ctx.AddToProducts(product2);

And expect the Entity Framework to issue 3 insert commands in the same order.

Today the EF doesn’t preserve this sort of ordering.

Instead the order inserts/updates and deletes are made in the Entity Framework is based mainly on local inter-dependencies.

For example if you insert a new Product in a new Category we have to add the Category before the Product .

This means that if you have a large set of changes there are local ordering constraints that we must satisfy first, and these rules can easily be in conflict with order things actually happen in the ObjectContext.

For example if you do this:

ctx.AddToProducts(
   new Product{
      Name = "Bovril",
      Category = new Category {Name = "Food"}
   }
);

the effect is that the Product is added (to the context) first and then when we walk the graph we add the Category too.

i.e. the insert order into the context is:

Product
Category

but because of referential integrity constraints we must re-order like this before attempting to insert into the database:

Category
Product

So this kind of local re-ordering is kind of non-negotiable.

However if there are no local dependencies like this, you could in theory preserve the order of changes.

Today though we don't track 'when' something was added to the context or even when something gets modified, and for efficiency reason we don't track entities in order preserving structures like lists. So currently we can't preserve the order of unrelated inserts, updates and deletes etc.

My question to you is how important is this?

Would you like to see us preserve your ordering as much as possible?

Tip 22 - How to make Include really Include

This is 22nd post in my ongoing series of Entity Framework Tips.

If you want to do eager loading with the Entity Framework it is generally really easy, you simply write something like this:

var results = 
        from post in ctx.Posts.Include(“Comments”)
        where post.Author.EmailAddress ==
“alexj@microsoft.com
        select post;

In this example for each post that matches you will get back it’s comments, all in one query, aka Eager loading.

Cool. So far so good.

However if you start to do more interesting queries that change the ‘shape’ of the query, either by introducing an intermediary join or something, maybe like this:

var results =
        from post in ctx.Posts.Include(“Comments”)
        from blog in post.Blogs
        where blog.Owner.EmailAddress == “
alexj@microsoft.com
        select post;

The include no longer works.

Why? 

When the first example is translated into a query the columns that are selected remain the same from start to end. The filter introduces a join but it doesn’t effect which columns are selected, so from the time the Include() is applied until the final select the shape of the query is unchanged.

In the second example when the Include() is applied the query includes just post columns, but then the second from changes the shape to include both post and blog columns. i.e. the shape of results changes, albeit temporarily, and this temporary shape change stops Include() working.

Now in this particular example you can re-write the query like this, to get it working again:

var results =
        from post in ctx.Posts.Include(“Comments”)
        where post.Blogs.Any(
             b => b.Owner.EmailAddress == “
alexj@microsoft.com
        )
        select post;

…and it will work again. Because the query has been rewritten to avoid changing the shape, from the time the Include() is applied until the end.

Unfortunately this type of workaround though change is somewhat invasive because it forces you to change how you write your queries just to get include working.

There is however a better option.

Workaround

The workaround is actually pretty simple, you just move the Include to the end of the query.

var results =
        ((from post in ctx.Posts
        from blog in post.Blogs
        where blog.Owner.EmailAddress ==
“alexj@microsoft.com
        select post) as ObjectQuery<Post>).Include(“Comments”);

For this to work your final select must be entities, i.e. select post rather than select new {…}, if so you can cast the result to an ObjectQuery, and then do the include.

This works just fine, because between when the include is applied and the end of the query the shape remains the same.

An enumeration of one?

Having something enumerable is the gateway to all LINQ’s loveliness.

But sometimes you have just one object.

So how do you make that enumerable?

var people = new Person[] {person};

Not exactly hard huh?

In fact you can simplify this even more, you can replace new T[] with just new [] like this:

var people = new [] {person};

And the compiler will infer the type of the array for you.

At this point you can start treating your object as a enumeration, and gain all the benefits of the collection monad, not least of which is delayed execution.

var results = from x in new [] {person}
                 select DoSomethingPrettyCPUIntensive(x);

And notice the expensive operation is only executed if someone actually enumerates the results.

Learn about EF Pluralization Services courtesy of Dan Rigsby

Not long ago I wrote a ‘sneak peek’ for our new Pluralization features on the ADO.NET team blog. There is a more indepth post coming soon…

But it seems the community is starting to do our education for us, and beating us (or should I say me) to the punch!

Dan Rigsby, who is a WCF MVP, has a fantastic in depth post covering our Pluralization Service features.

His goes deeper that my ‘sneak peek’ by looking at the API and how you can use our built-in en-us PluralizationService in your code, his post even shows how you can even add custom pluralizations.

Check it out.

Tip 21 – How to use the Single() operator – EF 4.0 only

This is 21st post in my ongoing series of Entity Framework Tips, and the first that is specific to EF 4.0.

Entity Framework 4.0 Beta 1

As you’ve probably heard VS 2010 Beta 1 is now available to subscribers which means some of you can get your hands on EF 4.0 Beta 1 too. If you have any questions our new pre-release forums are here.

Support for Single() and SingleOrDefault()

One thing we’ve added is support for LINQ’s Single() operator.

The expected semantics of this method is that if there is not exactly one match it will raise an exception. For example this:

var person = (from p in ctx.People
              where p.Firstname == “Alex”
              select p).Single();

Will throw an exception both if no matches are found or if more than one match is found.

We’ve also added support for SingleOrDefault() too. Which is slightly different, it means there should be at most one match, meaning it is okay for there not to be a match.

How it is implemented

Someone in the forums had already noticed that we had added support for Single() and noticed that the T-SQL issued is a TOP(2) query, i.e. something like this:

SELECT TOP (2) …
FROM [dbo].[People] AS [Extent1]
WHERE N'Alex' = [Extent1].[Firstname]

As Matthieu notes in his answer in the forums this makes perfect sense if you think about it. We have to get the first two results (and no more) to know whether we should throw an exception, if the resulting DataReader has 2 rows rather than just 1, it is exception time!

Tip 20 – How to deal with Fixed Length Keys

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

Fixed Length Field Padding:

If you have an fixed length column in the database, for example something like NCHAR(10) when you do an insert, padding happens automatically. So for example if you insert ‘12345’ you get 5 spaces automatically appended, to create a string that is 10 characters long.

Most of the time this automatic padding doesn’t matter. But if you use one of these Columns as your Primary Key with the Entity Framework you can run into trouble with identity resolution.

So what is Identity Resolution?

Identity Resolution is an important feature that most ORMs support. It insures that you only ever have one object in memory for each ‘Entity’ in the database.

So if already have an object in the ObjectContext that represents a particular ‘Entity’ and you issue another query for that ‘Entity’ the query should return the same object again, rather than creating another object.

This is important because it stops you getting into situations where you make multiple contradictory changes to the same ‘Entity’ via different objects.

So how can things go wrong?

Things are highly unlikely to go wrong for you, but it is possible. Here’s how…

In the Entity Framework we do ‘Identity Resolution’ based on the value of the EntityKey (aka the Primary Key) in the CLR and we don’t do any automatic padding for you, unlike the database.

What this means is if you write this code where the ProductCode is the primary key of the Product entity and is NCHAR(10):

Product p1= new Product
{
    ProductCode = "SG500",
    Description = "7200rpm 500 GB HDD"
};
ctx.AddToProducts(p1);
ctx.SaveChanges();

The EntityKey in memory is ‘SG500’. But in the database you get ‘SG500     ’.

Now if you write a query like this:

Product p2 = ctx.Products.First(p => p.ProductCode == "SG500");

Because of SQLServer query semantics this will match the ‘SG500     ’ record in the database, and the resulting ‘Entity’ will have an EntityKey of ‘SG500     ’.

If this query is run against the same ObjectContext identity resolution should kick in and return p1 instead of creating a completely new object, i.e. this shouldn’t fail:

Debug.Assert(Debug.ReferenceEquals(p1, p2));

Unfortunately this isn’t the case because p1 has an EntityKey of ‘SG500’ and p2 has an EntityKey of ‘SG500     ’, which when compared using CLR semantics are clearly not identical. So Identity Resolution Fails, and you end up with different objects.

By this point you may be starting to see how unlikely you are to run into this scenario. It only really matters if you create and later query and modify the same entity via the same context, if you do that it probably means you have a long running ObjectContext, which is not what we generally recommend.

Nevertheless the point of this whole discussion is that while unlikely things might go badly wrong, and it is better to be forewarned.

Guaranteeing you avoid Identity Resolution Problems:

The solution to all this is remarkably simple. When you create your entity for the first time (or attach it) simply pad the key yourself. i.e. something like this:

Product p1= new Product
{
    ProductCode = "SG500     ",
    Description = "7200rpm 500 GB HDD"
};

You might even want to create a little utility method to do the padding for you:

ProductCode = Pad(“SG500”,10);

If you do this the Entity Frameworks Identity Resolution code will work just fine.

I highly recommend being defensive like this if you use fixed length Primary Keys with the Entity Framework.

Tip 19 – How to use Optimistic Concurrency with the Entity Framework

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

Background:

If you have a table with a timestamp column, and you reverse engineer an Entity from that table, you will end up with a Binary property in your entity (in my example called Version).

If you look at the properties window for that property you will see something like this:

ConcurrencyModeFixed

The interesting thing here is the Concurrency Mode. The Entity Framework support 2 Concurrency Modes:

  • None – This is the default and means the property is not involved in any concurrency checks
  • Fixed – Which means that the original value of this property is sent as part of the WHERE clause in all updates or deletes

So timestamps have a Concurrency Mode of Fixed, which means the original value loaded from the database is included in the WHERE clause of any Updates or Deletes.

If you delve a little deeper by looking at the Storage Model (aka SSDL), which you can see if you open your EDMX in the XML editor, you will notice something else, namely that the Version property has a StoreGeneratedPattern of Computed.

There are 3 possible StoreGeneratedPatterns:

  • None – This is the default and by far the most common. It means that this column is not generated in the database.
  • Identity – This means that when the EF does inserts the database will generate a value. So after an insert the EF will get the generated value and feed it back into the Entity. This setting is frequently used for primary keys that are automatically generated in the database.
  • Computed – This means that whenever the EF does insert OR update the store will generate a new value. So the EF will feed the generated value back into the entity after both inserts AND updates. Yes you guessed it this is generally used for things like Timestamps.

So because timestamps have a StoreGeneratedPattern of Computed, whenever the EF Inserts or Updates an entity with a timestamp column it will automatically get the latest timestamp value and feed it back into the Entity.

Handling Optimistic Concurrency Exceptions:

In the example below I have an Entity called Post that has a timestamp column called Version. Given that this simple code:

using (TipsEntities ctx1 = new TipsEntities())
{
    // Get a post (which has a Version Timestamp) in one context
    // and modify.
 
    Post postFromCtx1 = ctx1.Post.First(p => p.ID == 1);
    postFromCtx1.Title = "New Title";

    // Modify and Save the same post in another context 
    // i.e. mimicking concurrent access.
    using (TipsEntities ctx2 = new TipsEntities())
    {
        Post postFromCtx2 = ctx2.Post.First(p => p.ID == 1);
        postFromCtx2.Title = "Newer Title";
        ctx2.SaveChanges();
    }
    // Save the changes... This will result in an Exception
    ctx1.SaveChanges();
}

… will cause an OptimisticConcurrencyException:

OptimisticConcurrencyExceptionHeader

… now if we delve a little deeper, by clicking ‘View Detail’ you will see that the OptimisticConcurrencyException gives you access to the ObjectStateEntry(s)associated with the Entity(s) that caused the concurrency exception via the StateEntries property:

OptimisticConcurrencyException

Which means that if you want to handle this sort of situation gracefully you simply trap the OptimisticConcurrencyException and grab the Entity(s) related to those StateEntries so you can provide some sort of message:

catch (OptimisticConcurrencyException ex) {
    ObjectStateEntry entry = ex.StateEntries[0];
    Post post = entry.Entity as Post;
    Console.WriteLine("Failed to save {0} because it was changed in the database", post.Title);
}

Pretty simple if you ask me.

Of course in the real world things are seldom this simple. Your requirements probably states that you have to give the user the ability to compensate and retry. How do you do that exactly?

Well that is definitely an interesting scenario, so expect another tip soon.

Tip 18 – How to decide on a lifetime for your ObjectContext

One of the most common questions we get is how long should an ObjectContext should live. Options often cited include one per:

  • Function
  • Form
  • Thread
  • Application

Plenty of people are asking these types of questions, case in point here is a question on Stackflow. I am sure there are many more buried away on our forums too.

This is a classic it depends type of question.

Lots of factors weigh into the decision including:

  • Disposal:
    Cleanly disposing of the ObjectContext and it’s resources is important. It is also significantly easier if you create a new ObjectContext for each Function, because then you can simply write a using block to ensure resources are disposed appropriately:

using (MyContext ctx = new MyContext())
{
  …
}

  • Cost Of Construction:
    Some people are, quite understandably, concerned about the cost of recreating the ObjectContext again and again. The reality is this cost is actually pretty low, because mostly it simply involves copying, by reference, metadata from a global cache into the new ObjectContext. Generally I don’t think this cost is worth worrying about, but as always, there will be exceptions to that rule.
  • Memory Usage:
    The more you use an ObjectContext, generally the bigger it gets. This is because it holds a reference to all the Entities it has ever known about, essentially whatever you have queried, added or attached. So you should reconsider sharing the same ObjectContext indefinitely. There are some exceptions to that rule and a workaround, but for the most part these approaches just aren’t recommended.
    • If your ObjectContext only ever does NoTracking queries then it won’t get bigger because the ObjectContext immediately forgets about these entities.
    • You could implement some very explicit tidy-up logic, i.e. implement some sort of Recycle interface, that iterates through the ObjectStateManager detaching entities and AcceptingChanges(..) to discard deleted objects. Note: I’m not recommending this, I’m just saying it should be possible, I have no idea if relative to recreation it will result in any savings. So this might be a good subject for a future blog post. 
  • Thread Safety:
    If you are trying to re-use an ObjectContext you should be aware that is not thread safe, i.e. similar to the standard .NET collection classes. If you access it from many threads (e.g. web requests) you will need to insure that you synchronize access manually.
  • Stateless:
    If your services are designed to be stateless, as most web services should be, re-using an ObjectContext between requests might not be best because, the leftovers in the ObjectContext from the last call may have subtle effects on your application that you are not expecting.
  • Natural finite lifetimes:
    If you have a natural finite lifetime way of managing an ObjectContext,such as a short lived Form, a UnitOfWork or a Repository, then scoping the ObjectContext accordingly might be the best thing to do.

As you can see there are lots of issues at play.

Most of them tend to point towards a short lived context that isn’t shared.

So that is my recommended rule of thumb.

However as always understanding the reasoning behind a ‘rule of thumb’ will help you know when it is appropriate to go your way.

Tip 17 – How to do one step updates with AttachAsModified(..)

Background:

In Tip 13 - How to Attach the easy way I showed you how to ‘establish’ the EntitySet for a particular CLR Type so you could Attach it.

But in all the tips so far the same basic pattern is used:

  1. Attach the original version of the Entity
  2. Modify it
  3. SaveChanges

I’ve given you tips to make it easier to do (1) see Tip 13 and Tip 16. I’ve also covered the things you need to understand when doing (2) in Tip 7 and Tip 9 respectively.

But what about if you want to merge steps (1) and (2).

I.e. you already have the modified object, and you just want to attach it. Well this is where AttachAsModified(…) comes in.

Solution:

There are two key tasks that we want to handle in one step:

  1. Attach the entity (at this stage the EF thinks it is unchanged)
  2. Mark every property of the entity as modified.

To do this you could use the default entity set idea shown in Tip 13 and add an Extension method directly to ObjectContext.

But instead I’m going to build on the ideas of Tip 16, and add another extension method on ObjectQuery<T>, something like this:

public static void AttachAsModified<TEntity>(
     this ObjectQuery<TEntity> query, 
     TEntity entity) where TEntity : EntityObject
{
    if (query == null) throw new ArgumentNullException("query");
    if (entity == null) throw new ArgumentNullException("entity");
    // Uses method created in Tip 16
    query.Attach(entity);
   
query.Context
         .ObjectStateManager
         .MarkAllPropertiesModified(entity);
}

The Attach(..) method is implement in Tip 16 so now all I need to add is an implementation of MarkAllPropertiesModified(…).

While it uses some obscure code from the bowels of the ObjectStateManager it is actually remarkably simple:

public static void MarkAllPropertiesModified<TEntity>(
     this ObjectStateManager manager,
     TEntity entity) where TEntity : EntityObject
{
    if (manager== null)
        throw new ArgumentNullException("manager");
    if (entity == null)
        throw new ArgumentNullException("entity");

    // get the object state entry for the Entity
    var entry = manager.GetObjectStateEntry(entity);
    
    // use metadata to get all the property names
    // this is quicker and safer than reflection,
    //
because it ignores properties not in the model
    var propNames =
        from x in entry.CurrentValues.DataRecordInfo.FieldMetadata
        select x.FieldType.Name;
    
    // loop over every property and mark it modified
    foreach (var propName in propNames)
        entry.SetModifiedProperty(propName);
}

All it does is find the ObjectStateEntry for the attached entity and loop over all its properties and mark them as modified.

With these extension methods in place I can write code like this:

Customer updatedCustomer = GetUpdatedEntity();
ctx.Customers.AttachAsModified(updatedCustomer);
ctx.SaveChanges();

Very simple isn’t it?

Notice that for the first time I don’t have to phase my changes into before and after attach code. All the interesting changes to my entity are made before attaching it to the context.

This makes it much easier to create layers / tiers etc in your code.

Caveats:

As per usual References or the lack of Foreign Key properties in .NET 3.5 SP1 can cause some problems.

If you want to update the reference properties (i.e: customer.SalesPerson) you will need to re-introduce some before and after attach logic.

Before calling AttachAsModified(...) you can update all the Properties and but not the references. References will need to be their original values, because of the way the Entity Framework deals with Independent Associations. 

Then after calling AttachAsModified(…) you will need to update the references with the latest values, i.e. something like (customer.SalesPersonReference.EntityKey =  … )

See Tip 7 for more on this.

More Posts Next page »
Page view tracker