Code through the pain Ladislav Mrnka's professional blog about software development

8May/1119

The first version of Entity Framework introduced in .NET 3.5 SP1 (EFv1) contained only a single type of association between entities. All associations in EFv1 was based on the correct object oriented approach where a relation between entities is modelled as a reference between objects. The problem of this association type was the internal implementation in Entity framework which makes it sometimes (especially in detached scenarios) very hard to use. The next version of Entity Framework introduced in .NET 4.0 (EFv4) included a new type of association where conceptual model also includes foreign key properties to define connections between entities. To differ between these two types of associations ADO.NET team decided to call the old type Independent association and the new type Foreign key association.

The question is: Was introducing the new type of association a good design choice? I believe that Foreign key associations should not never be included and instead Independent association should be improved. The main reasons for introducing the new type of association are covered by the article on Entity Framework Design blog. The community was obviously divided between two groups where one group requested foreign keys whereas second group didn't want them. I'm the member of the second group because in my opinion ORM tool should not push relational concepts to the conceptual / object model. A foreign key is definitely a relational concept to model a relation and we rarely want it to pollute our object model.

Despite of that I agree with ADO.NET team that the final decision should be left to developers so if we want to include a foreign key property in our entity we should be able to do that. I don't agree with the way how it was achieved. The biggest problem is that a difference between Independent and Foreign key associations is not only in the way how they use foreign keys. These two association types are handled by EFv4 completely differently. The rest of the article will explain differences between these two association types and it will also mention how this affects Entity Framework 4.1 and its DbContext API.

When participating on Stack Overflow, I found that differences between Foreign key and Independent associations are not very well known and because of that I quite often reference my answer to this question asked by Daniel Liuzzi.  The answer partially describes different handling of these two association types. Let's check it more in detail on this simple database relation:

The database model for Order and OrderLines

There is one more thing to mention. The difference is only in the case of one-to-many relation. If you model a one-to-many relation you can choose if you want to use Foreign Key or Independent association. Other types of relations are without a choice. One-to-one relation in EFv4 always uses Foreign Key association and many-to-many relation always uses Independent association. This makes all stuff around associations even fuzzier.

Independent association

  • Main characteristic of Independent association is a missing foreign key property in a dependent entity.  When using Independent association we can't map a foreign key to a property - Visual Studio will throw a validation error in EDMX file if we try to do it.
  • This association must be mapped to its database counterpart (in the Mapping details window in Visual Studio). The foreign key is used only internally to establish the relation in the mapping.

The entity model for independent association between Order and OrderLine

  • The relation between two entities is tracked as separate object by ObjectStateManager. It has its own state which must be correctly handled. This is the biggest problem of Independent associations when working with detached entities. Handling this correctly can be pretty tough task. This is something that should be simplified instead of creating new association type.
  • When creating a new relation in code we always need entities from both ends of the new association. This looks like a big problem but actually this can sometimes be cheated with fake/dummy entities (the attached instance of the entity type which has a primary key property set to a value of the existing entity).

The example of using a dummy entity to define an independent association:

// Add new OrderLine to existing Order without loading the order from the database
var line = new OrderLine
    {
        Price = 150.0M,
        Quantity = 15
    };
// Create fake / dummy order with Id of existing order
var order = new Order { Id = orderId };

using (var context = new ModelContainer())
{
    // Cheat the context by dummy entity so that context thinks that entity was loaded
    context.Orders.Attach(order);
    // Add new line
    context.OrderLines.AddObject(line);
    // Create a relation between the new line and the existing order
    line.Order = order;
    context.SaveChanges();
}

Foreign key association

  • Main characteristic of Foreign key association is a foreign key property exposed on a dependent entity. The foreign key property must be always exposed when using this type of association.
  • This association is not mapped to its database counterpart. The association is built by referential constraints. This is actually most useful feature of foreign key association because it allows building relations which don't exists in the database and it also allows some more complex mapping scenarios.

The entity model for foreign key association between Order and OrderLine

  • The relation between two entities is not tracked. The tracking is done on a dependent entity where a value of a foreign key property changes. This is a big simplification for some scenarios and the main reason why I usually recommend using Foreign key association despite the fact I don't agree with exposing a foreign key in conceptual model - sometime an architectonic purity must fall back because of a limited feature set.
  • When creating a new relation we just need a dependent entity and a primary key of a parent entity. The tricky part here is that primary key must be unique for all attached entities of a given type. Even if we use auto generated keys in the database we must still assign temporary unique key to newly created entities which are added to relations.

The example of problems caused with non-unique temporary keys used for foreign keys:

using (var context = new EFAssociationsEntities())
{
    // First order
    Order orderOne;
    context.Orders.AddObject(orderOne = new Order {OrderDate = DateTime.Now});
    context.OrderLines.AddObject(new OrderLine
    {
        Price = 10.0M,
        Quantity = 1,
        OrderId = orderOne.Id
    });
    // Second order
    Order orderTwo;
    context.Orders.AddObject(orderTwo = new Order { OrderDate = DateTime.Now });
    context.OrderLines.AddObject(new OrderLine
    {
        Price = 10.0M,
        Quantity = 1,
        OrderId = orderTwo.Id
    });

    // UpdateException: Unable to determine the principal end of the
    // 'EFAssociationsModel.FK_OrderLines_Orders' relationship.
    // Multiple added entities may have the same primary key.
    context.SaveChanges();
}

The solution for last example is either assigning Order instance directly to navigation property in OrderLine (or vice-versa) or assigning temporary unique keys to Order instances - we can use for example negative integers to avoid collision with existing entities.

DbContext API and code-first

