(MEF) Composable Entities with Entity Framework

by Rudi20. September 2012 00:04

When applying Domain Driven Design, entities are not only data containers, they are also the classes on which the business logic is implemented. However, business logic implementation may require access to services that would typically be injected using a dependency injection framework.
This article explains how entity materialization can be intercepted to apply MEF composition with Entity Framework.
The sample that comes with this article demonstrates MEF composition on entity materialization within the context of a WCF service:

Composable Entities Sample
ComposableEntitiesSample.zip (135.12 kb)

An example

Take for instance an order processing application. In a DDD-approach, it would be the Order object itself that would be in charge of its own processing. In other words, the Order class would have a ProcessOrder() method. The ProcessOrder() method could then delegate the processing of individal order lines to the OrderLine.ProcessOrderLine() method.

But what if the processing of an orderline requires access to the Entity Framework ObjectContext, or to other services ? For instance a stockservice ?

Instances of OrderLine  are created ('materialized') by the Entity Framework. How then can we get contexts and services injected by for instance MEF (Managed Extensibility Framework) ?

A composable WCF service

To start with, we need a composable WCF service (or an other environment set up for composition or dependency injection). In the enclosed sample, both the OrderService and StockService have MEF composition enabled.

The sample shows two ways of enabling composition on a WCF service. The OrderService has its service implementation class decorated with a [ComposableBehavior] attribute:

[ServiceBehavior]
[ComposableBehavior]
public class OrderService : Contract.IOrderService
{
    [Import]
    internal OrderContext Context;
    ...
}

The StockService does not have this, but the web.config of the StockService defines a "composable" service behavior. See the following extract of the web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          ...
          <composable />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="composable" type="Library.Services.Composition.ComposableBehavior, Library.Services" />
      </behaviorExtensions>
    </extensions>
    ...
  </system.serviceModel>
  ...
</configuration>

The result is basically the same. Both services can now declare fields with the [Import] MEF-attribute so that those services will be injected:

public class StockService : Contract.IStockService
{
    [Import]
    internal StockContext Context;
    ...
}

In this case, the Entity Framework ObjectContext is injected, this required the addition of an [Export] attribute on the StockContext class, which could be performed on a partial class declaration. See StockModel.cs:

[Export]
partial class StockContext
{
    ...
}

That's it! We have 2 WCF services that rely on MEF composition for injecting their Entity Framework context (the OrderService also has a StockService injected; it is not used, I just added it for the demo).

Composable Entities

Both services have facade class, the service implementation. For the OrderService, that's the OrderService class. When something is asked to the service implementation, it will typically delegate the request to the responsible domain object. For instance, to 'process' an order, the ProcessOrder request is delegated to the concerning Order entity:

[ServiceBehavior]
[ComposableBehavior]
public class OrderService : Contract.IOrderService
{
    [Import]
    internal OrderContext Context;
    ...
 
    [OperationBehavior]
    public bool ProcessOrder(int orderId)
    {
        var order = Context.Orders.Single(it => it.Id == orderId);
        order.ProcessOrder();
        Context.SaveChanges();
        return order.Completed;
    }
}

But what now if the Order entity needs access to the context or to external services ? Can we compose this entity ?

The good news is, yes, we can ! And it's not even that hard to achieve.

The ObjectContext class has an ObjectMaterialized event that is send for every entity that is materialized: the ideal time to apply composition to the object.

In addition, our ComposableBehavior implementation stores the MEF composition container in the WCF InstanceContext extensions, making it available throughout the processing of WCF requests. Thanks to this, we can at all times access the composition container through (ServiceComposer is a wrapper around the effective MEF composition container):

ServiceComposer.Current

In the sample, I made the EF contexts not only [Export]ed, but I also added an OnContextCreated method that creates a 'CompositionHandler':

[Export]
partial class OrderContext
{
    partial void OnContextCreated()
    {
        new CompositionHandler(this);
    }
}

The CompositionHandler caputres the ObjectMaterialized event, where it composes the entity using the compositionContainer installed as extension on the InstanceContext.

As a result, an entity as OrderLine can also be composed (see its [Import]ed fields composed):

partial class OrderLine
{
    [Import]
    internal Lazy<StockService> StockService;
 
    public void ProcessOrderLine()
    {
        ... some code using the StockService ...
    }
}

The sample

The sample consists of a an ASP.NET MVC3 client application and 2 WCF services (OrderService and StockService). The common classes to perform composition are located in the Library.Services library project.

An SQL script is also provided to create the database under the ".\SQLEXPRESS" instance (or another instance provided you change the connectionstrings in the web.config and app.config files).

The MVC client application is very basic, it allows for adding items to a current order, then place that order, then try to process that order, and finally place backorders to refill the stock.

Two different ComposableBehavior implementations

The sample uses the instance based composable behavior, but the solution contains two different implementations of composable behaviors: instance based and request based. You will find both implementations under Library.Services/Composition.

The request based implementation uses the same class names, but is disabled by setting its file build actions to "None".

The difference between both implementations is that the instance based composable behavior uses an IInstanceProvider to provide a composed instance of the service, while the request based behavior uses an IDispatchMessageInspector to apply composition on a per request basis.

In principle the instance based approach is better as it correctly takes into account how WCF performs instantiation (per request, per session,...) while the per request approach only works if you also use per request instantiation. But I have one problem with the IInstanceProvider implementation: you cannot chain instance providers, hence, when I implement an instance provider to add some behavior, I must rewrite all behavior. So in cases where you work with per request instantiation, you might choose for the request based approach.

Tags:

Entity Framework | Dependency injection

Unittesting ADO.NET Entity Data Models

by Rudi17. September 2012 23:59

Entiy Framework 4.0 claimed to be unittestable. Unfortunately, that was only the case for ‘code first’ usage. The "ADO.NET Entity Data Model" way of using Entity Framework (with a drawn entity model) was still not unittestable (without a powerful IL-rewriting mocking tool).

In this article I’ll explain what has to be done in order to make entity data models mockable and unittestable.

The article comes with a sample solution containing an entity model, some code around it, and a (small) battery of unittests.

Unittesting Entity Framework Sample
UnittestingEntityFrameworkSample.zip (40.60 kb)

Note: this article and the delivered code is written towards Entity Framework 4.0.

Creating the model

Before unittesting a model, of course, we need to have a model. Either take an entity model you already have, or create one by adding an "ADO.NET Entity Data Model" to your project, then either generate a model from database, or start with an empty model to design the model yourself.

Making the model testable/mockable

The problem with the code generated by default by the ADO.NET Entity Data Model Designer, is that it does not allow unittesting the generated ObjectContext (without a living backend database). The reason for that is partially because the generated ObjectContext does not define an interface that allows mocking the context.

