coffeecop coffeecop - 23 days ago 7
C# Question

Intercept and Redirect Entity save from within SaveChanges

I currently have a table in the database that is structured like the following:

Orders
OrderId int , --Primary Key
CustomerId int,
PartId int,
OrderDate Date,
Quantity int


Unfortunately because OrderId was set as the primary key instead of having a composite key of CustomerId, PartId, and OrderDate we have many instances of the following in the database:

OrderId | CustomerId | PartId | OrderDate | Quantity
1 | 23 | 45 | 2016-11-16 | 1
2 | 23 | 45 | 2016-11-16 | 1
3 | 23 | 45 | 2016-11-16 | 1
4 | 26 | 30 | 2016-10-25 | 1
5 | 26 | 30 | 2016-10-25 | 1


Instead of:

OrderId | CustomerId | PartId | OrderDate | Quantity
1 | 23 | 45 | 2016-11-16 | 3
4 | 26 | 30 | 2016-10-25 | 2


I'm not authorized to update the database due to regulatory/logging issues and an update would break legacy code. I however have convinced my boss to allow me to update Entity to enforce these constraints on any data moving forward.

My idea is to override
SaveChanges
in
DbContext
so that if the legacy code tries to add another row, where the
CustomerId
,
PartId
, and
OrderDate
already exists, that save is cancelled and the
Quantity
column of the existing row is increased. So far I have the following but am unsure how to cancel the save, update the existing row and force that row to save from within
SaveChanges
.

public override int SaveChanges()
{

var PartAssemblyList = ChangeTracker.Entries()
.Where( x => x.Entity is Order &&
x.State == EntityState.Added);

foreach (var entity in PartAssemblyList)
{
if (/*RowExists*/)
{
//Cancel Save (entity.State = EntityState.Unchanged)?
//Update Quantity of Existing Row
//Set existing row to save
}
}

return base.SaveChanges();
}

Answer

I think that overriding EF is a bad idea because you could use it with other entities other than Orders. However why don't you wrap the SaveChanges() call and make the add/update job yourself ?

public AddUpdateOrder(Order o)
{
    using(var ctx = new YourDataModelContext())
    {
        if(ctx.Orders.Any(x => x.OrderId == o.OrderId && x.CustomerId == o.CustomerId && x.PartId == o.PartId && x.OrderDate == o.OrderDate))
        {
            var e = ctx.Orders.Where(x => x.OrderId == o.OrderId && x.CustomerId == o.CustomerId && x.PartId == o.PartId && x.OrderDate == o.OrderDate).FirstOrDefault();
            e.Quantity += 1;
            ctx.Entry(e).State = Modified; 
        }
        else
        {
            Order e = new Order() { OrderId = o.OrderId, CustomerId = o.CustomerId, PartId = o.PartId, OrderDate == o.OrderDate, Quantity = 1};
            ctx.Orders.Add(e);
        }
        ctx.SaveChanges();
    }
}