The ObjectContext of Your Desire, Part The Second

In Which We Painlessly Scope the Lifespan of the Entity Framework Context

In the previous post of this pair, we covered where non-barbarian (and non-physicist) developers can hook their business logic code when using the ADO.NET Entity Framework. To round out the set, we will A the frequently-asked Q of when we should instantiate the ObjectContext, and when we should run it out to the curb for the GC. IMHO AFAIK. LOL.

ObjectContext != DbConnection

If you are coming at the Entity Framework from an old-timey ADO.NET perspective, you might align the idea of a data context with that of a data connection. The best way to handle a data connection directly is to enclose it in a using block, which upon its closing brace will pull up its socks and tidy its underlying external resources:

DataTable results = new DataTable();
using (IDbConnection con = GetConnection())
{
    // open the connection
    con.Open(); 
    
    // query the database
    IDbCommand cmd = con.CreateCommand();
    cmd.CommandText = "select * from Employee";
    results.Load(con.ExecuteReader());
}   
// now the connection is closed and 
// ready for garbage collection

While a data context surely uses a data connection or two under the hood, don’t mistake one for the other. The change-tracking mechanism featured in EF bonds a context and its entities like a mother to her babies; when you try to separate one from the other (say, by disposing the ObjectContext with the close of a using block), you may well lose an arm. How, then, can we scope the ObjectContext without defeating the proverbial Wookiee at space-chess, I hear you say?

Go With The Current

In a small Windows-based application, using a single static instance of the ObjectContext is an acceptable plan. This way, changes from different areas of the application can be tracked and saved together, providing a clearer big picture of what your user is up to at any given point. Using a lazy-loading pattern in a static property on the ObjectContext, here’s how we can simplify access to the shared instance of our context:

private static AdventureWorksEntities _current;
/// <summary>
/// Gets the current AdventureWorks ObjectContext for
/// a Windows-based application.
/// </summary>
public static AdventureWorksEntities Current
{
    get
    {
        if (_current == null)
            _current = new AdventureWorksEntities();

        return _current;
    }
}

At some point in your application, you may need to smash this context instance into tiny bits and start over, but for the sake of not boring the other kids in the class to tears, I will leave such a mechanism as an exercise for the reader.

Do You Take Requests?

I like small Windows applications. Small Windows applications are nice. In fact, I’m thinking about dressing up as a small Windows application for Halloween this year. But the majority of my projects these days don’t involve small Windows applications anymore, and I’m willing to wager that you can identify. And we are certainly aware of the perils of spinning up static anything in ASP.NET. So as Web application and/or service developers, we must approach the Entity Framework in a different way in order to remain peril-free.

In order to scale well, as grown-up Web apps and services must, the best lifespan scope for our context is one per HTTP request. We can achieve this by stashing our context in the current HttpContext, like so:

private static AdventureWorksEntities _current;
/// <summary>
/// Gets the current AdventureWorks ObjectContext for
/// a Web-based application.
/// </summary>
public static AdventureWorksEntities Current
{
    get
    {
        // build a unique string to use as a key
        string key = HttpContext.Current.GetHashCode().ToString("x") + "_context";
        
        // if it doesn't already exist, create a 
        // new AdventureWorksContext and add it to the HttpContext
        if (!HttpContext.Current.Items.Contains(key))
            HttpContext.Current.Items.Add(key, new AdventureWorksEntities());

        return HttpContext.Current.Items[key] as AdventureWorksEntities;
    }
}

All Together Now

Being that this is the ObjectContext of your desire, we want it to be defined once in a library that can be shared by both Windows and Web-based apps in an Enterprise situation. Thus, combining the above methods, we arrive at the following:

