EDM: I'm not impressed either

Published 11 February 07 07:25 AM | andersnoras 

Hammett and Oren both posted about the ADO.NET Entity Framework this weekend. Go ahead can read Hammnett's "Is EDM the unlearned EJB lesson?" and Oren's follow up "Complex EDM".
I've had the unpleasant experience of working with the horribly broken architecture of Enterprise Java Beans, and I built on these experiences trying to follow a lighter path as a .NET-developer. The EJB Container Managed Persistence (CMP) model was very weak. EJB 1 did not support relationships between Entity Beans, simple features such as sorting was not introduced before EJB 2.1 released. 

EDM, LINQ to Entities, and other LINQ technologies are steps in the right direction, and hopefully these technologies will change the way .NET-developers think about database integration. The EDM has a better model than the loathed EJB CMP model, but I agree with Hammett that Microsoft are focusing on the wrong features.

You have two options when you want to create an entity data schema; either you use the EDM Designer tool or you write the required XML by hand. The latter option is tedious, so most developers will be using the tool to generate the schema. The EDM Designer lets you generate a schema from an existing database, which means that you'll generate an anemic domain model. This is fits well with the common Microsoft guidance to separate data objects from business behavior, but this is not a good way to design a business layer. You can write your own entity data schema XML descriptor to map an existing domain model to EDM, but this might also be problematic since the EDM does not support behavioral inheritance.

"Entity types can be defined so they inherit from other types (e.g. Employee could inherit from Contact). This kind of inheritance is strictly structural, meaning that there is no "behavior" inherited as it happens in object-oriented programming languages. What's in inherited is the structure of the base entity type; in addition to inheriting its structure, a instances of the derived entity type satisfy the "is a" relationship when tested against the base entity type."
From "The ADO.NET Entity Framework Overview"

Unless I need to use a legacy schema, I prefer to use NHibernate's DDL support to create the database schema from the mapping documents rather than defining the database schema by hand because this enables database portability and makes it easy to use an in-memory database for testing.

Another limitation of the the Entity Framework is that it does not support detached objects. Consider the following example from the overview document.

// we'll use the order-tracking store
using(OrderTracking orderTracking = new OrderTracking())
{
    // find all the pending orders for sales people
    // in Washington
    var orders = from order in orderTracking.SalesOrders
        where order.Status == "Pending Stock Verification" &&
        order.SalesPerson.State == "WA"
        select order;

        foreach(SalesOrder order in orders)
        { 
           // obtain a list of StockAppProduct objects
           // to be used for validation
           List<StockAppProduct> products = new 
               List<StockAppProduct>(
                   from orderLine in order.Lines
                   select new StockAppProduct
                   {
                       ProductID = orderLine.Product.ID,
                       LocatorCode =
                           ComputeLocatorCode(orderLine.Product)
                   }
                );

             // make sure all products for this order
             // are in stock through the stock management
             // system

             if(StockApp.CheckAvailability(products)) {
                 // mark the order as "shippable"
                 order.Status = "Shippable";
             }
     }

     // if we marked one or more orders as shippable, persist
     // the changes in the store
     orderTracking.SaveChanges();
}

Even though the vision for next generation data access states that the Entity Framework has support for "occasionally connected components" this is not the case for the current CTP. In the above example. all the business logic has to be performed within the same scope for the EDM to be able to persist changes to entities. This implies that you cannot return detached entity instances from your business layer to the presentation layer through a facade nor use the exposed domain model pattern to let a presentation tier consume these instances.

"In the current CTP there is no support for the "long running scenario". We're actively looking at this specific scenario and how applications drop and later on re-construct their execution context, including the object context. The goal of that is to preserve, at users' option, optimistic concurrency check-related information."
From the ADO.NET Team Blog

The lack of behavioral inheritance and no support for detached objects are limitations that promote the Transaction Script pattern which seldom is the best choice for complex business applications. Since transactions scripts have fewer benefits from ORM-frameworks than applications built around the domain model pattern, I fear that these limitations will result in many sub-optimal architectures built around ADO.NET vNext.

Hammnet points to one of the "unique" features of the Entity framework, which is the ability to compose an entity as a logical view of more tables. As Oren points out, this is also supported by Hibernate 3 and many JDO implementations support this as well. Both Hammnet and Oren are right that this feature is something you'd seldom need, but there are a couple of scenarios where it can be useful; you could need to map your domain model to a legacy database where the data which makes up one entity in your domain model is normalized across multiple tables - or - in extreme cases you might want to tune your database by splitting coherent data into multiple tables. For instance you could have one table with the mist commonly used attributes, and another with rarely used attributes to speed up updates on the commonly used attributes.
These are both edge cases, and I feel that an ORM should fully support the common use cases before these.

The killer feature of the Entity framework is LINQ to Entities which allows developers to write LINQ queries against the model. A query language is a basic feature of any ORM, and NHibernate has two different approaches to this. You have the HQL query language which is very domain specific and therefore is superior to the more generic LINQ language and the Criteria API. There was some talk about adding LINQ support to NHibernate last year, but I've heard little of the NHiberLINQ project after the initial idea came about. I believe that it should be relatively straight forward to write a NHibernate session implementation which implements the System.Linq.IQueryable<T> interface and use the Criteria API to construct the actual queries, but the big question is if this would add any value. You can write better queries with HQL. This LINQ query (again from the overview document):  

SELECT VALUE sp
FROM AdventureWorks.AdventureWorksDB.SalesPeople AS sp
WHERE EXISTS
(
    SELECT VALUE o
    FROM NAVIGATE(p, AdventureWorks.SalesPerson_Order) AS o
    WHERE o.TotalDue > 200000
)

...can be written like this using HQL...

SELECT sp FROM  SalesPeople sp JOIN sp.Orders o WHERE o.TotalDue > 200000

Sun has learnt a lot from the EJB-backlash. Recently EJB 3.0 was introduced, and it has gone through significant design improvements - but still many common ORM features such as support for collections of primitive types are missing.
Still the annotation based mappings have adopted many of its concepts from successful ORMs such as Hibernate and JDO. As it is today the Entity framework is an "half-way there" solution to a problem that has already been solved. I agree with Hammnet that they should learn more from the EJB-story and do things in a way that works instead of trying to reinvent the wheel.

Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Anders Norås' Blog said on February 11, 2007 11:44 PM:

Johannes Brodwall has written an excellent blog post on the history of Java . Whether you do Java development

# Anders Norås' Blog said on March 2, 2007 8:27 AM:

In wake of the recent discussion on Microsoft's Entity Framework , mapping types to more than one table

# aL said on May 22, 2008 1:36 PM:

err that is not a linq query at all.. not sure what it is, but linq it aint. for startes all linq queries start with "from" not "select"

a linq query equvalent to the hql query you wrote would be:

var x = from salesguy in AdventureWorks.AdventureWorksDB.SalesPeople

where salesguy.Orders.TotalDue > 200000

select salesguy

note that you dont have to do the join explicitly because its inferred from the edm model

Leave a Comment

(required) 
(optional)
(required) 
Enter the code you see below