Introduction

This post describes issues and solutions involved when using 'complex' object graphs as models for ASP.NET MVC applications.

The ASP.NET MVC Controller class has a TryUpdateModel() method that is described in the API reference on MSDN as "Updates the specified model instance using values from the controller's current value provider":

protected internal bool TryUpdateModel<TModel>(TModel model)

This method does this correctly on the given model and even on nested objects (which is really how it should be). But when the object graph consists of collections (or dictionaries), the result may not be what you expect...

Applies to: this behavior has been observed on ASP.NET MVC2 RC2 (which is the latest version at the time of writing) and earlier versions.

The context

Note: the context described here is fictious and only meant to describe the problem type. Aspects as security and design are deliberately ignored ;)

Within an ASP.NET MVC application, I want to allow customers to update the quantities on a placed order. For this, I’ve a form that looks like:

<% Html.BeginForm("SaveOrder", "Order"); %>
<%= Html.HiddenFor(m => m.Id) %>
<%= Html.EditorFor(m => m.Customer.Phone) %>
<% for(int i=0; i<Model.Lines.Count; i++) { %>
    <% // if (i==0) continue; %>
    <p>
        <%= Html.EditorFor(m => m.Lines[i].Quantity) %>
        x <%= Model.Lines[i].UnitPrice) %>
        of <%= Model.Lines[i].Product.Name %>
    </p>
<% } %>
<input type="submit" value="Submit" />
<% Html.EndForm(); %>

So it shows the order lines, allows for editing the quantity of each line, and shows the name of the product associated with the line. It could have been possible to put all the information of the order in hidden fields, but this is deliberately not done as we do not want to divulgate all this information (security and privacy reasons).

To save the order, we need to retrieve the original order, then update the order with the values of the form postback, and then save the updated order. The SaveOrder action is implemented as follows:

public ActionResult SaveOrder(int id)
{
    // Retrieve the original order from the service:
    Order order = Service.GetOrder(id);

    // Update the order by the form postback:
    this.TryUpdateModel(order);

    // If valid, save the updated order:
    if (ModelState.IsValid)
    {
        order = Service.SaveOrder(order);
    }

    return RedirectToAction("Index", new { Id = order.Id });
}

This is what we would like to have. Unfortunately, it does not work...

Before the call to TryUpdateModel(), my order consists of OrderLines having quantity, unitprice and associated product. After the TryUpdateModel() call, though the quantities on my OrderLines have been updated, the unitprice and associated product have been removed !

The problem

The TryUpdateModel() method, to which a model is given, is supposed to update the given model and not to return a new model. It does this correctly for 'simple' models. Even for 'nested' models, this behavior is correct: I've added an EditorFor the phone number of the customer on the form and the TryUpdateModel() will correctly update the phone number of the provided customer object, leaving the customer’s name, email and address properties intact.

So it works fine for the root model object and all nested objects and can thus update a whole object graph. Except... when the object graph contains collections. While the Customer of my Order is correctly updated, the OrderLines of my Order are not, they are replaced with new instances containing only the properties of my form postback.

Not only is this behavior inconsistent with the behavior of parts in my object graph that are not beneath a collection, it is also contrary to the behavior I would expect from a method called TryUpdateModel(). If the method is to create new model objects instead of updating given ones, it should be named TryCreateModel() and should not require a model argument.

The cause

To find the cause of the problem, we need to delve deep into the implementation of the DefaultModelBinder class in System.Web.Mvc. After a thorough understanding of the problem and a few debugging sessions in the DefaultModelBinder implementation, I could pinpoint the issue. The DefaultModelBinder class uses an internal UpdateCollection() method to bind collection members. Within this method, an 'inner' ModelBindingContext is constructed for each collection member, to bind it. However, when constructing this inner ModelBindingContext, a "null" model value is passed to it (line 7 in the code below), such that binding has to happen on a new instance of the collection member instead of on the existing member...