The solution is however easy as the Entity Data Model Designer allows using a custom code generation template (see: http://msdn.microsoft.com/en-us/library/dd456821.aspx).

First, and if you have not yet done so, install the "EF 4.x EntityObject Generator for C#" from within Visual Studio’s Extension Manager, or by downloading and installing from the following link:

http://visualstudiogallery.msdn.microsoft.com/e6db6554-345c-477a-9a73-3c5db06e9081

Next, on your Entity Model, right-click and choose "Add Code Generation Item...":

Then choose for the "ADO.NET Testable EntityObject Generator":

Finally, check the properties of your entity model: the Code Generation Strategy property should be "None":

Congratulations, you are now ready to... begin make your context testable!

What the code generation template did, was change the generation of your context class to also define a context interface, and to make the context class implement that interface.

The default Entity Data Model Designer code generation template generates something as:

public partial class SomeContext : ObjectContext
{
    public ObjectSet<Customer> Customers ...
    ...
}
 

The "EF 4.x EntityObject Generator for C#" generation template changed this into something as:

public partial interface ISomeContext
{
    public IObjectSet<Customer> Customers;
    ...
}
 
public partial class SomeContext : ObjectContext, ISomeContext
{
    public IObjectSet<Customer> Customers ...
    ...
}
 

So it added an ISomeContext interface and made SomeContext implement that interface. In addition, the entity set members are of type IObjectSet<T> instead of ObjectSet<T>, an important change!

This is a good step forward towards a testable context as the context now relies more on interfaces. But there’s still one missing interface: IObjectContext. The IObjectContext interface is not defined in the .NET framework and so we need to create it ourself. In the enclosed solution you will find the IObjectContext interface in the "Library" project, in the "System.Data.Objects" folder/namespace.

As the IObjectContext is not part of the .NET framework, I didn’t want the code generated by the "EF 4.x EntityObject Generator for C#" template to rely on that interface as it would create an additional dependency on an external library and limit the usability of that template.

Fortunately, thanks to partial classes you can now easily ensure the SomeContext class implements IObjectContext by adding following code (in the enclosed solution this is done in the "Model.cs" file of the "Sample.Domain" project):

partial interface ISomeContext : IObjectContext
{ }
 

(You could also have declared the class SomeContext to implement IObjectContext instead, both ways are good.)

We now have our context inheriting ObjectContext, and implementing a custom context interface that inherits from a custom IObjectContext: our context class is now the implementation of an interface and becomes subject to mocking:

Mocking the objectcontext

We can now start coding (provided we rely on the interfaces to ensure the code is unittestable) and write unittests to test our code.
Within the unittests, we will use a mock of the context. The mock class still needs to be implemented, but the Library project of the enclosed solution provides you a helpful base class: MockObjectContext. Using this class, we can now write a mock context class as follows:

public class MockSomeContext : MockObjectContext, ISomeContext
{
    public MockSomeContext()
        : base(new SomeContext())
    { }
 
    public IObjectSet<Customer> Customers
    {
        get { return this.GetObjectSet<Customer>(); }
    }
    ...
}
 

The context mock is basically a class inheriting from MockObjectContext and implementing our context interface. Thanks to the GetObjectSet<T>() method of its base class, implementing the context interface is easy.

One noteworthy remark: the constructor passes a real context instance to it’s base constructor! The reason for this is that the context mock uses a real context behind the scenes. This ensures that the expected behavior of an object context remains guaranteed.

(You could eventually think of creating a .tt text template to create mock contexts based on the real context class.)

In the enclosed sample I have added the following code to the context mock class:

    #region MockObjectContext overrides
 
    private int nextId = 0;
 
    protected override void WhenSavingAddedEntity(object entity)
    {
        var idProp = entity.GetType().GetProperty("Id");
        if (idProp != null && idProp.CanWrite)
        {
            idProp.SetValue(entity, --nextId, null);
        }
    }
 
    protected override void WhenSavingAddedRelationship()
    {
    }
 
    #endregion
 

This provides every entity with a unique "Id" value (as I’m using primary key int Id values on my model). I make the values negative to avoid conflicts with id values set explicitely. If you always set primary keys explicitely, you could leave both methods empty.

Writing unittests

We are now ready to write unittests!

One of the tests in the enclosed solution is the following:

[TestClass]
public class StockManagerTest
{
    [TestMethod]
    public void DoNotCreateNewLineInOrderWhenArticleAlreadyPresentTest()
    {
        using (var context = new MockStockContext())
        {
            #region Test Setup
            context.Articles.AddObject(new Article()
                  { Id = 1, Name = "a", StockCount = 0, ReorderTarget = 0 });
            context.Orders.AddObject(new Order()
                  { Id = 1 });
            context.OrderLines.AddObject(new OrderLine()
                  { OrderId = 1, ArticleId = 1, Quantity = 12 });
            context.ResetForTest();
            #endregion
 
            // Test:
            var manager = new StockManager() { Context = context };
            manager.AddToOrder(1, 1, 4);
 
            // Assert:
            Assert.AreEqual(1, context.OrderLines.First().OrderId);
            Assert.AreEqual(1, context.OrderLines.First().ArticleId);
            Assert.AreEqual(16, context.OrderLines.First().Quantity, 
               "OrderLine should now have 16 items");
            context.AssertSavedChangesOfType<OrderLine>(0, 1, 0);
            context.AssertSavedChangesOfAnyType(0, 1, 0);
        }
    }
}
 

In the "Test Setup" region, entities are added to the context to create an initial situation. In this case, an Article, Order and OrderLine entity are added. The entities are also related to each other (the ArticleId of the OrderLine is the Id of the Article).
Once the context contains all entities needed to be able to start the test, the "ResetForTest()" method of the mock context should be called. This will reset all status counters, telling that the context contains no changes.

Next, perform the test. The test creates a StockManager, then tries to add 4 pieces of an article already present on the given order. The idea is that when an orderline already exists for that article, no new orderline is created, but the existing orderline is altered.

And that is exactly what is asserted in the "Assert" section of the test.

The "context.AssertSavedChangesOfType<OrderLine>(0, 1, 0)" line asserts that of the entity type OrderLine, none was added, none was deleted, and exactly one was modified.

The AssertSavedChangesOfType<T>() method of MockObjectContext has the following signature:
public void AssertSavedChangesOfType<T>(int? additions, int? modifications, int? deletions)

In addition, the "context.AssertSavedChangesOfAnyType(0, 1, 0)" does the same check, but over all entity types. In other words, this line checks that of all entities, only one was modified, none added and none deleted.

When you write a test that should not impact the database, you could end the test with the assertion "context.AssertNoSavedChanges()", which asserts that nothing was saved by the context.

Unittests with (MEF) composition

It is also possible to have MEF or another dependency injection framework compose the objects for the unittest. I’ve included a "ComposedStockManagerTest" class in the test project to demonstrate that.

About the enclosed solution

The enclosed solution contains the following elements:

A database script to recreate the database used in the sample (although, running the unittests do not require a life database, you’ll only need the database if you want to run the sample console application or update the entity model.

A "Library" project containing the IObjectContext interface as well as the MockObjectContext base class.

A "Sample.ConsoleClient" project, just to proof the code also works outside unittests.

A "Sample.Domain" project, that’s where the entity model resides !

A "Sample.Domain.Test" project, that’s where the MockStockContext class and the unittests reside !

Conclusions

Once setup, it is possible to write unittest for code that relies on Entity Framework data models and even perform assertions on the interaction with the Entity Framework object context. The unittests are straight-forward, easy to read and write. Because the MockObjectContexts uses a real ObjectContext behind the scenes, the behavior of an ObjectContext (especially towards associations) is still present (if you set the customer property of an order, the orders property of that customer will contain that order).

Tags:

Development practice | Entity Framework | Microsoft .NET | Unit testing

Understanding Entity Framework Associations

by Rudi17. February 2011 22:21

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)

Tags:

Entity Framework

Static Code Analyser (2)

by Rudi16. March 2010 02:12

Sequel

It took me some time, but I finally wrote the sequel on my post of the Static Code Analyzer.

Whereas my previous post was more of a teaser to the code analyzer capabilities, I have now published a complete article on the subject on CodeProject. The article describes haw the code analyzer operates and how you can use it for different code analysis applications including a website to document the dependencies of your application:

Sample Website generated by Code Analysis
(Click on the website image for a life version :))

