Introduction

Since Entity Framework 4, EF supports two different types of associations. Microsoft names these association types independent associations and foreign key associations, but I like to call them mapped associations and constrained associations.

You will also find more information about these association types in the MSDN article “Defining and Managing Relationships”:
http://msdn.microsoft.com/en-us/library/ee373856.aspx

Mapped associations (independent associations)

A mapped association is one that is mapped on the storage model, on tables and columns. Such an association is created when you create or update your entity model from database and choose not to create foreign key properties. A mapped association can also be added manually to the model, for instance by using the association tool from the EDM toolbox.

The context menu of a mapped association, containing a menu item to access the table mapping of the association.
The context menu of a mapped association, containing a menu item to access the table mapping of the association.

 By right-clicking on a mapped association and selecting ‘Table Mapping’ from the context menu, you can define the table and columns to map the association on.

Constrained associations (foreign key associations)

When choosing to have foreign key properties created during the creation or update of the entity model from database, Visual Studio.NET Entity Data Model Wizard will create another type of associations: constrained associations.

In contrary to mapped associations, constrained associations are not mapped directly on tables and columns, but on scalar properties (which on their turn are mapped on columns). The context menu of a constrained association does not show a ‘Table Mapping’ option.

The context menu of a constrained association.
The context menu of a constrained association.

You can also manually create (or edit) a constrained association by using the association tool from the EDM toolbox, and then edit the ‘Constraint’ property from the properties box of the association. The constraint of an association is similar to an association table mapping, except that is a mapping in terms of the conceptual model (in terms of scalar properties instead of in terms of columns).

When you delete the constraint of a constrained association, it automatically becomes a mapped association (that is, the ‘Table Mapping’ menu item appears in the context menu of the association), and by (clearing the table mapping and) adding a constraint on a mapped association, it becomes a constrained association.

Understanding the difference

So why do two association types exist in Entity Framework ? The reason is: to accommodate the rule that a database column may only be mapped to a single ‘item’ (scalar property or association) in Entity Framework. When adding support to foreign key properties in Entity Framework 4, this introduced a situation where a single column (the foreign key column) would be mapped on both the foreign key property (which is basically a regular scalar property) and the association. Therefore, the EF designers decided to add constrained properties which would not be mapped on columns but rather be mapped on (or constrained by) the foreign key properties.

Within the EDMX file, the difference is clear. A mapped association is defined as both an association in the conceptual model:

<Association Name="OrderCustomer"> 
  <End Type="OrderingModel.Customer" Role="Customer" Multiplicity="0..1" /> 
  <End Type="OrderingModel.Order" Role="Order" Multiplicity="*" /> 
</Association> 

and a mapping between the conceptual model’s association and storage model’s tables and columns in the ‘C-S mapping’ section of the EDMX file:

<AssociationSetMapping Name="OrderCustomer" 
 TypeName="OrderingModel.OrderCustomer" StoreEntitySet="Order"> 
  <EndProperty Name="Order"> 
    <ScalarProperty Name="Id" ColumnName="Id" /> 
  </EndProperty> 
  <EndProperty Name="Customer"> 
    <ScalarProperty Name="Id" ColumnName="CustomerId" /> 
  </EndProperty> 
  <Condition ColumnName="CustomerId" IsNull="false" /> 
</AssociationSetMapping> 

While a constrained association is defined entirely in the conceptual model (as its constraints are in terms of the same conceptual model):

<Association Name="OrderCustomer"> 
  <End Role="Customer" Type="OrderingModel.Customer" Multiplicity="0..1" /> 
  <End Role="Order" Type="OrderingModel.Order" Multiplicity="*" /> 
  <ReferentialConstraint> 
    <Principal Role="Customer"> 
      <PropertyRef Name="Id" /> 
    </Principal> 
    <Dependent Role="Order"> 
      <PropertyRef Name="CustomerId" /> 
    </Dependent> 
  </ReferentialConstraint> 
</Association>

