title: Overriding SaveChanges in Entity Framework 5 Code First to replicate the behavior of an old legacy library
body: <p>Our company ships a suite of various applications that manipulate data in a database. Each application has its specific business logic, but all applications share a common subset of business rules. The common stuff is incapsulated in a bunch of legacy COM DLLs, written in C++, which use "classic ADO" (they usually call stored procedures, sometimes they use dynamic SQL). Most of these DLLs have XML-based methods (not to mention the  proprietary-format-based methods!) to create, edit, delete and retrieve objects, and also extra action such as methods which copy and transform many entities quickly.</p>
  
  <p>The middleware DLLs are now very old, our application developers want a new object-oriented (not xml-oriented) middleware that can be easily used by C# applications.
  Many people in the company say that we should forget old paradigms and move to new cool stuff such Entity Framework. They are intrigued by the simplicity of POCOs and they would like to use LINQ to retrieve data (The Xml-based query methods of the DLLs are not so easy to use and will never be as flexible as LINQ).</p>
  
  <p>So I'm trying to create a mock-up for a simplified scenario (the real scenario is much more complex, and here I'll post just a simplified subset of the simplified scenario!). I'm using Visual Studio 2010, Entity Framework 5 Code First, SQL Server 2008 R2.
  Please have mercy if I make stupid mistakes, I'm a newby to Entity Framework.
  Since I have many different doubts, I'll post them in separate threads. 
  This is the first one. Legacy XML methods have a signature like this:  </p>
  
  <pre><code>    bool Edit(string xmlstring, out string errorMessage)
  </code></pre>
  
  <p>With a format like this: </p>
  
  <pre><code>&lt;ORDER&gt;
      &lt;ID&gt;234&lt;/ID&gt;
      &lt;NAME&gt;SuperFastCar&lt;/NAME&gt;
      &lt;QUANTITY&gt;3&lt;/QUANTITY&gt;
      &lt;LABEL&gt;abc&lt;/LABEL&gt;
  &lt;/ORDER&gt;
  </code></pre>
  
  <p>The Edit method implemented the following business logic: when a Quantity is changed, an "automatic scaling" must be applied to all Orders which have the same Label.
  E.g. there are three orders: OrderA has quantity = 3, label = X. OrderB has quantity = 4, label = X. OrderC has quantity = 5, label = Y.
  I call the Edit method supplying a new quantity = 6 for OrderA, i.e. I'm doubling OrderA's quantity. Then, according to the business logic, OrderB's quantity must be automatically doubled, and must become 8, because OrderB and OrderA have the same label. OrderC must not be changed because it has a different label.</p>
  
  <p>How can I replicate this with POCO classes and Entity Framework? It's a problem because the old Edit method can change only one order at a time, while
  Entity Framework can change a lot of Orders when SaveChanges is called. Furthermore, a single call to SaveChanges can also create new Orders.
  Temporary assumptions, just for this test: 1) if many Order Quantities are changed at the same time, and the scaling factor is not the same for all of them, NO scaling occurs; 2) newly added Orders are not automatically scaled even if they have the same label of a scaled order.</p>
  
  <p>I tried to implement it by overriding SaveChanges.</p>
  
  <p>POCO class: </p>
  
  <pre><code>using System;
  
  namespace MockOrders
  {
      public class Order
      {
          public Int64 Id { get; set; }
          public string Name { get; set; }
          public string Label { get; set; }
          public decimal Quantity { get; set; }
      }
  }
  </code></pre>
  
  <p>Migration file (to create indexes):</p>
  
  <pre><code>namespace MockOrders.Migrations
  {
      using System;
      using System.Data.Entity.Migrations;
  
      public partial class UniqueIndexes : DbMigration
      {
          public override void Up()
          {
              CreateIndex("dbo.Orders", "Name", true /* unique */, "myIndex1_Order_Name_Unique");
              CreateIndex("dbo.Orders", "Label", false /* NOT unique */, "myIndex2_Order_Label");
          }
  
          public override void Down()
          {
              DropIndex("dbo.Orders", "myIndex2_Order_Label");
              DropIndex("dbo.Orders", "myIndex1_Order_Name_Unique");
          }
      }
  }
  </code></pre>
  
  <p>DbContext:</p>
  
  <pre><code>using System;
  using System.Data.Entity;
  using System.Data.Entity.ModelConfiguration;
  using System.Linq;
  
  namespace MockOrders
  {
      public class MyContext : DbContext
      {
          public MyContext() : base(GenerateConnection())
          {
          }
  
          private static string GenerateConnection()
          {
              var sqlBuilder = new System.Data.SqlClient.SqlConnectionStringBuilder();
              sqlBuilder.DataSource = @"localhost\aaaaaa";
              sqlBuilder.InitialCatalog = "aaaaaa";
              sqlBuilder.UserID = "aaaaa";
              sqlBuilder.Password = "aaaaaaaaa!";
              return sqlBuilder.ToString();
          }
  
          protected override void OnModelCreating(DbModelBuilder modelBuilder)
          {
              modelBuilder.Configurations.Add(new OrderConfig());
          }
  
          public override int SaveChanges()
          {
              ChangeTracker.DetectChanges();
  
              var groupByLabel = from changedEntity in ChangeTracker.Entries&lt;Order&gt;() 
                          where changedEntity.State == System.Data.EntityState.Modified
                                  &amp;&amp; changedEntity.Property(o =&gt; o.Quantity).IsModified
                                  &amp;&amp; changedEntity.Property(o =&gt; o.Quantity).OriginalValue != 0
                                  &amp;&amp; !String.IsNullOrEmpty(changedEntity.Property(o =&gt; o.Label).CurrentValue)
                          group changedEntity by changedEntity.Property(o =&gt; o.Label).CurrentValue into x
                          select new { Label = x.Key, List = x};
  
              foreach (var labeledGroup in groupByLabel)
              {
                  var withScalingFactor = from changedEntity in labeledGroup.List 
                      select new 
                      { 
                          ChangedEntity = changedEntity, 
                          ScalingFactor = changedEntity.Property(o =&gt; o.Quantity).CurrentValue / changedEntity.Property(o =&gt; o.Quantity).OriginalValue 
                      };
  
                  var groupByScalingFactor = from t in withScalingFactor 
                                             group t by t.ScalingFactor into g select g;
  
                  // if there are too many scaling factors for this label, skip automatic scaling
                  if (groupByScalingFactor.Count() == 1)
                  {
                      decimal scalingFactor = groupByScalingFactor.First().Key;
                      if (scalingFactor != 1)
                      {
                          var query = from oo in this.AllTheOrders where oo.Label == labeledGroup.Label select oo;
  
                          foreach (Order ord in query)
                          {
                              if (this.Entry(ord).State != System.Data.EntityState.Modified
                                  &amp;&amp; this.Entry(ord).State != System.Data.EntityState.Added)
                              {
                                  ord.Quantity = ord.Quantity * scalingFactor;
                              }
                          }
                      }
                  }
  
              }
  
              return base.SaveChanges();
  
          }
  
          public DbSet&lt;Order&gt; AllTheOrders { get; set; }
      }
  
      class OrderConfig : EntityTypeConfiguration&lt;Order&gt;
      {
          public OrderConfig()
          {
              Property(o =&gt; o.Name).HasMaxLength(200).IsRequired();
              Property(o =&gt; o.Label).HasMaxLength(400);
          }
      }
  }
  </code></pre>
  
  <p>It seems to work (barring bugs of course), but this was an example with just 1 class: a real production application may have hundreds of classes! 
  I'm afraid that in a real scenario, with a lot of constraints and business logic, the override of SaveChanges could quickly become long, cluttered and error-prone.
  Some colleagues are also concerned about performance. In our legacy DLLs, a lot of business logic (such as "automatic" actions) lives in stored procedures, some colleagues are worried that the SaveChanges-based approach may introduce too many round-trips and hinder performance.
  In the override of SaveChanges we could also invoke stored procedures, but what about transactional integrity? What if I make changes to the database 
  before I call "base.SaveChanges()", and "base.SaveChanges()" fails?</p>
  
  <p>Is there a different approach? Am I missing something? </p>
  
  <p>Thank you very much!</p>
  
  <p>Demetrio</p>
  
  <p>p.s. By the way, is there a difference between overriding SaveChanges and registering to "SavingChanges" event? I read this document but it does not explain whether there's a difference:
  <a href="http://msdn.microsoft.com/en-us/library/cc716714(v=vs.100).aspx" rel="nofollow noreferrer">http://msdn.microsoft.com/en-us/library/cc716714(v=vs.100).aspx</a> </p>
  
  <p>This post:
  <a href="https://stackoverflow.com/questions/6797895/entity-framework-savechanges-customize-behavior">Entity Framework SaveChanges - Customize Behavior?</a></p>
  
  <p>says that "when overriding SaveChanges you can put custom logic before and AFTER calling base.SaveChanges". But are there other caveats/advantages/drawbacks?</p>