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

No comments: