NopCommerce添加事务机制

NopCommerce现在最新版是3.9,不过依然没有事务机制。作为一个商城,我觉得事务也还是很有必要的。以下事务代码以3.9版本作为参考:

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

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

自然相应的IDbContext接口实现类NopObjectContext也要实现该方法:

        public IEnumerable<DbEntityEntry> 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 = ,
CreatedOnUtc = DateTime.Now,
UpdatedOnUtc = DateTime.Now.AddDays()
};
ForumGroupRepository.Insert(forumGroup); // 第一次插入数据 var setting = new Setting
{
Name = "test_transaction_name",
Value = "test_transaction_value",
StoreId =
};
SettingRepository.Insert(setting); _unitOfWork.Commit(); // 提交
}
catch (Exception)
{
_unitOfWork.Rollback(); // 回滚
} Assert.AreEqual(ForumGroupRepository.TableNoTracking.Count(), );
Assert.AreEqual(SettingRepository.TableNoTracking.Count(x => x.Name == "test_transaction_name"), 1);
}
}

如果你觉得对你有帮助,右侧打个赏呗!

Authori:黄仲秋

QQ:875755898

上一篇:net core mvc剖析:启动流程


下一篇:Django_collections01