为工作单元上的多个 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 的相关文章

  • 实体框架与oracle数据库的连接

    我使用的是 Entity Framework 6 1 版本和 oracle 11 我是实体框架的新手 任何人都可以建议连接 oracle 的先决条件是什么 任何更改都需要在 web config 中进行 在web config中 默认它是与
  • 我想最小化@Transactional 的范围吗?

    不确定 范围 在这里是否是正确的术语 我使用 Spring 进行 JPA 事务管理 下面有 Hibernate 我执行数据库事务的方法是私有的 但是由于您只能在类或类上设置 Transactional公共方法 http static spr
  • EF6“模型配置”已设置但未发现

    我有以下库 实体模型 dll 包含 POCO 类 实体DAL dll 引用EntityMODEL dll 实体服务 dll 引用 EntityMODEL dll 和 EntityDAL dll 实体测试 dll 引用 EntitySERVI
  • “等待操作超时”...但仅来自 .NET 客户端?

    我有一个查询 当从我的应用程序执行时会抛出 SqlException 0x80131904 超时已过期 操作完成之前超时时间已过 或者服务器没有响应 在 Visual Studio 中单步执行代码时 我遇到了同样的错误 但是 当使用相同的凭
  • EF Core 迁移可以手动编辑吗?

    我在示例项目中使用 EF Core 2 0 和一些值对象配置 我修改代码并通过 CLI 命令行生成迁移 在最后一次迁移中 它没有像应有的那样添加新的数据库表 而是尝试将现有表彼此重命名并为现有表创建一个额外的表 我不明白其中的原因 问题是
  • 使用 linq-to-entities 将字符串转换为日期时间的大问题

    如何使用 linq toEntity 将字符串转换为日期时间 我收到以下查询 其中visit date列数据类型是字符串 var memberl from v in abc visits join m in abc members on v
  • 当 edmx 文件位于单独的项目中时出错

    我有问题说 在配置中找不到指定的命名连接 或者不打算与EntityClient提供者 或无效 我的 edmx 文件位于单独的项目中 但该项目的连接字符串app config 什么可能导致问题 确保 app config 位于设置为启动项目的
  • 对于相同的数据库对象,实体框架对象引用是否相同

    如果我从不同位置查询 逻辑上 在数据库中 相同的对象 实体框架是否返回相同的对象引用 例如 我查询了名为 Joe Black 的客户 并假设现在我知道数据库中只有一个 Joe Black Customer c select blabla w
  • 使用 DI 将参数传递给 DbContext

    我想向 DBContext 传递一个附加参数 如下所示 string myParam xx string con connenctionstring services AddDbContext
  • 即使没有显式事务,SQL Server 也会获取锁吗?

    我第一次阅读有关 MSSQL 锁定的内容 在很多地方 锁定机制概念依赖于事务的存在 我想知道在不涉及任何事务的情况下是否可以锁定 一般来说 当不存在显式事务时 每个 SQL 语句都在自动 自动提交 事务中执行 在这种情况下将应用正常的锁定行
  • 如何获取 EF 中的实体更改增量?

    我只需要获取已更改字段的列表 数据存储区是 ssce 因此没有可用的触发器 EF 是否支持获取列表或构建通用组件 根据上下文的类型和生成的实体 您可以通过多种不同的方式来完成此操作 如果对象继承自 Entity 或 POCO 您可以使用Ob
  • 使用更新的值重新加载实体框架上下文中的对象

    我有一个从数据库中提取的 EF 对象 然后 我通过使用另一个函数调用来更新数据库中的相应行DBContext 在此更新之后 我想使用更新后的内容重新加载对象的内容 但是 EF 上下文似乎缓存了这些内容 这是代码示例 我删除了一些不相关的内容
  • VS 2012 中缺少实体数据模型

    添加新项目时 我在 数据 选项卡下找不到实体数据模型 我查看了几个问题和答案以及有关此问题的信息 但没有一个解决方案有效 我已修复 卸载并重新安装 手动安装 EF Tools 包并尝试卸载所有 VS 相关程序 我还尝试在不同的 NET 框架
  • 抑制实体框架核心中的 SQL 查询日志记录

    我有一个使用实体框架核心的控制台 net core 应用程序 该应用程序使用日志框架写入文件和控制台 serviceProvider new ServiceCollection AddLogging AddDbContext
  • 应用程序内的 SQLite 文件版本兼容性

    我有一个 C NET 应用程序 一种复杂的计算应用程序 其中用户输入数据 处理后的信息使用 JSON 序列化和 EF 保存到 SQLite 文件中 需要时可以将其加载到我们的应用程序中 应用程序在开发过程中经历了很多变化 类也被修改 因此
  • 将大量实体插入 SQL Server 2012 [重复]

    这个问题在这里已经有答案了 我正在进行一个使用 Entity Framework 5 和 SQL Server 2012 的项目 我们需要一次插入大量行 100k 个实体的顺序 基本上 我们有一个物理程序 它输出大量二进制数据 然后我们需要
  • 包括过滤器子集合[重复]

    这个问题在这里已经有答案了 我在为 LINQ 查询中包含的项目添加一些过滤条件时遇到一些困难 我的查询就像 var item Context Order Include Inner Include Inner first Include I
  • 不支持 EF6 上下文类型“System.Data.Entity.Core.Objects.ObjectContext”

    我有一个使用 Visual Studio 2013 和 ADO NET 实体数据模型 EF6 创建的新项目 现在我必须使用一些动态数据函数 例如访问 MetaTable 对象 所以我添加以下代码 MetaModel model new Me
  • 如何获取 EF 中与组合(键/值)列表匹配的记录?

    我有一个数据库表 其中包含每个用户 年份组合的记录 如何使用 EF 和用户 ID 年份组合列表从数据库获取数据 组合示例 UserId Year 1 2015 1 2016 1 2018 12 2016 12 2019 3 2015 91
  • 从备用位置获取实体框架连接字符串?

    如何从自定义配置文件而不是 web config 检索 Entity Framework 4 连接字符串 编辑 删除默认构造函数生成的代码并在分部类中重新创建它以使用拉入的连接字符串是否合理 我真的很想避免使用包括连接字符串在内的重载方法更

随机推荐