• NopCommerce添加事务机制


    NopCommerce,一直没有事务机制。作为一个商城,我觉得事务也还是很有必要的。以下事务代码以3.9版本作为参考:

    首先,IDbContext接口继承IDisposable接口,以便手动释放相关资源,并添加一个新方法CurrentEntries,目的是得到跟踪实体的当前跟踪状态(主要作用是使用事务回滚后改变当前实体对应的状态):

            /// <summary>
            /// 得到跟踪实体的当前跟踪状态
            /// </summary>
            /// <returns></returns>
            IEnumerable<DbEntityEntry> CurrentEntries();

    自然相应的IDbContext接口实现类NopObjectContext也要实现该方 CurrentEntries() { return ChangeTracker.Entries(); }

    注意:主项目代码添加这个方法之后,所有需要操作数据库的插件都要实现该方法,这个大家自行斟酌,如果插件也需要事务的话。

    添加一个接口命名IUnitOfWork,如下:

    复制代码
        public interface IUnitOfWork : IDisposable
        {
            /// <summary>
            /// 开启事务
            /// </summary>
            /// <param name="isolationLevel"></param>
            void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified);
    
            /// <summary>
            /// 提交
            /// </summary>
            void Commit();
    
            /// <summary>
            /// 回滚
            /// </summary>
            void Rollback();
    
            /// <summary>
            /// 释放资源
            /// </summary>
            /// <param name="disposing">是否释放</param>
            void Dispose(bool disposing);
        }
    复制代码

    并实现该接口,添加实现类命名UnitOfWork,如下:

    复制代码
        public class UnitOfWork : IUnitOfWork
        {
            private IDbContext _context;
            private ObjectContext _objectContext;
            private IDbTransaction _transaction;
    
            private bool _disposed;
    
            public UnitOfWork(IDbContext context)
            {
                _context = context;
            }
    
            public void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified)
            {
                _objectContext = ((IObjectContextAdapter)_context).ObjectContext;
                if (_objectContext.Connection.State != ConnectionState.Open)
                    _objectContext.Connection.Open();
    
                _transaction = _objectContext.Connection.BeginTransaction(isolationLevel);
            }
    
            public void Commit()
            {
                _transaction.Commit();
            }
    
            public void Rollback()
            {
                _transaction.Rollback();
                foreach (var entry in _context.CurrentEntries())
                {
                    switch (entry.State)
                    {
                        case EntityState.Modified:
                            entry.State = EntityState.Unchanged;
                            break;
                        case EntityState.Added:
                            entry.State = EntityState.Detached;
                            break;
                        case EntityState.Deleted:
                            entry.State = EntityState.Unchanged;
                            break;
                    }
                }
            }
    
            public void Dispose(bool disposing)
            {
                if (_disposed)
                    return;
    
                if (disposing)
                {
                    try
                    {
                        if (_objectContext != null && _objectContext.Connection.State == ConnectionState.Open)
                            _objectContext.Connection.Close();
                    }
                    catch (ObjectDisposedException)
                    {
                    }
                    if (_context != null)
                    {
                        _context.Dispose();
                        _context = null;
                    }
                }
    
                _disposed = true;
            }
    
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }
    复制代码

    代码很好理解,我就不多做注释了,不清楚的自行网上了解。

    下面附上我写的单元测试:

    复制代码
        [TestClass]
        public class UnitTest1
        {
            protected static NopObjectContext Context = new NopObjectContext(ConfigurationManager.ConnectionStrings["ConnectionStr"].ToString());
            private readonly IUnitOfWork _unitOfWork = new UnitOfWork(Context);
            protected readonly IRepository<ForumGroup> ForumGroupRepository = new EfRepository<ForumGroup>(Context);
            protected readonly IRepository<Setting> SettingRepository = new EfRepository<Setting>(Context);
    
            [TestMethod]
            public void Can_Commit_Test()
            {
                try
                {
                    _unitOfWork.BeginTransaction(); // 开启事务
    
                    var forumGroup = new ForumGroup
                    {
                        Name = "ForumGroup1", // 自行建立Name的唯一约束测试,测试两次第二次会自行回滚
                        DisplayOrder = 1,
                        CreatedOnUtc = DateTime.Now,
                        UpdatedOnUtc = DateTime.Now.AddDays(1)
                    };
                    ForumGroupRepository.Insert(forumGroup); // 第一次插入数据
    
                    var setting = new Setting
                    {
                        Name = "test_transaction_name",
                        Value = "test_transaction_value",
                        StoreId = 1
                    };
                    SettingRepository.Insert(setting);
    
                    _unitOfWork.Commit(); // 提交
                }
                catch (Exception)
                {
                    _unitOfWork.Rollback(); // 回滚
                }
    
                Assert.AreEqual(ForumGroupRepository.TableNoTracking.Count(), 1);
    Assert.AreEqual(SettingRepository.TableNoTracking.Count(x => x.Name == "test_transaction_name"), 1); } }
    复制代码
  • 相关阅读:
    背水一战 Windows 10 (90)
    背水一战 Windows 10 (89)
    背水一战 Windows 10 (88)
    背水一战 Windows 10 (87)
    背水一战 Windows 10 (86)
    背水一战 Windows 10 (85)
    背水一战 Windows 10 (84)
    背水一战 Windows 10 (83)
    背水一战 Windows 10 (82)
    背水一战 Windows 10 (81)
  • 原文地址:https://www.cnblogs.com/zhangruisoldier/p/7988619.html
Copyright © 2020-2023  润新知