Many-to-many associations

Foreign key properties are only supported on the 1 or 0..1 side of an association. Therefore, many-to-many associations, which have only many sides, don’t support the use of foreign key properties. Hence, many-to-many associations are always defined as mapped associations.

In this article I will further concentrate on one-to-many associations.

Choosing the association type

Choosing the type of association is easy because the choice depends on whether you want to have foreign key properties or not. If you want to have a foreign key property, then the matching association must be a constrained one (as it is not allowed to map a column to both a foreign key property and an association).

If you do not (want to) have a foreign key property, then the association would be a mapped one (as there is no foreign key property to use in the constraint definition).

So the question is, do you want to have foreign key properties ?

Foreign key properties can help increasing performance of your application by limiting the complexity and number of database queries. For instance, if you need the id of an order together with the id of its customer (or need to use them in a where clause), with foreign keys you can request properties of the same Order entitytype: order.Id and order.CustomerId. While if you did not define foreign key properties, you would need to traverse the association connecting both which means you’ll have to perform an extra query or extra join on database level: order.Id and order.Customer.Id.

But then again, it is perfectly legal to mix mapped and constrained associations together in one entity model and to switch an association from one type to another (by adding or removing constraints and defining or clearing the table mapping) anytime you like. So why bother, really ?

Known issues

Both types of associations are supposed to show the same behavior (support lazy loading, etc.). However, so far I’m aware of 2 issues related to associations in Entity Framework. (Both issues happen with and can be solved through the default generation template. I did not investigate those issues on the Self-Tracking entities template or the POCO template.)

The first issue has been described by:

http://stackoverflow.com/questions/3023993/entity-framework-auto-updating-foreign-key-when-setting-a-new-object-reference

This issue tells us that changes made on foreign key properties are not always reflected on the association properties. As this issue relates to the use of foreign key properties, it only occurs with constrained associations.

I have inspired my solution from the one described in the StackOverflow post, but corrected it as it was not correct under all circumstances.

The other issue tells us that a reference property is not considered changed if it is set to null without first reading its value. As a result the following code does not work as expected (provided an order with Id==1 exists, it already has a customer associated to it, and the CustomerId foreign key column is nullable), while uncommenting the commented line solves the issue:

// Perform update: 
using (var context = new OrderEntities()) 
{ 
    Order order = context.Orders.First(x => x.Id == 1); 
    // dummy = order.Customer; // solves the issue 
    order.Customer = null; 
    context.SaveChanges(); 
} 

Solving the issues

For a real solution of those issues we must update the code generation template of Entity framework.

The first step is to add the code generation template to our project by choosing “Add Code Generation Item…” in the context menu of the Entity Model diagram, and then choose for the “ADO.NET EntityObject Generator”. Using this template you still get ‘regular’ entities (no POCO’s or self-tracking entities).

The Add Code Generation Item menu option

This option adds a “model.tt” file to our project which is a text template used to generate the entity context and classes.

Next, we’ll ‘fix’ that template. From line 381 to (including) 391 you’ll find the following code:

<#=code.SpaceAfter(NewModifier(navProperty))#><#=Accessibility.ForProperty(navProperty)#> <#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#> <#=code.Escape(navProperty)#> 
{ 
    <#=code.SpaceAfter(Accessibility.ForGetter(navProperty))#>get 
    { 
        return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#>>("<#=navProperty.RelationshipType.FullName#>", "<#=navProperty.ToEndMember.Name#>").Value; 
    } 
    <#=code.SpaceAfter(Accessibility.ForSetter(navProperty))#>set 
    { 
        ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#>>("<#=navProperty.RelationshipType.FullName#>", "<#=navProperty.ToEndMember.Name#>").Value = value; 
    } 
} 

Replace this code with the following:

