zoukankan      html  css  js  c++  java
  • 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); } }
    复制代码
  • 相关阅读:
    ajax的原理及实现方式
    在linux中添加环境变量
    ftp简单命令
    linux命令之scp
    java中创建对象的方法
    10个调试技巧
    java读取.properties配置文件的几种方法
    Java对象和XML转换
    Java Float类型 减法运算时精度丢失问题
    Java内存分配全面浅析
  • 原文地址:https://www.cnblogs.com/zhangruisoldier/p/7988619.html
Copyright © 2011-2022 走看看