The original code of the UpdateCollection() method (in MVC2 RC2) looks like this:

...
foreach (string currentIndex in indexes) {
    ...

    ModelBindingContext innerContext = new ModelBindingContext() {
        ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
                        null, elementType),
        ModelName = subIndexKey,
        ModelState = bindingContext.ModelState,
        PropertyFilter = bindingContext.PropertyFilter,
        ValueProvider = bindingContext.ValueProvider
    };
    object thisElement = elementBinder.BindModel(controllerContext, innerContext);

    ...
}
...

Because of the null passed as first argument of the GetMetaDataForType() method, model binding of each element of the collection has to be done towards a null object, hence a new instance is to be created. This issue can be solved by replacing the above implementation with:

...
foreach (string currentIndex in indexes) {
    ...

    object model = null;
    Func<object> modelAccessor = null;
    if ((bindingContext.Model != null)
        && (true))
    {
        model = bindingContext.Model.GetType().GetProperty("Item")
                .GetValue(bindingContext.Model, 
                 new object[] { Convert.ToInt32(currentIndex) });
        modelAccessor = delegate() { return model; };
    }
    ModelBindingContext innerContext = new ModelBindingContext() {
        ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
                        modelAccessor, elementType),
        ModelName = subIndexKey,
        ModelState = bindingContext.ModelState,
        PropertyFilter = bindingContext.PropertyFilter,
        ValueProvider = bindingContext.ValueProvider
    };
    object thisElement = elementBinder.BindModel(controllerContext, innerContext);

    ...
}
...

But of course, to apply this solution we need to update the original DefaultModelBinder class implementation.

Solving the problem

Unless we work at Microsoft and can update the implementation of the DefaultModelBinder, the only thing we can do is implement our own 'Default' ModelBinder. The UpdateCollection() method is internal to DefaultModelBinder, and we cannot simply inherit of DefaultModelBinder to override that single method. We don’t want to rewrite the DefaultModelBinder from scratch either, as this is quite complex, it could break compatibility with later releases of ASP.NET MVC, and we really only want to change 0.3% of it’s code...

Fortunately, ASP.NET MVC is well designed and quite extensible, and it’s DefaultModelBinder recursively calls the overridable BindModel on each step in the model binding process. So what we can do, is specialize from DefaultModelBinder, override it’s BindModel method, and always delegate it to its base implementation, except when collections are to be bound.

The following implementation should do the trick:

/// <summary>
/// A DefaultModelBinder that can update complex model graphs.
/// </summary>
public class DefaultGraphModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // Bind collections 'our way':
        if ((bindingContext.Model.IsCollection())
            && (bindingContext.Model.CollectionGetCount() > 0))
            return this.BindCollection(controllerContext, bindingContext);
        else
            return base.BindModel(controllerContext, bindingContext);
    }

    private object BindCollection(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        object collection = bindingContext.Model;
        Type collectionMemberType = typeof(Object);
        if (collection.GetType().IsGenericType)
            collectionMemberType = 
                collection.GetType().GetGenericArguments()[0];
        int count = collection.CollectionGetCount();
        for (int index = 0; index < count; index++)
        {
            // Create a BindingContext for the collection member:
            ModelBindingContext innerContext = new ModelBindingContext();
            object member = collection.CollectionGetItem(index);
            Type memberType = 
                (member == null) ? collectionMemberType : member.GetType();
            innerContext.ModelMetadata = 
                ModelMetadataProviders.Current.GetMetadataForType(
                    delegate() { return member; },
                    memberType);
            innerContext.ModelName =
                String.Format("{0}[{1}]", bindingContext.ModelName, index);
            innerContext.ModelState = bindingContext.ModelState;
            innerContext.PropertyFilter = bindingContext.PropertyFilter;
            innerContext.ValueProvider = bindingContext.ValueProvider;

            // Bind the collection member:
            IModelBinder binder = Binders.GetBinder(memberType);
            object boundMember = 
                binder.BindModel(controllerContext, innerContext) ?? member;
            collection.CollectionSetItem(index, boundMember);
        }

        // Return the collection:
        return collection;
    }
}

