C# 在较长的数据上下文或上下文之外的事务之间进行权衡?
我正在编写一个WebAPI Rest服务,它对一组不同的实体进行操作。我把它们分解成这样:C# 在较长的数据上下文或上下文之外的事务之间进行权衡?,c#,entity-framework,asp.net-web-api,transactions,C#,Entity Framework,Asp.net Web Api,Transactions,我正在编写一个WebAPI Rest服务,它对一组不同的实体进行操作。我把它们分解成这样: db = new DBEntities(); using (var dbContextTransaction = db.Database.BeginTransaction()) { try { ProcessClient(); ProcessCl
db = new DBEntities();
using (var dbContextTransaction = db.Database.BeginTransaction())
{
try
{
ProcessClient();
ProcessClientPerson();
ProcessGuardian();
ProcessAddress();
ProcessEmail();
ProcessPhones();
ProcessChildren();
dbContextTransaction.Commit();
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
etc.
按照数据上下文应该尽可能短的建议,每个方法都会创建自己的数据上下文,调用SaveChanges(),并在最后处理它:
private ProcessClient()
{
db = new DBEntities();
....
这显然不起作用-以这种方式创建的事务上下文与数据上下文绑定。如果某个实体操作出错,则只回滚该操作(隐式),而不回滚总体事务
我发现了这一点,但我想知道是应该遵循它,还是应该让我的数据上下文在事务期间保持有效,并将事务保持在EF
我不是在寻找意见,而是寻找关于稳定性、性能等方面的数据。没有立即需要保持上下文的短期性。你可以这么做,但你不必这么做 随着时间的推移,实体将在上下文中累积。如果您面临内存不足的风险,则有必要释放上下文 否则,通常的过程是在逻辑工作单元的持续时间内保持上下文活动。这里,UOW是所有这些方法的整体 这也使得事务管理更容易(正如您已经发现的) dbContextTransaction.Rollback()
这是一种反模式。如果发生错误,请不要承诺。对此我有复杂的感觉。我正在处理一个没有外键约束的遗留数据库,在其中一个服务调用中插入、更新和删除20到30个对象 问题是我需要频繁调用SaveChanges()来获取将成为外键的标识列值 另一方面,如果在三层以下出现问题,我必须能够回滚所有内容,因此需要一个大型事务 由于某些我无法确定的原因,在同一数据上下文上重复调用SaveChanges将导致连接状态为打开的错误。因此,我最终为每个方法提供了自己的数据上下文:
var scope = new TransactionScope(TransactionScopeOption.RequiresNew,
new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted);
using (scope)
{
try
{
ProcessClient();
ProcessClientPerson();
ProcessGuardian();
ProcessAddress();
ProcessEmail();
ProcessPhones();
ProcessChildren();
scope.Complete();
}
catch (System.Data.Entity.Validation.
DbEntityValidationException ex)
{
[...] handle validation errors etc [...]
}
}
每个部分基本上都是这样做的,一旦剥离到最基本的部分:
private void ProcessClient() {
{
using (MyDBEntities db = new MyDBEntities())
{
[...] doing client stuff [...]
aClient.LastUpdated = DateTime.Now;
db.AddOrUpdate(db, db.Clients, aClient, aClient.ClientID);
db.SaveChanges();
ClientId = aClient.ClientID; // now I can use this to form FKs
}
}
关于锁定的感觉很复杂,因为在我的开发虚拟机上,事务运行1-2秒,这是一个生产数据库,办公室工作人员和在线客户同时通过web应用程序执行CRUD事务
不相关,但对我的AddOrUpdate方法很有帮助