从 SaveChanges 中拦截和重定向实体保存
Intercept and Redirect Entity save from within SaveChanges
我目前在数据库中有一个 table 结构如下:
Orders
OrderId int , --Primary Key
CustomerId int,
PartId int,
OrderDate Date,
Quantity int
不幸的是,因为 OrderId 被设置为主键而不是 CustomerId、PartId 和 OrderDate 的复合键,我们在数据库中有许多以下实例:
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
而不是:
OrderId | CustomerId | PartId | OrderDate | Quantity
1 | 23 | 45 | 2016-11-16 | 3
4 | 26 | 30 | 2016-10-25 | 2
由于 regulatory/logging 问题,我无权更新数据库,更新会破坏遗留代码。然而,我已经说服我的老板允许我更新实体以对任何向前发展的数据实施这些限制。
我的想法是覆盖 DbContext
中的 SaveChanges
,这样如果遗留代码试图添加另一行,其中 CustomerId
、PartId
和 OrderDate
已经存在,取消保存并增加现有行的 Quantity
列。到目前为止,我有以下内容,但不确定如何取消保存、更新现有行并强制该行从 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();
}
我认为覆盖 EF 不是一个好主意,因为您可以将它用于 Orders
以外的其他实体。但是,为什么不包装 SaveChanges()
调用并自己完成 add/update 工作呢?
public void 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();
}
}
我目前在数据库中有一个 table 结构如下:
Orders
OrderId int , --Primary Key
CustomerId int,
PartId int,
OrderDate Date,
Quantity int
不幸的是,因为 OrderId 被设置为主键而不是 CustomerId、PartId 和 OrderDate 的复合键,我们在数据库中有许多以下实例:
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
而不是:
OrderId | CustomerId | PartId | OrderDate | Quantity
1 | 23 | 45 | 2016-11-16 | 3
4 | 26 | 30 | 2016-10-25 | 2
由于 regulatory/logging 问题,我无权更新数据库,更新会破坏遗留代码。然而,我已经说服我的老板允许我更新实体以对任何向前发展的数据实施这些限制。
我的想法是覆盖 DbContext
中的 SaveChanges
,这样如果遗留代码试图添加另一行,其中 CustomerId
、PartId
和 OrderDate
已经存在,取消保存并增加现有行的 Quantity
列。到目前为止,我有以下内容,但不确定如何取消保存、更新现有行并强制该行从 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();
}
我认为覆盖 EF 不是一个好主意,因为您可以将它用于 Orders
以外的其他实体。但是,为什么不包装 SaveChanges()
调用并自己完成 add/update 工作呢?
public void 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();
}
}