基本上我将EF与一次调用混合存储过程进行一些批量删除,否则EF太慢了。
以下是此场景的一些伪代码(实际上我有更复杂的代码):
public void RemoveCustomer(int customerUID)
{
// this code is running in one db transaction
{
// retrieve certain orders of particular customer using EF
var orders = repoOrders.GetOrdersOfCustomer(filter, customerUID);
// do something with above orders before deletion using EF
repoX.DoSomethingWithOrders(orders);
// call SP to delete all orders of customer
repoOrders.DeleteAllOrdersOfCustomer(customerUID); // this calls a stored procedure
// delete customer using EF
repoCustomers.DeleteCustomer(customerUID); // throws exception due to relationship!
}
}
当然,客户订单是one-to-many
(1:m)关系。
我想在上面的场景中避免在属于被删除的客户的上下文加载某些订单时引发的异常。例外是:
"因为一个或多个关系无法改变 外键属性是不可为空的。当对a进行更改时 关系,相关的外键属性设置为空值。 如果外键不支持空值,则为新关系 必须定义外键属性必须另外分配 必须删除非空值或不相关的对象。"
所以,我想知道是否有可能从<DbSet>.Local
清除部分/全部订单,而不会在调用存储过程之后和用户被删除之前对数据库进行任何更改。
我猜Detach可以使用,但这意味着我应该循环使用。
你会推荐什么?
编辑:我是EF新手,我现在正在使用ADO.NET完成存储库之后整合EF,是的,BL保持不变...所以我试试这个在这一点上尽量简化整合。
注意:我无法对数据库结构进行更改。
答案 0 :(得分:6)
我个人使每个存储库方法都使用自己的上下文,在方法结束时保存自己的更改等,然后使用TransactionScope
来确保操作是原子的。 / p>
void DeleteAllOrdersOfCustomer(Guid customerUID)
{
using (var context = new Context())
{
...
context.SaveChanges();
}
}
...
using (var ts = new TransactionScope())
{
// call SP to delete all orders of customer
repoOrders.DeleteAllOrdersOfCustomer(customerUID); // this calls a stored procedure
// delete customer using EF
repoCustomers.DeleteCustomer(customerUID); // throws exception due to relationship!
ts.Complete();
}
答案 1 :(得分:1)
我一直在使用SqlQuery
dbset
来实现此目的:
context.xdbset.SqlQuery("storedprocedure; select * from xdbset");
查询调用存储过程,然后调用此处必需的select *...
,因为查询结果必须包含上下文构建“xdbset”对象所需的数据格式。
您可以查看here进行类似的辩论。
答案 2 :(得分:0)
这可能有点棘手,我不知道使用它有多贵。您需要使用RefreshMode
Enum,我认为您需要StoreWins
。
顺便说一下,你可以加速你的EF删除,而不是批量,但那是一个不同的问题。