private static AdventureWorksEntities _current;
/// <summary>
/// Gets the current AdventureWorks ObjectContext for
/// a Windows or Web-based application.
/// </summary>
public static AdventureWorksEntities Current
{
    get
    {
        if (HttpContext.Current != null) // web
        {
            // build a unique string to use as a key
            string key = HttpContext.Current.GetHashCode().ToString("x") + "_context";
            
            // if it doesn't already exist, create a 
            // new AdventureWorksContext and add it to the HttpContext
            if (!HttpContext.Current.Items.Contains(key))
                HttpContext.Current.Items.Add(key, new AdventureWorksEntities());

            return HttpContext.Current.Items[key] as AdventureWorksEntities;
        }
        else // windows
        {
            if (_current == null)
                _current = Create();

            return _current;
        }
    }
}

Lazy Like a Fox

So–a quick sidebar. Have you tried the new version of Entity Framework? You know, the one brought to you by the number 4? Well, the good guys over at Microsoft have now implemented lazy loading for related entities.  Cautious as they are, however, they left it switched off by default. Personally, I am spectacularly lazy and I prefer this feature to be enabled by default.  This is mostly because I was exhausted from doing the IsLoaded/Load dance every time I wanted to explore a related entity outside of a query.

Now, I get that this may cause some of you to fill your shorts with tremblings about performance, but I come from a place of clean and readable code by default, and targeted optimization by exception, where it’s needed. And those among you who have witnessed prematurely optimized code like I have are right there with me.

Get On With It

My point here is this.  Remember in Part the First, when we overrode the OnContextCreated method to add an handler to the SavingChanges event so that we could add custom business logic in the event of a save or delete?  That was awesome.  Well, we can also hook into that same function to tweak our ObjectContext instance with, say, our pet non-default preferences.  Full shorts be damned.

partial void OnContextCreated()
{    // set your fav defaults here
    this.ContextOptions.LazyLoadingEnabled = true;

    // Register the handler for the SavingChanges event.
    this.SavingChanges
        += new EventHandler(context_SavingChanges);
}

And Bob’s your uncle, there it is! The ObjectContext you can lug around with you and depend upon like an old blanket.  At least until .NET is dead and all the cool kids are making .edmx jokes at your expense. But viddy how readable our code can be in the meantime:

// get Jenkins on the phone!
var jenkins = (from p in AdventureWorksEntities.Current.Employees
    where p.Contact.LastName == "Jenkins"
    select p).First();

// check out lazy-loading the related Contact entity!
DialPhone(jenkins.Contact.Phone);

// Jenkins, YOU'RE FIRED.
jenkins.CurrentFlag = 0;

// poor Jenkins
jenkins.Contact.FirstName = "Mud";

// surely this violates Google's 'don't be evil' motto
// good thing we're using .NET
// and don't call me shirley
AdventureWorksEntities.Current.SaveChanges();

You can download the code from this article and its prequel here, and further pursue the subject here.

The ObjectContext of Your Desire, Part The First

In Which We Take Care of Business with the Entity Framework

There are few phases of application development that I want to have done with faster than running plumbing from the database. Some of us, bless the cockles of their tiny hearts, live in ORM-land and love it. As for me, I’ll take the path of least resistance every time with regard to this drudgery, because I have features to code and a user interface to build. And at the moment, the path of least resistance means using the ADO.NET Entity Framework.

The Entity Framework does a bang-up job of creating a usable data layer in a matter of seconds, once directed toward a database. But though I was no longer spending hours hacking out properties and mapping them to DataRows, it dawned on me that I was not sure where my business logic was suppose to live, now that my data access was practically codeless.

This is one task for which we are not handed a silver platter containing a wizard composed entirely of Next buttons. And you and I both know that if this whole Entity Framework thing is to catch on at all, we’ll need a clean and reusable solution to this dilemma.

I have one here.

I, Entity

The individual entity types generated for a standard Entity Data Model have plenty of hooks for when specific properties have changed, but none for when the entity itself is being saved or deleted, which is often the best place for our custom logic to set up camp. We can bridge this gap by creating a dead simple interface that any interested types could implement:

public interface IEntity
{
    void OnSaving();
    void OnDeleting();
}