internal static class DefaultModelGraphBinderCollectionExtensions
{
    public static bool IsCollection(this object obj)
    {
        return (obj != null)
            && (obj.GetType() != typeof(String))
            && (typeof(System.Collections.IEnumerable).IsInstanceOfType(obj));
    }

    public static int CollectionGetCount(this object collection)
    {
        if (collection.GetType().IsArray)
            return ((Array)collection).GetLength(0);
        else
            return (int)collection.GetType().GetProperty("Count")
                .GetValue(collection, null);
    }

    public static object CollectionGetItem(this object collection, int index)
    {
        if (collection.GetType().IsArray)
            return ((Array)collection).GetValue(index);
        else
            return collection.GetType().GetProperty("Item")
                .GetValue(collection, new object[] { index });
    }

    public static void CollectionSetItem(this object collection, int index, object value)
    {
        if (collection.GetType().IsArray)
            ((Array)collection).SetValue(value, index);
        else
            collection.GetType().GetProperty("Item")
                .SetValue(collection, value, new object[] { index });
    }
}

To install this model binder as the default one, add the following line of code in the Application_Start method of the Global.asax.cs file:

ModelBinders.Binders.DefaultBinder = new DefaultGraphModelBinder();

Robustness

There are for sure some remarks to do on the given implementation. For instance it’s use of reflection and assumption that an instance of IEnumerable has properties Count and Item. The implementation will certainly have to grow whenever unsupported cases are met.

Furthermore, within this implementation we assume that the index is an integer starting at 0. Although the original DefaultModelBinder does not seem to make this assumption, it appears not to work when that’s not the case. For instance, if you uncomment the code in the following line in the view,

<% // if (i==0) continue; %>
then the original DefaultModelBinder does not succeed in binding the collection. The above implementation will successfully bind the other collection members.

Another story is the support of dictionaries which I haven’t tested so far.

Conclusions

Though the current ASP.NET MVC implementation still has some imperfections probably due to a rapid growth of supported features (also remember I used a release candidate version), thanks to it’s open and extensible architecture, it is possible to tailor the framework to your specific requirements with limited rework.

Download

The sample order application can be downloaded here. It simulates a basic order editing system and demonstrates the operation of the DefaultGraphModelBinder.

DefaultGraphModelBinder sample Order application
MvcGraphBindingSample.zip (20.94 kb)

Currently rated 5.0 by 2 people

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

Static Code Analyser (1)

Published 7/2/2009 by Rudi in Code analysis

Introduction 

An automated code analyzer can come in handy when maintaining and refactoring an existing project. For this goal I have written a 'static code analyzer', that's a code analyzer that operates by analyzing compiled assemblies. It thereby analyzes the method calls and builds a graph of which method calls which method. The result of the analyzer is a graph in memory that looks like what's represented in the following picture:

In fact, the analyzer has no notion of classes or types, it only looks to the methods and their calls. So from the picture, the analyzer only sees the green dots and their connecting lines.

Still, with this limited view, and with some 'smart algorithms', this code analyzer can be used for a lot of applications, including:

Providing a simplified view on the application logic

Asserting certain coding conventions

Detecting 'dead code'

Checking test code coverage (on method level)

Checking test code quality (i.e. whether Assert methods are called)

...

To ease you in writing those several applications, the analyzer comes with an extensible set of 'processors' including a rule based processor!

Getting started

To run the analyzer, you first need to write an XML file that describes the analysis process. The code analyzer can then be started with the following code (where "SomeProfile.xml" is the process description file):

// Create an AnalyzerSession and process it through an Analyzer:
StaticCodeAnalyzerSession session = new StaticCodeAnalyzerSession(@"SomeProfile.xml");
StaticCodeAnalyzer analyzer = new StaticCodeAnalyzer();
MethodList methods = analyzer.Process(session);

