ADO.NET Entity Framework: Impressive! Powerful! Useless!

by Stephen M. Redd 22. August 2008 18:57

The new Microsoft Entity Framework is the latest in a long line of very impressive, yet tragic failures in Microsoft's data access strategy...

The basics of ADO.NET are great. SqlCommand, SqlConnection and their relatives for other platforms... awesome. But almost every single version of ADO.NET has failed when it comes to useful higher level abstractions. To be sure, they each demo well and they each have uses with simple applications (like those you'd be shown a demo of).

But whenever it comes to complex applications, the abstractions tend to become cumbersome, restrictive, an inflexible. The result is that most serious application end up using 3rd party frameworks or custom abstraction layers instead and under-the-hood they tend to stick to the basic ADO.NET SqlConnections and SqlCommands to do the dirty work.

In .NET 1.x it was DataSets and SqlAdapters. In .NET 2.x it was DataTables and TableAdapters. And now we have the ADO.NET Entity Framework (EF).

I had high hopes for EF. MS had clearly recognized that a radical new approach would be needed if they were to achieve a useful abstraction without having to re-invent the same wheel over and over again every few years. They had also set some pretty good goals in terms of making EF useful in support of other data stores outside the classic relational database.

Sadly, what has been delivered in the 1.x version of EF is hopelessly crippled by the deliberate lack of implicit lazy loading.

Here is an example of what this means. Assume we have two logical EF entities that map more-or-less directly to physical tables in a database. One is the Order object and the other the Customer. These entities have a navigation relationship between each other (which is analogous to the physical database's foreign key).

If you get a reference to an Order object it will have a property called Customer. This property is how you'd navigate the relationship between the entities.

So you'd expect that if you look at MyOrder.Customer you'd get back a reference to an instance of the Customer entity... But you would be fucking wrong!

The Customer property on the instance of Order may not have been fetched from the database automatically when you obtained your reference to the Order...

Instead of implicit lazy loading, EF has "Deferred Loading"... or if you prefer you can call it "Explicit Lazy Loading". The idea is that you can check to see if the Customer has been loaded for an Order, and if not then you can explicitly load it when and if you need it. But it will not automatically load the data for these properties and related entities unless you explicitly tell the framework to do so (which is unlike most ORM frameworks, LINQ to SQL, etc.).

What happens in real applications is that you never know what has and has not been loaded. So your code is chock-full of bullshit like this:

if(!someOrder.CustomerReference.IsLoaded)
{
	someOrder.CustomerReference.Load();
}
string customerLastName = someOrder.Customer.LastName;

This allows you to do what you need to be doing in your code, but the price is that you HAVE to do this all over the fucking place... every time you want to access a property that traverses a relationship. You end up with more checks for data than you do data in the first place.

Even worse than that though, when you code something to use your EF model, now you now have to somehow magically "know" which properties on your entities are going to traverse a relationship and which don't.

If you know in advance that you are going need the related data later on, then when you fetch your entity you can a technique known as "Eager Loading" to tell EF to go ahead and load up the related data in advance.

This looks like this:

var x = entities.Orders.Include("Customer");

Again, this allows you to do what needs doing, but if you are making the fetched order entity available to other classes (like as a return value from a public method)... then the caller isn't going to know if you pre-loaded the relationships or not... so they'll still have to do the whole "IsLoaded" anti-tard checking shit anyway.

In his response to a nasty online petition called the "Vote of No Confidence", Tim Mallalieu defended the lack of implicit lazy loading with this statement:

"We took a fairly conservative approach in v1.0, because we wanted developers to be aware of when they were asking the framework to make a roundtrip to the database... our take on 'boundaries are explicit'."

That has to be the most depressing statement that I've ever read regarding ANY data access technology ever!

Hey guys!

The entire point of an abstraction layer is so that developers using that layer DON'T have to be aware of the damned internal workings under the abstraction layer!!!!

But most offensive to me is the overall fact that I cannot "trust" the EF model. For example... if I have a Customer entity then I have no way to know if Orders property contains an empty collection because there aren't any orders of if it is empty because the framework hasn't loaded data. Instead of being able to trust the entity model to be accurate I have to baby sit it and constantly ask "are you sure you loaded data for this already?".

Fuck that!

Then we get into the other side effect. All the mechanisms needed to do the paranoid checking-up after EF use some counter-intuitive techniques. Before I check the Customer property on an Order entity, I have to first check up with a CustomerReference property on my Order to get information about the state of the contents of the actual Customer property? Huh?

Yeah.... that's really slick there!

The eager load technique pisses me off even more!

So I can tell the EF to go ahead and load relationships... but to load them I have to use a method that takes a fucking string as an argument?!

So now I also have to be an expert on exactly what each navigation property in my EF model is specifically named... and that without strong type checking or intellisense? Sure... I can do that, but it slows me down and is just begging for a runtime bug (typoed the name or messed up the capitalization). That means I am constantly having to refer to the damned diagram all the time too which just slows me down and annoys the shit out of me at the same time!

Using EF without lazy loading is a good way to drive yourself into becoming so paranoid you'll need to remember to take your anti-psychotic meds before you even open Visual Studio!

There are a few 3rd party attempts out there to get implicit lazy loading features with the current version of EF. These are clever hacks, and I even tested out one of those. Overall, the hacks give you a much better experience than using the stock Entity Framework as is, but this is also code that will be hard to update to use any future releases of EF too, and these impose other limitations on your code too. I suppose though that if you HAD to use EF, you'd still be smart to use one of these 3rd party techniques to get the implicit lazy loading anyway.

LINQ to SQL may lack the ability to provide a true logical abstraction for your physical data model, or do fancy inheritance, or even handle some of the more unusual data mappings...  but at least you can TRUST that properties in a LINQ to SQL Entity will actually contain data that reflects what is in the real database. Plus the overall usage pattern of LINQ to SQL is much clearer and simpler.

Until EF gets built-in implicit lazy loading, screw it... I'll just use LINQ to SQL.

Tags: , , ,

Filed Under: Code

AjaxControlToolkit - Using the ReorderList with simple collections

by Stephen M. Redd 29. March 2008 09:02

Download Sample Project

Recently I've been working with the AjaxControlToolkit and Microsoft's Ajax technologies in .net 3.5. While I love the AjaxToolkit, I find the documentation and code-sample is somewhat lacking.

The ReorderList is also one of the lest intuitive controls in the Toolkit.

There are several other samples around the net, but all the ones I found assumed your were binding to a DataSource control of some sort, and most didn't demonstrate persisting changes to an underlying data store.

The few that showed persistence assumed a SqlDataSoruce control that would automate persistence with two-way binding (outside of demo-land, this is a a rare case  in my experience).

So when I first tried out this control, I was surprised at how difficult it was to use it with a simple collection such as an array, or a generic list.

Here is the basic markup you need in your page:

<ajaxToolkit:ReorderList ID="OrderList" runat="server" AllowReorder="true"
            LayoutType="Table" OnItemReorder="OrderList_ItemReorder" 
            PostBackOnReorder="true">
            <ItemTemplate>
                <span style="cursor: pointer;">
                    <asp:Label ID="ItemName" runat="server" 
                               Text='<%# Container.DataItem %>' />
                </span>
    </ItemTemplate>
</ajaxToolkit:ReorderList>

We're setting the text of the label control to the Container.DataItem directly rather than using an Eval or Bind method. That's because simple collections don't have properties that Eval and Bind can use, so you put the content of the data item directly in your output. This is the same with almost all bindable controls with simple collections, but is also one of those things the documentation just sort of "assumes" you already know... which is probably why I coded asp.net for about 4 years before I discovered this little trick.

On a postback or callback, there is no reliable way to get at the data items in their re-arranged state. If you put a button on the page to postback to the server and try to look at the items in the control, you will only be able to see them in the order they had been in when the control was first bound to the collection.

This means you can't just let the user make changes on the client and just submit the page back when they are done. The only reliable way to keep up with the user made reordering is to let the control postback each time the user makes a change, then manually keep track of the changes yourself.

Annoyingly, if you let the control post back to the server as the users makes their changes, the control will re-render itself with the original items in their original order. This will cause the list to reset after each postback effectively undoing the user's changes.

The only way around that seems to be to manually rebind the control yourself on each postback after you've updated the collection that you are using to manually track the changes.

To get all this to work together, the trick is to cache a copy of the items. When a user reorders the list you rearrange your copy of the items, recache it, and re-bind the ReorderList control to your updated copy.

How you choose to cache the items might depend on how much information is in the collection. For small collections you can just use ViewState, but for larger collections you'd probably want to cache them on the server with the Cache API or session variable.

This example will use ViewState since it assumes small and simple collection.

Here is the code that does all this:

protected void Page_PreRender(object sender, EventArgs e)
{
    // doing this at PreRender so we don't have to worry about when/if 
    // we should bind based on if it's a postback or callback and what not.
    OrderList.DataSource = OrderItems;
    OrderList.DataBind();
}

protected void SaveOrder_Click(object sender, EventArgs e)
{
    //normally you'd save to reordered list to the DB or whatever
    foreach(string s in OrderItems)
    {
        // output the re-ordered values to page
        Message.Text = Message.Text + s + "
"; } } protected void OrderList_ItemReorder(object sender, ReorderListItemReorderEventArgs e) { string[] items = OrderItems; List list = new List(OrderItems); //using a list for the reordering (convienience) string itemToMove = list[e.OldIndex]; list.Remove(itemToMove); list.Insert(e.NewIndex, itemToMove); OrderItems = list.ToArray(); //you could save this to the DB now, but this example uses a //save button to batch up changes }

As you can see, this is pretty straight forward. We maintain our own copy of the items collection putting it into ViewState between server trip. When the user makes a change the event handler just syncs our copy of the items collection. On PreRender we rebind the ReorderList to our collection, which should always be in sync with the client's copy. And finally, the save button can just commit the changes using our copy.

Tags: , , ,

Filed Under: Code

The Waffle House Code Engine

by Stephen M. Redd 16. December 2007 18:03

I spend a lot of time at my local Waffle House writing code. I know, not the most up-scale choice, but unfortunately a necessary one considering the lack of other good options these days.

waffel house logoFor those unfamiliar with it, Waffle House is a very large chain of greasy-spoon diners. It is nearly a national chain, but there are a few areas that haven't been graced with a waffle house yet but most places have something similar.

Waffle houses are very small restaurants seating around 25 people comfortably. They are usually located on major interstates or within major cities. They are also notoriously dirty places, with generally crappy food guaranteed to cause heat disease nearly instantly. The regular clients of such places range from retired old men to drunken motards with a lot of not much in-between.

On the plus side though, waffle houses are cheap places to eat (more or less), they serve great coffee. For their employees the house pays weekly, and they pay in cash too. This makes it the ideal job for drug-addicts, escaped convicts, illegal immigrants, and anyone whose idea of a "savings" account includes a mattress and some coupon books.

It wasn't always this way for me.

I used to hang out in higher-class establishments like IHOP or Denny's. Hey! I didn't say "high" class, just higher class than the awful waffle. But I'm a smoker, and I love sitting around with my laptop writing code while drinking coffee and smoking at 3am, and for that there just aren't many class-establishments to choose from.

It just works for me.

I've tried this at home, but all that mess about having to get up and make coffee, pour it myself when my cup runs empty... uug... and I don't smoke in the house so I have to actually go out to the garage when I want a smoke. Also, at home I have all my other stuff handy like the TV, a fast internet connection, and a lot of neglected chores that need doing.

So its easy to get distracted.

At the office, things are better. But there I have co-workers that need working with, my end-users have questions to ask, bugs to report, and just general problems that need solutions. Plus there is my boss who needs status updates and has new ideas and features to propose and some other projects to discuss. Then there are meetings and the occasional talking to the customer too.

In short:

if(codeAtHome == null && codeAtWork < optimal)
{
    DoWorkAtWaffleHouse();
}

So while I get code done at the office, and less often even at home, I still do my best work after-hours in places where there are people getting paid to look after me. Plus the staff makes good entertainment when you need to take a break from the screen for a bit.

But the anti-smoking movement is on its way, and I'm sure it wont last much longer, every year there is more and more political noise in the direction of banning smoking in all public places. At this point it may just be a matter of time. So once I either quit smoking (which I'm planning to do this year) or they finally ban it, the only real thing that changes is that I'll have more options for where to hang out.

Tags: ,

Filed Under: Code

Powered by BlogEngine.NET 1.6.1.6
Theme by Stephen M. Redd