Out of Context

Now, the entities themselves may not give any notice when they are saved, but the ObjectContext, who does the actual saving, certainly does. Ergo, our next step is to create a partial class for the generated ObjectContext (in this case, built using our friend the AdventureWorks database), and handle its SavingChanges event thusly:

public partial class AdventureWorksEntities
{
    private static void context_SavingChanges(object sender, EventArgs e)
    {
        // Get the list of changes we are interested in
        var changes = (sender as ObjectContext).ObjectStateManager.GetObjectStateEntries(
            EntityState.Added | EntityState.Modified | EntityState.Deleted);

        // for each change involving an IEntity,
        foreach (ObjectStateEntry change in changes)
        {
            if (!change.IsRelationship && change.Entity is IEntity)
            {
                // trigger custom logic as appropriate
                switch (change.State)
                {
                    case EntityState.Added:
                    case EntityState.Modified:
                        (change.Entity as IEntity).OnSaving();
                        break;
                    case EntityState.Deleted:
                        (change.Entity as IEntity).OnDeleting();
                        break;
                }
            }
        }
    }

    partial void OnContextCreated()
    {
        // Register the handler for the SavingChanges event.
        this.SavingChanges
            += new EventHandler(context_SavingChanges);
    }
}

For those of you who may have seen this MSDN article, that code should appear familiar–I used it as a starting point. The key difference between that code and this listing is that we have used an interface to loosely connect the logic code to the context, rather than having embedded our custom rules directly in the ObjectContext, as might a barbarian or a physicist.

To clarify, I don’t mean to slight physicists, or even barbarians; but while we as developers don’t necessarily excel at tearing someone’s arm off and beating them with it, or at edging closer to drafting the Theory of Everything, we are likely to know that business logic probably ought not to live down in the ObjectContext.

Anyway

Here’s how to apply what we’ve done to add some custom logic to the AdventureWorks Employee entity:

partial class Employee : IEntity
{
    #region IEntity Members

    public void OnSaving()
    {
        // make sure the employee has a LoginID
        if (string.IsNullOrEmpty(this.LoginID))
            throw new ArgumentException("You must give the employee a LoginID.");

        // if this is a new employee,
        if (this.EmployeeID == 0)    
        {
            // make sure they don't already have a record
            if (AlreadyExists(this.LoginID))
                throw new ArgumentException("This employee already exists.");
        }
    }

    public void OnDeleting()
    {
        throw new InvalidOperationException(
            "Employee records may not be deleted.  Please set the Current Flag instead.");
    }
    
    #endregion
}

And here’s what using this newly-adorned Employee entity might look like:

var awc = new AdventureWorksEntities();
var e = (from p in awc.Employees
where p.EmployeeID == eid
select p);

// a clear abuse of my power as 
// example-writer, to be sure.
// but trust me, this guy deserves it.
e.LoginID = string.Empty;
 
awc.SaveChanges(); // throws ArgumentException ("You must give the employee a LoginID.") 

// curses!  foiled again.

Coming Up! Part The Second, in which we painlessly scope the ObjectContext‘s lifespan.

Visual Studio 2010 and .NET 4 at the Aptera Developer Meeting

Earlier this evening, I had the privilege of collaborating with my teammate Brock in presenting highlights from Visual Studio 2010 and .NET 4 to our fellow Aptera developers. After Brock brought the house down with his overview of new language features and a deep-dive into 2010’s outrageous Historical Debugging feature, I brought the team up to date on the wonders of modern Parallel Programming using the Tasks Parallel Library and PLINQ.

If you wish to perform a closer examination of them, you may download my materials from the talk here. This archive contains:

  • The Powerpoint Presentation
  • Full source code from the demonstrations

But Wait, There’s More! Here are a few articles that got me off the ground with the new parallel goodness (and with some other exciting offerings) from .NET 4 and Visual Studio 2010.

Thanks to Brock and the team at Aptera!