The MethodList object that is returned by the Process method is a list of all methods (ma1, ma2, ma3, mb1, mb2, mb3, mb4, ..., me3, me4) of the assemblies that were analyzed. The list contains objects of type "Arebis.CodeAnalysis.Static.Method", which provides properties as CallsMethods (which methods are directly called by this one), CalledByMethods (which methods call this method directly), but also GetAllCallsMethods() and GetAllCalledByMethods() methods which retrieve both directly and indirectly called methods.

For instance, the GetAllCalledByMethods() on method mc2 will return: ma2, ma3, mb2, mb3, mb4 and mb5.

The MethodBase property provides access to the "System.Reflection.MethodBase" object matching this method:

The analysis process description is an XML file that has the following structure:

<?xml version="1.0" encoding="utf-8" ?>
<analyzer>
  <assemblies>
    ...
  </assemblies>
  <language code="C#">
    ...
  </language>
  <processors>
    ...
  </processors>
</analyzer>

The <assemblies> section lists, using wildcards, the assemblies to include in the analysis.

The <language> section describes the programming language to use. This is not used during the analysis process, but is used afterwards, when you ask string representations of method signatures etc. (the language settings will for instance replace "System.Int32" into "int" and remove known namespaces).

The <processors> section contains custom processors to run during the analysis process. You can easily implement your own processors by implementing the IProcessor interface, but for the most common tasks, predefined processors are already provided, including a rule based one.

namespace Arebis.CodeAnalysis.Static
{
    public interface IProcessor
    {
        void Initialize(XmlNode processorInstance);
        void Process(MethodList methods);
    }
}

In next posts on this blog, I will explain how to use the rule based processor and other provided processors to write some useful applications.

In the mean time, take a look at the following sample, including all the code of the static code analyzer. The sample already enviels how to detect dead code and perform other analysis tasks:

Static Code Analyzer code & sample
StaticCodeAnalyzerSample.zip (42.79 kb)

Note that the code assumes .NET 3.5 and also the Microsoft Parallel Extensions (System.Threading.dll). If you don't have .NET 3.5, you'll have to change the sample code (which yses LINQ), but on the code analyzer, you'll only have to change the reference to the HashSet<T> class to use the one provided in the Arebis.Common project. If you don't have the Microsoft Parallel Extensions, you can use the "Parallel" class provided in the Arebis.Common project, or even replace the Parallel.ForEach call into a regular foreach.

For this project, I must thank Sorin Serban, which did most of the work for the core of the analyzer engine by publish his method body parser on CodeProject (http://www.codeproject.com/KB/cs/sdilreader.aspx).

Currently rated 4.5 by 2 people

  • Currently 4.5/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 5.0 by 5 people

  • Currently 5/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 5.0 by 4 people

  • Currently 5/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 5.0 by 1 people

  • Currently 5/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 5.0 by 4 people

  • Currently 5/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 5.0 by 9 people

  • Currently 5/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 5.0 by 3 people

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

Welcome to codetuning.net

Published 11/23/2008 by Rudi in General

Welcome to my blog. I am Rudi Breedenraedt, software architect living in Belgium. Early eighties I started developing on a Sinclair home computer using Basic and Z80 assembler. In the next decennia I’ve played with different environments and languages: QuickBasic and Visual Basic, object oriented Turbo Pascal, C and C++, assembler, Smalltalk, Java,… Nowadays I lead .NET software development projects as a technical architect at RealDolmen.

Codetuning.net is about code tuning in .NET: writing quality code in an object oriented language. I hope you will find this blog to be a valuable source for better coding techniques, design patterns, tricks and solutions.

My experience has led me to believe that quality software is readable and maintainable yet powerful. A good design should be simple, intuitive, and focussed on responsibility distribution. Design patterns should be applied because they fit the needs, not because they exist.



"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away."

Antoine de Saint-Exupery.

Be the first to rate this post

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

Code Tuning .NET

For better development practices