<#=code.SpaceAfter(NewModifier(navProperty))#><#=Accessibility.ForProperty(navProperty)#> <#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#> <#=code.Escape(navProperty)#> 
{ 
    <#=code.SpaceAfter(Accessibility.ForGetter(navProperty))#>get 
    { 
        return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#>>("<#=navProperty.RelationshipType.FullName#>", "<#=navProperty.ToEndMember.Name#>").Value; 
    } 
    <#=code.SpaceAfter(Accessibility.ForSetter(navProperty))#>set 
    { 
<#      AssociationType association = GetSourceSchemaTypes<AssociationType>().FirstOrDefault(_ => _.FullName == navProperty.RelationshipType.FullName); 
        if (association.ReferentialConstraints.Count > 0) { 
#> 
        #region Fix: Foreign key properties not correctly updated between new objects 
        // Update foreign key properties: 
        if(value != null) 
        { 
<#          foreach(var cons in  association.ReferentialConstraints) 
            { 
                for(int i=0; i<cons.FromProperties.Count; i++) 
                { 
                    var fromProperty = cons.FromProperties[i]; 
                    var toProperty = cons.ToProperties[i]; 
#> 
            this.<#=toProperty.Name#> = value.<#=fromProperty.Name#>; 
<# 
                } 
            } 
#> 
        } 
        else 
        { 
<#          foreach(var cons in  association.ReferentialConstraints) 
            { 
                for(int i=0; i<cons.FromProperties.Count; i++) 
                { 
                    var fromProperty = cons.FromProperties[i]; 
                    var toProperty = cons.ToProperties[i]; 
                    if (toProperty.Nullable) { 
#> 
            this.<#=toProperty.Name#> = null; 
<# 
                    } else { 
#> 
            throw new ArgumentNullException("value", "<#= String.Format("{0} of {1} cannot be null.", navProperty.Name, entity.Name) #>"); 
<# 
                    } 
                } 
            } 
#> 
        } 
        #endregion 
 
<# 
        } 
#> 
        #region Fix: Reference properties set to null require a read-first to persist 
        // When assigned value=null, preload the property before updating it 
        // to ensure EF4 detects the referential property change: 
        if(value == null) 
        { 
            var dummy = this.<#=code.Escape(navProperty)#>; 
        } 
        #endregion 
 
        // Update the relationship (=original implementation): 
        ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(), code)#>>("<#=navProperty.RelationshipType.FullName#>", "<#=navProperty.ToEndMember.Name#>").Value = value; 
 
        // Call partial On~Changed method: 
        this.On<#=code.Escape(navProperty)#>Changed(); 
    } 
} 
 
partial void On<#=code.Escape(navProperty)#>Changed(); 

Or download the “Model_fixed.tt” file (see download links below).

With this new template, a property that previously generated to:

public Customer Customer
{
    get
    {
        return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Customer>("Ef4UpdateBugDbModel.OrderCustomer", "Customer").Value;
    }
    set
    {
        ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Customer>("Ef4UpdateBugDbModel.OrderCustomer", "Customer").Value = value;
    }
} 

Will now generate into:

public Customer Customer
{
    get
    {
        return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Customer>("OrderEntityModel.OrderCustomer", "Customer").Value;
    }
    set
    {
        #region Fix: Foreign key properties not correctly updated between new objects
        // Update foreign key properties:
        if(value != null)
        {
            this.CustomerId = value.Id;
        }
        else
        {
            this.CustomerId = null;
        }
        #endregion
    
        #region Fix: Reference properties set to null require a read-first to persist
        // When assigned value=null, preload the property before updating it
        // to ensure EF4 detects the referential property change:
        if(value == null)
        {
            var dummy = this.Customer;
        }
        #endregion
    
        // Update the relationship (=original implementation):
        ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Customer>("OrderEntityModel.OrderCustomer", "Customer").Value = value;
    
        // Call partial On~Changed method:
        this.OnCustomerChanged();
    }
}
    
partial void OnCustomerChanged(); 

Notice the two code regions followed by the regular implementation. And finally, an additional partial method free for you to use.

The sample

