在我的一个应用程序中,我正在重写Asp Core Identity UserManager的CreateAsync,除了在UserStore中创建新用户外 - 在单独的统计表(在不同的dbcontext上)中创建一个新行。问题是,我希望在事务中触发这两个操作,这样如果一个失败 - 另一个不提交。这是代码:
public override async Task<IdentityResult> CreateAsync(TUser user, string password)
{
// We need to use transactions here.
var result = await base.CreateAsync(user, password);
if (result.Succeeded)
{
var appUser = user as IdentityUser;
if (appUser != null)
{
// create user stats.
var userStats = new UserStats()
{
ActionsCount = 0,
EventsCount = 0,
FollowersCount = 0,
ProjectsCount = 0,
UserId = appUser.Id
};
_ctx.UserStats.Add(userStats);
await _ctx.SaveChangesAsync();
}
}
return result;
}
事情是,我不知道如何设置这样的事务,因为似乎TransactionScope不是.Net Core的一部分(?)并且使用HttpContext.GetOwinContext获取base.CreateAsync()的当前作用域DbContext( )不起作用,因为HttpContext似乎缺少此方法(引用Microsoft.Owin.Host.SystemWeb或Microsoft.AspNet.WebApi.Owin,如其他一些堆栈溢出答案中暗示的那样 - 两者都与.netcore不兼容) 。有什么帮助吗?
答案 0 :(得分:4)
首先,您需要使用带有作用域生存期的标识设置您正在使用的dbcontext:
services.AddDbContext<MyDbContext>(ServiceLifetime.Scoped); // this is the important bit
services.AddIdentity<User, Role>(options =>
{
})
.AddEntityFrameworkStores<MyDbContext, int>()
.AddDefaultTokenProviders();
然后,当您需要创建交易时,请执行以下操作:
using (var transaction = await _myDbContext.Database.BeginTransactionAsync())
{
var result = await _userManager.CreateAsync(newUser, password);
try
{
if (result.Succeeded)
{
DBItem newItem = new DBItem();
_myDbContext.Add(newItem);
await _myDbContext.SaveChangesAsync();
transaction.Commit();
}
}
catch (Exception e)
{
transaction.Rollback();
}
}
答案 1 :(得分:0)
我认为以下是正确的方向:
using (var transaction = _context.Database.BeginTransaction())
{
}