Search code examples
sql-serverentity-framework-6xaf

Which tables should have a timestamp column? Concurrency check with Entity Framework, XAF, DDD


I am using Dev Express XAF WinForms to write an ERP system.

In practice I have found that my DBContext needs to have a DBSet for most of my business objects.

I am trying to figure out which tables should have a timestamp column for optimistic concurrency purposes.

For example I have

[NavigationItem("Sales")]
public class SalesOrder : BaseSalesHeader 
{
    public SalesOrder()
    {
       Lines = new List<SalesOrderLine>();
    }
    [Aggregated]
    public virtual List<SalesOrderLine> Lines { get; set; }  
}

[NavigationItem("Production")]
 public class SalesOrderLine : BaseSalesProductTransactionLine 
{

    [Browsable(false)]
    [System.ComponentModel.DataAnnotations.Required]  
    [RuleRequiredField(DefaultContexts.Save)]
    [ForeignKey("SalesOrder_Id")]
    public virtual SalesOrder SalesOrder { get; set; }
}

In my DBContext I have

    public DbSet<SalesOrder> SalesOrders { get; set; }
    public DbSet<SalesOrderLine> SalesOrderLines { get; set; }

In my OnModelCreating I have

    modelBuilder.Entity<SalesOrder>().HasMany(p => p.Lines).WithRequired(t => t.SalesOrder).WillCascadeOnDelete(true);

Sales Order Lines are accessible from 2 Menus As part of a Sales Order, and as a Sales Order Line Item under the Production navigation item.

I think I should have the timestamp field in the SalesOrders table. Should I also have it in the SalesOrderLine table ?

Here is the linked question at Dev Express Support


Solution

  • Whether or not you want to apply optimistic concurrency (OC) for an entity is something we can't decide for you. But there are some things to consider:

    • It's not necessarily true that only entities that are exposed as DbSet will need OC. After all, any mapped entity can be changed when it's reachable through navigation properties. SalesOrder exposes SalesOrderLines by its Line property, so by all means you can create some UI that only modifies SalesOrderLines while it only receives a SalesOrder (including its lines) as input.
    • In Entity Framework (and other ORMs), a parent isn't marked as modified when one of its children is modified. If you save a SalesOrder with modified SalesOrderLines, there will only be update statements for the lines.

    So, yes, you probably want to protect SalesOrderLine by OC as well. But also consider this:

    • OC isn't for free. When you add a RowVersion* column to a table (and map it as rowversion appropriately), Entity Framework will read its value after each insert or update. I've experienced that this may considerably harm performance in processes that update relatively many records (EF doesn't shine there anyway). Also, when a concurrency conflict occurs, EF will read the current values of the conflicting record(s) from the database.

    I've seen applications where the performance impact from OC is mitigated by marking a parent object (having OC) as modified when any of its children is modified. I think that's rather contrived, but it may be something to consider.


    * TimeStamp is a deprecated data type