The separate area is a new DbContext API and code-first approach. When defining class in the code-first approach the only difference is if we create a foreign key property or not (either with default convention mapping, data annotations or fluent mapping). Entity Framework 4.1 will detect the property and handle the relation as Foreign key association. Foreign key associations are favored by DbContext API because DbContext API and its DbChangeTracker doesn't provide a way to change a state of Independent association (we must convert DbContext back to ObjectContext and change the state in ObjectStateManager). This makes me upset because it looks like Foreign key associations are winning => polluting entities with database related features is presented as a good practice.

Example of code-first entity using Independent association:

public class OrderLine
{
    public int Id { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    public virtual Order Order { get; set; }
}

Example of code-first entity using Foreign key association:

public class  OrderLine
{
    public int Id { get; set; }
    public int OrderId { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    public virtual Order Order { get; set; }
}

Conclusion

As you can see Foreign key association brings some very important features. I'm not against these features and I'm not against features offered by Independent association. I'm against two types of associations where each offers only partial functionality we would like to use - we should simply have one type combining benefits of these two. Introducing two completely different types of associations is a design flaw and it is the decision which hurts usability of Entity framework.

Posted on May 8, 2011 by Ladislav Mrnka
Filed under: Entity framework
Leave a comment
Comments (19) Trackbacks (7)
  1. public virtual Order { get; set; }

    Shouldn’t this be

    public virtual Order Order { get; set; }

    ? You have defined the type but not the name of the property

  2. I’m confusing. In Independent Relationship. You said that “The relation between two entities is tracked as separate object by ObjectStateManager.”

    Supposed I have 2 Entity : Contact and Address, which the relationship is 1:M.

    And I run this code :
    var newCon = new Contact();
    var newAddr = new Address();
    newCon.Addresses.Add(newAddr);
    context.Contacts.AddObject(newCon);
    var ose = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added |
    EntityState.Deleted | EntityState.Modified | EntityState.Unchanged)
    .Where(entry => entry.IsRelationship == true);

    But when I inspected the ObjectStateManager I only found 1 RelationshipEntry object for each relationship
    (ose.Count = 1).

    Would you like to clear this ?

    • That is a correct behaviour. You have Contract and Address instances and relation between them. Your state manager will contain 3 instances of ObjectStateEntry. One for each entity and one for relation. The entry for relation doesn’t represent the entity. It represents only the linkage between two entities (it also wraps the foreign key).

  3. how can i update navigation property only e.g:update Admin_Role table only

    http://stackoverflow.com/questions/5749110/readonly-properties-in-ef-4-1

    public void Update(T entity, params Expression<Func>[] properties) { _dbSet.Attach(entity); DbEntityEntry entry = _context.Entry(entity); foreach (var selector in properties) { entry.Property(selector).IsModified = true; } }

  4. Thank you for this clarifying article!
    You wrote: “ORM tool should not push relational concepts to the conceptual / object model.” I agree, but at the same time, EF requires a (primary) key property – this is definitely a relational concept. I wouldn’t add an Id property to a class when designing the object if EF didn’t require it. Shouldn’t that be handled by the ORM, too ?

  5. Hi Ladislav,

    I struggled working on resolving this issue for a long time. Looks like the second way, i.e.( assigning temporary unique keys to Order instances ) and linking the objects with foreign keys works for me, but not the first one i.e.(assigning Order instance directly to navigation property ). Thanks a lot for the solution!!!
    Also can you kindly confirm whether the first way, i.e. linking with navigation properties works?

  6. Hi, thanks for a great explanation!

  7. Supr clanek… Moc pomohl :)

  8. In my opinion there’s another interesting future available with FK association.
    If you define the Orderline primary Key as composed by Id+OrderId (PK and FK) you can remove an orderline from Order.OrderLines and have a delete genereted from EF. Without have to manually delete OrderLine entity. I hope to find this functionality for Indepenend association in future.
    I have a question because you said that in one-to-one only FK association is available. What do you mean?
    Actually I’m using Idependent association with one-to-one rel. like
    public class Order{
    public virtual Company Customer {get;set;}

    }

  9. I couldn’t agree more! I like independent associations like anyone who likes to work with POCO’s. Although, admittedly, sometime it is very convenient to just set an Id. I was a bit puzzled about you being “thrilled” (at the bottom of your post) until I understood you probably meant “upset”.

    Thanks for your post and your valuable contributions at Stack overflow!

  10. Is it possible to have a foreign key relationship and a Navigation property at the same time for the same type.

    For ex I have a Job entity and a field called PaymentType_ID with a foreign key relationship to a PaymentType entity. When I do an insert it works fine.

    Then I add a Navigation property using the same association that is used for the FK, when I try insert I get the following error “Invalid column name ‘PaymentType_PaymentTypeID’.”

    It seems EF is for some reason adding another column by itself even though a FK already exists.

    Is this possible or what am I doing wrong

    • I believe this blog post shows that it is possible to have both navigation property and foreign key property for the same relation – that is Foreign key association. Also I think I answered your question on Stack Overflow and linked example how to do it in model first.

  11. Great article! Solved the exact problem I was having. Ladislav, I really appreciate all the articles you write and comments you make on Stack Overflow and other places about EF. Thanks!

  12. Nice Example. Solved my problem without much effort. Saved my time. Really appreciate your work

  13. I definitely agree with you on not letting relational model creep into the object-oriented model.

    I have this damn problem, I can’t figure it out in EF
    I have a Document class
    which is the base class for any kind of documents
    like Books, or Balanc Sheets, or even an Article
    This means that I have a complete inheritance
    public class Document {}
    and
    public class Article: Document {}
    Now, I can’t force the EF to just insert Article, not Document

    I don’t like to break this inheritance design in C#, just because EF says so. What should I do?


Leave a comment

(required)