The solution you can download contains two projects containing both the same entity model, but one using constrained associations and the other using mapped associations. Both projects consist of unittests that test and demonstrate the issues. By default, the default code generation templates of Entity Framework are used.

You can switch to the ‘fixed’ templates by doing the following in each project:

1. Expand the “Model.tt” node in the Solution Explorer
2. Select the “Model.cs” file and set it’s Build Action property to “None”
3. Expand the “Model_Fixed.tt” node in the Solution Explorer
4. Select the “Model_Fixed.cs” file and set it’s Build Action property to “Compile”

Switch from default to fixed templates in the sample project.

Downloads

Sample Application
UnderstandingAssociationsSample.zip (75.50 kb)

Fixed Model.tt template
Model_Fixed.tt (47.16 kb)

Currently rated 3.0 by 5 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

I have updated the AttachObjectGraph code lately. It has been fixed to handle correctly - I hope - inheritance and recursivity in the entity model. I have also fixed an issue related to VB.NET compatibility (apparently, a Lambda expression is compiled differently from VB.NET as from C#).

Not only the code of the AttachObjectGraph method was fixed, I've also extended the sample to contain test methods of the different situations. Therefore, the model has been extended with a recursive element (nestable CatalogFolders), and inheritance (Customer and Supplier as subtype of Contact):

Updated AttachObjectGraph sample

Unfortunately, my account on CodeProject has been corrupted and my requests to fix this have remained unanswered. Therefore, the download and article content on CodeProject will not be updated. I really hope CodeProject will restore my account such that I can continue to provide updates there too.

AttachObjectGraph code + sample (v3)
CodeProjectAttachObjectGraphSample3.zip (44.11 kb)

Currently rated 4.2 by 12 people

  • Currently 4.166667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

A new version of my CodeProject article "Reattaching Entity Graphs with the Entity Framework" has been posted. The main purpose of the update was enhancing performance, an issue brought to my attention by my colleague Luc. A description of this change can be found in the article under the chapter "Performance".

Feel free to comment on the article or code on CodeProject, and don't forget to vote for the article ;)

CodeProject - Reattaching Entity Graphs with the Entity Framework
http://www.codeproject.com/KB/architecture/attachobjectgraph.aspx

Currently rated 3.9 by 9 people

  • Currently 3.888889/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

I have spend some time lately in finalizing the code and the article that was meant for this - for now - last post on my Entity Framework serie. However, both the code and the article became quite lengthy, so I decided to publish the article on CodeProject rather than as a blog post.

Working with Entity Framework in client/server environment, I was not happy with the lack of simple solution to transfer an entity graph to the client, have it edited, then bring back the entity graph to the server, attach it to an Entity Framework context, and save it. It should be 'that simple', but reality turned differently, until...

In my article on CodeProject I present a general AttachObjectGraph() method that does exactly what I want: take a new or edited, detached entity and bring it inside an Entity Framework context, including all modifications on it, so the changes can be saved through EF's context.

Using this general method, one could define the following server operation:

void SaveInvoice(Invoice editedInvoice)
{
    using (var context = new MyContext())
    {
        context.AttachObjectGraph( editedInvoice,
            p => p.Customer,
            p => p.Lines.First().Product,
        );
        context.SaveChanges();
    }
} 

The SaveInvoice would get a new or edited invoice object graph (including its relation to a customer, invoice lines and products) in detached state, and attach it to the entity context thereby detecting whether objects in the graph have been added, removed or relinked. In other words, the above SaveInvoice method is all it takes to store back most common editing scenario's.

Take a look at the article, and let me know youer thoughts !

CodeProject - Reattaching Entity Graphs with the Entity Framework
http://www.codeproject.com/KB/architecture/attachobjectgraph.aspx

And eh (this is my first post this year), happy 2009 !

Currently rated 3.3 by 6 people

  • Currently 3.333333/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Dedicated concurrency properties 

Entity Framework offers support for optimistic locking through the ability to mark the concurrency mode of properties as "fixed".

Within Entity Framework, you can use this feature in two ways:

1. Mark (almost) all properties as having "fixed" concurrency mode. This will ensure that all properties will have their original values included in the WHERE clause of the UPDATE statement.

2. Mark a dedicated property as having "fixed" concurrency mode. This property could for instance be version number, or a datetime of last change.

The second approach requires specific support from the persistence layer. Hereby I present a solution for automating the update of dedicated concurrency properties with Entity Framework.

Sample case

Step 1 : Defining dedicated concurrency properties

Let's take a sample case. In an invoicing application, I define a "LastChanged" property on each of my entities:

 

Within the properties of the LastChanged property, the Concurrency Mode is set to "Fixed": 

Now, on the one hand the Entity Framework API does not provide at runtime information as to which properties have fixed concurrency mode (at least, I couldn't find it). On the other hand, such information would not sufice: to update the value of the dedicated concurrency property we need additional information:

Is it a dedicated concurrency property ?

What is the type of the property ?

What algorithm to use to compute it's next value ?

To provide this additional information, I introduced an OptimisticConcurrencyAttribute. This attribute decorates the entity type, tells which property is the dedicated concurrency property (usually only one, but multiple are supported) and which class to use to compute it's next value. As the EDM Designer generates entity classes that are partial, we can easily create a new part to decorate the entity type without changing the code generated by the EDM designer (and jeopardizing a regeneration by the EDM designer). For instance, I can create the following partial class:

namespace CodeTuning.Sample.Invoicing
{
    [OptimisticConcurrency("LastChanged", typeof(LocalDateTimeConcurrencyResolver))]
    partial class Customer
    {
    }
}

The LocalDateTimeConcurrencyResolver here referenced is one of three ConcurrencyResolvers pre-implemented:

LocalDateTimeConcurrencyResolver : for use with local DateTime typed dedicated concurrency properties.

UniversalDateTimeConcurrencyResolver : for use with universal DateTime typed dedicated concurrency properties.

VersionNumberConcurrencyResolver : for use with Int64 typed dedicated concurrency properties.

You can easily provide your own concurrency resolver type by implementing the following interface:

public interface IConcurrencyResolver<T>
{
    T NextValue(T actualValue);
}

Step 2 : Extending the ObjectContext

The second step is to extend the ObjectContext with the functionality to update dedicated concurrency properties on modified entities.

This is the task of the OptimisticConcurrencyManager class. Simply create an instance of it, and attach it to the context that will perform the SaveAllChanges() operation. For instance:

using (var context = new InvoicingContext())
{
    // Attach an OptimisticConcurrencyManager on the context:
    new OptimisticConcurrencyManager(context);

    ...

    // Save changes:
    context.SaveAllChanges();
}

However, the backdraw of this is that you need to attach the concurrency manager each time you create a context. I prefer to extend the context itself to have a concurrency manager attached in the following way: create a part of the partial class that the EDM designer generated, and implement the OnContextCreated partial method to create and attach an OptimisticConcurrencyManager:

namespace CodeTuning.Sample.Invoicing
{
    partial class InvoicingContext
    {
        partial void OnContextCreated()
        {
            // Automatically attach an OptimisticConcurrencyManager on each new context:
            new OptimisticConcurrencyManager(this);
        }
    }
}

That's all there is to do. The OptimisticConcurrencyManager registers to the context's WhenSavingChanges event, then queries the ObjectStateManager of the context and updates the dedicated concurrency properties of all modified entities.

If the dedicated concurrency property was modified on the entity, or by a concurrent transaction on the database, an OptimisticConcurrencyException will be raised. Otherwise, the dedicated concurrency property is updated on the entity, then checked and saved on database.

The code

The framework to support automated concurrency property updating, consists of the following code:

The IConcurrencyResolver interface:

namespace CodeTuning.Data.Entity
{
    /// <summary>
    /// Concurrency Resolver definition.
    /// </summary>
    /// <typeparam name="T">Type of the optimistic concurrency property</typeparam>
    public interface IConcurrencyResolver<T>
    {
        /// <summary>
        /// Provide the next value of the optimistic locking field, given
        /// it's actual value.
        /// </summary>
        T NextValue(T actualValue);
    }
}

Default implementations of the IConcurrencyResolver interface:

using System;

namespace CodeTuning.Data.Entity
{
    /// <summary>
    /// A ConcurrencyResolver for DateTime? properties containing LocalDateTime
    /// of last change.
    /// </summary>
    public class LocalDateTimeConcurrencyResolver : IConcurrencyResolver<DateTime?>
    {
        DateTime? IConcurrencyResolver<DateTime?>.NextValue(DateTime? actualValue)
        {
            return DateTime.Now;
        }
    }

    /// <summary>
    /// A ConcurrencyResolver for DateTime? properties containing UniversalDateTime
    /// of last change.
    /// </summary>
    public class UniversalDateTimeConcurrencyResolver : IConcurrencyResolver<DateTime?>
    {
        DateTime? IConcurrencyResolver<DateTime?>.NextValue(DateTime? actualValue)
        {
            return DateTime.UtcNow;
        }
    }

    /// <summary>
    /// A ConcurrencyResolver for Int64 properties containing a sequence number
    /// of last change.
    /// </summary>
    public class VersionNumberConcurrencyResolver : IConcurrencyResolver<long>
    {
        long IConcurrencyResolver<long>.NextValue(long actualValue)
        {
            return actualValue++;
        }
    }
}

The OptimisticConcurrencyAttribute class:

using System;
using System.Data.Objects;
using System.Linq;
using System.Reflection;

namespace CodeTuning.Data.Entity
{
    /// <summary>
    /// Declares a property for optimistic concurrency.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class OptimisticConcurrencyAttribute : Attribute
    {
        private string propertyName;
        private Type concurrencyResolverType;
        private object concurrencyResolver;

        /// <summary>
        /// Declares the optimistic concurrency attribute and its resolvertype.
        /// </summary>
        public OptimisticConcurrencyAttribute(string propertyName, Type concurrencyResolverType)
        {
            this.propertyName = propertyName;
            this.concurrencyResolverType = concurrencyResolverType;
            this.concurrencyResolver = Activator.CreateInstance(concurrencyResolverType);
        }

        /// <summary>
        /// Name of the concurrency property.
        /// </summary>
        public string PropertyName
        {
            get { return this.propertyName; }
            set { this.propertyName = value; }
        }

        /// <summary>
        /// Concurrency property value resolver type.
        /// </summary>
        public Type ConcurrencyResolverType
        {
            get { return this.concurrencyResolverType; }
            set { this.concurrencyResolverType = value; }
        }

        /// <summary>
        /// Whether the optimistic concurrency property has changed on the given instance.
        /// </summary>
        public bool HasPropertyChanged(ObjectContext context, object instance)
        {
            return context.ObjectStateManager.GetObjectStateEntry(instance).GetModifiedProperties().Contains(this.propertyName);
        }

        /// <summary>
        /// Updates the concurrency property on the given instance.
        /// </summary>
        public void UpdateInstance(object instance)
        {
            // Retrieve the property instance:
            PropertyInfo property = instance.GetType().GetProperty(this.propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            if (property == null) throw new ArgumentException(String.Format("ConcurrencyAttribute's PropertyName \"{0}\" not found."));

            // Invoke the NextValue method on the concurrency resolver, given the actual property value:
            object actualValue = property.GetValue(instance, null);
            Type iftype = typeof(IConcurrencyResolver<>).MakeGenericType(property.PropertyType);
            object nextValue = this.concurrencyResolverType.GetInterfaceMap(iftype).TargetMethods[0].Invoke(this.concurrencyResolver, new object[1] { actualValue });
            
            // Assign NextValue:
            property.SetValue(instance, nextValue, null);
        }

        /// <summary>
        /// Retrieves the OptimisticConcurrencyAttributes decorating the given entity type.
        /// </summary>
        public static OptimisticConcurrencyAttribute[] GetConcurrencyAttributes(Type entityType)
        {
            return (OptimisticConcurrencyAttribute[])entityType.GetCustomAttributes(typeof(OptimisticConcurrencyAttribute), true);
        }
    }
}

And finally the OptimisticConcurrencyManager class:

using System;
using System.Data;
using System.Data.Objects;

namespace CodeTuning.Data.Entity
{
    /// <summary>
    /// An Entity Framework addition to manage optimistic
    /// concurrency using OptimisticConcurrencyAttributes.
    /// </summary>
    public class OptimisticConcurrencyManager : IDisposable
    {
        private ObjectContext context;

        /// <summary>
        /// Instantiates a new OptimisticConcurrencyManager for the
        /// given ObjectContext.
        /// </summary>
        public OptimisticConcurrencyManager(ObjectContext context)
        {
            this.context = context;
            this.context.SavingChanges += new EventHandler(WhenSavingChanges);
        }

        /// <summary>
        /// Disposes the OptimisticConcurrencyManager, releasing it
        /// from the ObjectContext.
        /// </summary>
        public void Dispose()
        {
            if (this.context != null)
            {
                this.context.SavingChanges -= new EventHandler(WhenSavingChanges);
                this.context = null;
            }
        }

        /// <summary>
        /// Triggered when the attached ObjectContext saves changes.
        /// Changes optimistic concurrency attribute values.
        /// </summary>
        void WhenSavingChanges(object sender, EventArgs e)
        {
            // Update the concurrency properties of modified entities:
            foreach (var item in this.context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified))
            {
                object entity = item.Entity;
                foreach (var attr in OptimisticConcurrencyAttribute.GetConcurrencyAttributes(entity.GetType()))
                {
                    // Verify the property was not yet updated, which could
                    // indicate an optimistic concurrency violation:
                    if (attr.HasPropertyChanged(this.context, entity))
                        throw new OptimisticConcurrencyException(String.Format("Concurrency property {0}.{1} contains invalid update.", entity.GetType(), attr.PropertyName));

                    attr.UpdateInstance(entity);
                }
            }
        }
    }
}

Currently rated 3.8 by 16 people

  • Currently 3.75/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

The issue

One of the very nice things of Entity Framework, but mainly a feature of .NET 3.5, is the ability to express a query in a syntax that combines SQL with C#/VB.NET: Linq. Not only does Linq to Entities provide a manner to express queries on the level of ‘conceptual’ entities, it also offers the ability of compile-time validation, which is a feature not to be under-estimated !

Take for instance the following Linq to Entities query:

var query = from p
    in context.ProductSet
    where p.SalePrice > 1000
    select p;

However, Entity Framework lacks compile safety when it comes to include related objects in the query. The Include operation to be used expects a string argument containing a path of properties to include in the query results, as in:

var query = from p
    in context.ProductSet
       .Include("PriceHistory")
       .Include("Supplier.Address")
    where p.SalePrice > 1000
    select p;

This query, which is supposed to return all products priced over 1000 including their price history, supplier and their address, does compile without compile time check of the included property paths. However, I might have modelled a product as to have several suppliers and renamed the property to it’s plural form ‘Suppliers’.

I found this to be an issue I wanted to solve...

The solution

.NET 3.5 has some very interesting features of which lambda expressions allow for compile time checking of expressions without the requirement to execute them, while extension methods allow us to add or overload methods on classes not under our control.

Combining both techniques, it is possible to offer an alternative Include method which uses a lambda expression as property path. With it, I can rewrite the above query in:

var query = from p
    in context.ProductSet
       .Include(p => p.PriceHistory)
       .Include(p => p.Supplier.Address)
    where p.SalePrice > 1000
    select p;

Would I refactor my entity model to support multiple suppliers per product, then this query would result in a compile error. I could then rewrite the query as follows:

var query = from p
    in context.ProductSet
       .Include(p => p.PriceHistory)
       .Include(p => p.Suppliers.First().Address)
    where p.SalePrice > 1000
    select p;

Notice that, as Suppliers has become a collection, I can not simply dereference Address of it. I can only dereference Address on individual items of the suppliers collection. Here I chose to dereference Address on the first item of the collection. In reality, this lambda expression is merely used to produce the property path “Suppliers.Address”, which will eager load the addresses of all suppliers.

The code

The code consists of a ObjectQuery<T> extension method which receives an Expression as argument:

using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace CodeTuning.Data.Entity
{
    /// <summary>
    /// Extension methods on ObjectQuery.
    /// </summary>
    public static class ObjectQueryExtension
    {
        /// <summary>
        /// Specifies the related objects to include in the query results using
        /// a lambda expression mentioning the path members.
        /// </summary>
        /// <returns>A new System.Data.Objects.ObjectQuery<T> with the defined query path.</returns>
        public static ObjectQuery<T> Include<T>(this ObjectQuery<T> query, Expression<Func<T, object>> path)
        {
            // Retrieve member path:
            List<PropertyInfo> members = new List<PropertyInfo>();
            EntityFrameworkHelper.CollectRelationalMembers(path, members);

            // Build string path:
            StringBuilder sb = new StringBuilder();
            string separator = "";
            foreach (MemberInfo member in members)
            {
                sb.Append(separator);
                sb.Append(member.Name);
                separator = ".";
            }

            // Apply Include:
            return query.Include(sb.ToString());
        }
    }
}

The core functionality of 'parsing' the lambda expression is isolated in a separate EntityFrameworkHelper class. I've done this because I reused this parser code for another feature which will be subject of a leter post on this blog:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace CodeTuning.Data.Entity
{
    internal static class EntityFrameworkHelper
    {
        internal static void CollectRelationalMembers(Expression exp, IList<PropertyInfo> members)
        {
            if (exp.NodeType == ExpressionType.Lambda)
            {
                // At root, explore body:
                CollectRelationalMembers(((LambdaExpression)exp).Body, members);
            }
            else if (exp.NodeType == ExpressionType.MemberAccess)
            {
                MemberExpression mexp = (MemberExpression)exp;
                CollectRelationalMembers(mexp.Expression, members);
                members.Add((PropertyInfo)mexp.Member);
            }
            else if (exp.NodeType == ExpressionType.Call)
            {
                MethodCallExpression cexp = (MethodCallExpression)exp;

                if (cexp.Method.IsStatic == false)
                    throw new InvalidOperationException("Invalid type of expression.");

                foreach (var arg in cexp.Arguments)
                    CollectRelationalMembers(arg, members);
            }
            else if (exp.NodeType == ExpressionType.Parameter)
            {
                // Reached the toplevel:
                return;
            }
            else
            {
                throw new InvalidOperationException("Invalid type of expression.");
            }
        }
    }
}

You can download this code from the following link:
EF_LambdaInclude.zip (1.35 kb)

Currently rated 4.5 by 22 people

  • Currently 4.545455/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

I recently started investigating Entity Framework version 1. As many others have preceded me, I will not discuss what I believe are important issues or design flaws of EF. In stead I will focus on how to solve some of the issues and how to make better use of EF, as I believe EF deserves our attention.

Although I am not always thrilled of the Visual Studio designers that generate a lot of cumbersome code that does not fit in my frameworks, I decided to stick to the EDM designer which provides a graphical representation of my entities, and generates code that, thanks to partial classes and partial methods, is extensible to some degree. The knowledge that Microsoft intends to allow customization of the code generation process in later versions gives me satisfaction.

Focussing on client-server applications, I prepared some posts about better responsibility distribution and coping with detached object graphs.

So, stay tuned !

Currently rated 3.8 by 8 people

  • Currently 3.75/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Code Tuning .NET

For better development practices