The whole article including updated code of the Code Analyzer is available on CodeProject through the link below.

The download also includes a little sample application combining WPF, WCF and Entity Framework. You may find it a handy sample if you want to learn any of those technologies.

CodeProject - Static Code Analysis
http://www.codeproject.com/script/Articles/Article.aspx?aid=63872

 

Tags:

Code analysis | Development practice

Updating/Binding Model Graphs with ASP.NET MVC

by Rudi24. February 2010 21:47

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)

Tags:

ASP.NET MVC

Static Code Analyser (1)

by Rudi2. July 2009 01:35

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).

Tags:

Code analysis

Entity Framework - reattaching entity graphs (3)

by Rudi10. June 2009 22:42

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)

Tags:

Entity Framework

Entity Framework - reattaching entity graphs (2)

by Rudi26. February 2009 18:27

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

Tags:

Entity Framework

Entity Framework - reattaching entity graphs

by Rudi6. February 2009 00:50

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 !

Tags:

Entity Framework

Entity Framework - a concurrency manager

by Rudi16. December 2008 21:22

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);
}
}
}
}
}

Tags:

Entity Framework

About me

Widget Month List not found.

The file '/blog/widgets/Month List/widget.ascx' does not exist.X

Widget Page List not found.

The file '/blog/widgets/Page List/widget.ascx' does not exist.X