gpt4 book ai didi

entity-framework - 为一个工作单元上的多个 EF 上下文做准备 - TransactionScope

转载 作者:行者123 更新时间:2023-12-04 03:12:48 26 4
gpt4 key购买 nike

我正在考虑有关实现处理多个数据源的单个工作单元的选项 - Entity Framework 。我想出了一个试探性的方法——现在处理一个单一的上下文——但这显然不是一个好主意。

如果我们分析下面的代码,你会认为它是一个糟糕的实现吗?事务范围的生命周期是一个潜在的问题吗?

当然,如果我们用不同的上下文包装事务范围,如果第二个 context.SaveChanges() 失败,我们就会被覆盖......

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;

namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
using(UnitOfWork unitOfWork = new UnitOfWork())
{

var repository = new EmployeeRepository(unitOfWork);

var employee = repository.CreateOrGetEmployee("Whatever Name");

Console.Write(employee.Id);

unitOfWork.SaveChanges();
}
}
}

class UnitOfWork : IDisposable
{
TestEntities _context;
TransactionScope _scope;
public UnitOfWork()
{
_scope = new TransactionScope();
_context = new TestEntities();
}

public void SaveChanges()
{
_context.SaveChanges();
_scope.Complete();
}

public TestEntities Context
{
get
{
return _context;
}
}

public void Dispose()
{
_scope.Dispose();
_context.Dispose();
}
}

class EmployeeRepository
{
UnitOfWork _unitOfWork;

public EmployeeRepository(UnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}

public Employee GetEmployeeById(int employeeId)
{
return _unitOfWork.Context.Employees.SingleOrDefault(e => e.Id == employeeId);
}

public Employee CreateEmployee(string fullName)
{
Employee employee = new Employee();
employee.FullName = fullName;
_unitOfWork.Context.SaveChanges();
return employee;
}

public Employee CreateOrGetEmployee(string fullName)
{
var employee = _unitOfWork.Context.Employees.FirstOrDefault(e => e.FullName == fullName);
if (employee == null)
{
employee = new Employee();
employee.FullName = fullName;
this.AddEmployee(employee);
}
return employee;
}

public Employee AddEmployee(Employee employee)
{
_unitOfWork.Context.Employees.AddObject(employee);
_unitOfWork.Context.SaveChanges();
return employee;
}
}
}

最佳答案

为什么开始TransactionScope在构造函数中?您只需要它来保存更改。

public void SaveChanges()
{
// SaveChanges also uses transaction which uses by default ReadCommitted isolation
// level but TransactionScope uses by default more restrictive Serializable isolation
// level
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
_context.SaveChanges();
scope.Complete();
}
}

如果您想拥有更多上下文的工作单元,您只需将所有这些上下文包装在同一个工作单元类中。您的 SaveChanges会变得有点复杂:
public void SaveChanges()
{
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
_contextA.SaveChanges(SaveOptions.DetectChangesBeforeSave);
_contextB.SaveChanges(SaveOptions.DetectChangesBeforeSave);
scope.Complete();
_contextA.AcceptAllChanges();
_contextB.AcceptAllChanges();
}
}

此版本将保存操作与重置上下文的内部状态分开。原因是如果第一个上下文成功保存更改但第二个触发异常,则事务将回滚。因此,我们不希望第一个上下文已将所有更改清除为已接受(我们将丢失有关已执行更改的信息,我们将无法再次保存它们)。

关于entity-framework - 为一个工作单元上的多个 EF 上下文做准备 - TransactionScope,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10729171/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com