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

2024-01-08

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

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

当然,如果我们用不同的上下文包装事务范围,那么如果第二个 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(); 
    }
}

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为工作单元上的多个 EF 上下文做准备 - TransactionScope 的相关文章

  • 实体框架服务层更新 POCO

    我正在使用Service Layer gt Repository gt Entity Framework Code First w POCO objects方法 我在更新实体方面遇到了困难 我正在使用 AutoMapper 将域对象映射到视
  • 如何在 EF Core 2.1 中定义外键关系

    我的 DAL 使用 EF Core 2 1 这就是我的模型的样子 一名用户只能拥有一种角色 Role entity kind of master public class Role public int RoleId get set pub
  • 将 transaction.commit_manually() 升级到 Django > 1.6

    我继承了为 Django 1 4 编写的应用程序的一些代码 我们需要更新代码库以使用 Django 1 7 并最终更新到 1 8 作为下一个长期支持版本 在一些地方它使用旧风格 transaction commit manually and
  • 限制实体框架中子实体的数量

    底线在前 有没有一种简洁的方法可以限制可以属于实体框架中父级的子实体的数量 我现在使用的是4 3 1 问题 我正在开发一个 ASP NET MVC3 站点 它通过使用实体框架的数据访问层访问数据 我有一个 SearchList 实体 它与搜
  • 如何在没有互联网连接的情况下安装 NuGet 包?

    目前我正在一台不允许访问互联网的虚拟电脑上进行开发 我设法获取 NuGet Tools vsix 将 NuGet 添加到 Visual Studio 2010 但似乎无法找出如何离线部署 NuGet 包 例如 我下载了EntityFrame
  • 无法在 Zend Framework 中回滚事务

    我在 Zend Framework 中使用以下代码进行事务 但回滚功能不起作用 数据通过 insertSome data 插入数据库 怎么了 db gt beginTransaction try model gt insertSome da
  • 在c#中映射两个类

    我有两节课 public class foo1 public int id public string image link public string sale price and public class foo2 public int
  • 为什么 EF Core 使用此存储过程总是返回 -1?

    我正在尝试对本地 2016 DB 使用 EF Core 最新版本 并且我得到 1每次都回来 我不知道我做错了什么 我知道它正在到达数据库 我查了一下 int returnCode dbContext Database ExecuteSqlC
  • 从类型获取 DbSet

    我正在尝试为 MVC 6 应用程序制作通用表查看器 编辑器 我目前使用 Context GetEntityTypes 返回给我一份表格列表 现在我需要获取特定类型的数据 我当前的实现是 On my context public IQuery
  • 从客户端访问 DomainService 中的自定义对象

    我正在使用域服务从 Silverlight 客户端的数据库中获取数据 在DomainService1 cs中 我添加了以下内容 EnableClientAccess public class Product public int produ
  • 是否可以在不连接数据库的情况下检索 MetadataWorkspace?

    我正在编写一个需要遍历实体框架的测试库MetadataWorkspace对于给定的DbContext类型 但是 由于这是一个测试库 我宁愿不连接到数据库 它引入了测试环境中可能无法使用的依赖项 当我尝试获取参考时MetadataWorksp
  • 打开新EntityManager后线程锁

    我在使用 Spring JPA 事务时遇到一个非常奇怪的错误 该线程被锁定大约 16 分钟 然后继续 没有任何问题 情况如下 Transactional propagation Propagation REQUIRES NEW public
  • 实体框架代码优先 - 外键约束问题

    我是 EF 代码优先主体的新手 目前不知道该怎么做 我有 2 个 POCO 类 public class Problem public int ProblemID get set public int UserID get set publ
  • 使用@Transactional(readOnly = true) 有什么优点?

    我是初学者 据我了解 Transactional只需确保类或方法的所有内部工作都用注释 Transactional将被包装在一个事务中 并且来自外部源的所有调用都将创建一个新事务 但是为什么我们实际上需要在下面的存储库中使用这些注释以及使用
  • 如何解决“指定的包含路径无效”?

    我有一个相当基本的亲子关系设置 最终结果是我希望能够通过 ASP NET MVC WebAPI 以 JSON 形式返回结果表 我正在使用实体框架 5 0 beta 2 我可以用一个简单的例子来演示我遇到的错误 鉴于课程Category an
  • 在实体框架 6 中使用 SqlQuery>

    我正在尝试在 EF 6 中执行 SQL 查询 select查询返回两个字符串列 例如select a b 并且可以有任意数量的行 我想将结果映射到字典 但我无法摆脱以下错误 错误 1 无法将类型 System Data Entity Inf
  • PL/SQL 过程:如何返回 select 语句?

    我想创建一个存储过程 on ORACLE数据库服务器我的问题是 我不知道如何返回 select 语句 这是程序中应包含的逻辑 输入参数 过滤器1 int 过滤器2 字符串 with cte as select val1 val2 stdde
  • SimpleMemership CreateUserAndAccount 自定义

    我正在尝试添加一个新属性UserProfile我的模型中的类 public class UserProfile Key DatabaseGeneratedAttribute DatabaseGeneratedOption Identity
  • .edmx 文件的用途是什么?

    edmx 文件的用途是什么 阅读 CSDL SSDL 和 MSL 规范 在我看来 edmx 文件仅在设计时使用 我们打算将它与其他 edmx 一起分发吗 看来我们需要分发 ssdl 和 或 csdl 文件 EDMX 是 Visual Stu
  • 使用 SOA、UoW、Repository、DataContext 和多个数据库设计多租户应用程序

    首先 我对这篇文章的篇幅表示歉意 但我想提供尽可能多的细节 以增加得到答案的机会 提前致谢 我正在向集成来自多个数据库的数据的现有应用程序添加新功能 简而言之 它允许客户和 或其会计师访问和更新有关其位置的财务信息 该应用程序有 3 层 其

随机推荐