我在ASP.NET MVC Core 2应用程序中有一个数据库初始化方法。 在该方法中,我使用ApplicationDbContext和UserManager来初始化数据库。 我从构造函数的依赖注入中获取了两个实例:
public static void Initialize(ApplicationDbContext context,
UserManager<ApplicationUser> user)
我想知道的是,它们是否共享相同的上下文实例,或者是否为ApplicationDbContext创建了一个上下文,而为UserManager创建了另一个上下文。 如果我执行这样的事情:
ApplicationUser adminTeacherUser = new ApplicationUser
{
UserName = "test@test.com",
Email = "test@test.com",
EmailConfirmed = true,
Name = "test",
LastName = "test",
BirthDate = null,
EntryDate = DateTime.Now
};
userManager.CreateAsync(adminTeacherUser, "password").Wait();
在CreateAsync调用之后,用户在数据库中创建。
但是,如果那时我像这样更新用户:
adminTeacherUser.Name = "other";
userManager.UpdateAsync(adminTeacherUser);
调用UpdateAsync后,数据库中没有更新任何内容。用户名仍然是“test”。
但是,如果那时我执行:
context.SaveChanges();
应用更改并更新数据库。
那么,为什么CreateAsync方法“保存其更改”而不显式调用“context.SaveChanges”并且UpdateAsync方法需要它? ApplicationDbContext实例是通过依赖注入获得的,与CreateAsync使用的相同吗?
谢谢。
答案 0 :(得分:6)
ASP.NET Core应用程序中的Entity Framework Core的默认注册是按请求范围,因此它们将明确地共享上下文。
从EF Core for ASP.NET核心身份的默认实现的源代码中可以看到(here
/// <summary>
/// Creates the specified <paramref name="user"/> in the user store.
/// </summary>
/// <param name="user">The user to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the creation operation.</returns>
public async override Task<IdentityResult> CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Context.Add(user);
await SaveChanges(cancellationToken);
return IdentityResult.Success;
}
和here
/// <summary>
/// Updates the specified <paramref name="user"/> in the user store.
/// </summary>
/// <param name="user">The user to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the update operation.</returns>
public async override Task<IdentityResult> UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Context.Attach(user);
user.ConcurrencyStamp = Guid.NewGuid().ToString();
Context.Update(user);
try
{
await SaveChanges(cancellationToken);
}
catch (DbUpdateConcurrencyException)
{
return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
}
return IdentityResult.Success;
}
,他们都保存了更改。
您遇到的问题是,您await
的结果不是UpdateAsync
,因此您需要更改为:
await userManager.UpdateAsync(adminTeacherUser);
//or
userManager.UpdateAsync(adminTeacherUser).Wait();
当然,使用 async-all-the-way 是首选版本,您不应该使用.Wait()
阻止。