Showing posts with label Entity Framework. Show all posts
Showing posts with label Entity Framework. Show all posts

Wednesday, 3 September 2008

The Sorry State of ADO.NET Entity Framework 1.0

A few months ago I test-drove the ADO.NET Entity Framework 1.0 Beta 3. While I enjoyed certain aspects of EF, such as LINQ and graphical modelling, the overall experience of using EF hasn't been that great. In fact, my very first blog on this site was dedicated to EF bashing. My major complaint about EF was its intrusive approach to ORM - instead of using PONO (like in Hibernate), it generates bloated relational database-centric data entity models. This is against the domain driven design method. Another problem I encountered was its shoddy implementation of lazy loading (or lack of it, as a matter of fact).

I then realised that I was not alone in feeling disenchanted by EF. In the same month of my blog, several hundred people have signed up on the ADO.NET Entity Framework Vote of No-Confidence open letter, many of whom are from Microsoft's Most Valued Partners (MVP). In last month's issue of Visual Studio Magazine, the article A Vote for Transparency gave a blow-by-blow account of events on the controversy surrounding EF, including the aformentioned open letter. So Microsoft decided to make the EF version 2 design exercise a more transparent process. This no doubt is a step forward. However, it is too little too late for EF v1. Looks like EF v1 will not receive any significant improvements or address any of the communities concerns in the open letter. In fact, I doubt that any EF design improvements have been made into .NET Framework 3.5 SP1 (released in August 2008) since EF 1.0 Beta 3 (released in December 2007).

On a side note: although some people whine about JCP program being slow (e.g. the Java closure debate) and sometimes committee-driven, comparing to the traditional closed-door design pattern like EF v1, JCP is a great leap forward and the result speaks for itself. The JCP specifications are more readily accepted and adopted by the community than a proprietary one like EF.

Tuesday, 10 June 2008

Entity Framework Bug

In a previous post I blogged about Entity Framework (EF, v1.0 Beta 3) flaws, one of which was about the inconsistency between the entity context and the actual data in the database tables. Here I demonstrate it.

I have two tables: AddressField and Address with a many-to-many relationship as illustrated below.

In the database, the many-to-many relationship is representated as the address_addressfield table. EF correctly generated the entity model, which is shown below. In the entity model, Address has a collection of AddressField and vice versa. To avoid circular loops, lazy loading is used. So far, so good.

Suppose I have 3 addresses a1, a2 and a3, all of which are located in the same country, i.e. all 3 contain the same AddressField. Conversely, the AddressField representing the country should have 3 Addresses in its collection.

If I delete any Address, the corresponding database records in Address and Address_AddressField table should get removed. I would expect the same thing happens in the entity context - i.e. the deleted address should be removed from the AddressField's Address collection.

The following code snippet from my unit test illustrates this:

addressDao.Delete(a1);
Assert.AreEqual(2, addressDao.GetAll().Length);
addressDao.Delete(a2);
addressDao.Delete(a3);
Assert.IsNull(addressDao.GetAll());
Assert.AreEqual(0, 
  afDao.CountAddressReferences(afCountry)); // test fails here
The CountAddressReferences() method implementation is shown below:
public int CountAddressReferences(Address.Domain.AddressField af) {
    int id=(int) af.GetAddressFieldId();
    AddressModel.AddressField entity = addressContext.AddressField
        .Where(t => t.addressFieldId == id).First();
    entity.Address.Load();
    return entity.Address.Count;
}
When I inspect the database tables, everything was OK - the Address table was empty and so was the Address_AddressField table. So the problem is in the entity context - it is not refreshed/updated following the association between Address and AddressField. To get around this problem, I had to detach and reattach the AddressField as shown below (lines 7 to 9):
public int CountAddressReferences(Address.Domain.AddressField af) {
    int id=(int) af.GetAddressFieldId();
    AddressModel.AddressField entity = addressContext.AddressField
        .Where(t => t.addressFieldId == id).First();
    entity.Address.Load();
    Console.WriteLine("before count=" + entity.Address.Count);
    addressContext.Detach(entity);  // extra line
    addressContext.Attach(entity);  // extra line
    entity.Address.Load();          // extra line
    Console.WriteLine("after count=" + entity.Address.Count);
    return entity.Address.Count;
}
Inspecting the console output, it yielded:
before count=3
after count=0

Sunday, 8 June 2008

Entity Framework 1.0 Beta 3

The much anticipated Microsoft ADO.NET Entity Framework (by me at least) has turned out to be a big disappointment.

Entity Framework (EF) is an improvement of the old ADO.NET and supposed to be Microsoft's answer to third-party Object-Relational Mapping (ORM) products, such as Hibernate. However, it totally missed the plot of why people want to have ORM and how these tools are used.

The purpose of ORM is to shield the database details away from the business logic so that the developer does not have to worry about the implementation details of how the data are stored on disk, how the foreign keys relationships are traversed, etc. Developers only need to deal with the domain object model and the domain objects should be modelled as Plain Old .Net Objects (PONO, borrowing from the POJO acronym). This is evident in the tried and true ORM frameworks originated in the Java world: Hibernate, JPA, etc (and to certain extents iBatis SQL Mapper).

The EF way of doing this is to have an Entity Model which can be generated from the database schema. The Entity Model classes inherit from System.Data.Objects.DataClasses.EntityObject, which means that these entity objects are not PONO. So if you want to have a loosely coupled system (between data tier and business tier), then you will need to have a mapping layer between your PONO and these entity objects. This is unnecessary additional work which should have been taken care of by the ORM framework itself.

Another problem with dealing directly with these entity objects is that the developer will have be be aware of the fact that there is a whole new caching layer called entities context which caches the database records in memory in the form of these entity objects. Very often, the developer will have to worry about the synchronisation between the entities context and the actual database (by calling Attach(), Detach() and Load() methods explicitly on the entity model objects) especially when many-to-many relationship associations need to be followed on Delete or Update operations. See my other post on an example of this. Microsoft has also been evangelising the practice of putting these entity objects directly into GUI widgets as their data source. This again creates tight coupling between the data tier and the presentation tier. All these extra data and methods about the entity object life-cycle should be made only visible in the data tier (or DAL, as Microsoft calls it) and nowhere else. That is why PONO should be used throughout the business and presentation tiers, rather than these bloated entity objects. It is disappointing to see that after witnessing all these great ORM examples in the Java world, Microsoft still could not make a decent ORM framework.