仅使用一个 SaveChanges 调用似乎不会更新我的数据库



我在我的方法中做了几件事;就我而言,它们是必要的,但优化代码并不是这个问题的目的。

在这种方法中,我创建一个用户,将用户添加到一个角色,创建一个Directorate,并在DirectorateUsers表中创建一条记录,将用户链接到新的Directorate。

这里有一些数据库操作,所以我想尝试通过只调用SaveChanges一次来减少数据库的负载。

不过,它似乎什么也没做;我没有看到新的董事会被添加,董事会用户也没有被添加。但是,它会创建用户并将其添加到指定的角色中。

是否可以通过这种方式批处理对实体框架中数据的多个更改,或者每次添加或更新记录时都必须使用await db.SaveChangesAsync()

[HttpPost]
public async Task<ActionResult> Create([Bind(Include = "MunicipalityId,DirectorateName,UserEmailAddress, UserPassword")] RegisterDirectorateViewModel model)
{
try
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.UserEmailAddress, Email = model.UserEmailAddress };
var createUserResult = await UserManager.CreateAsync(user, model.UserPassword);

if (createUserResult.Succeeded)
{
// Add the user to the directorate role.
await UserManager.AddToRoleAsync(user.Id, nameof(SystemRoles.Directorate));
// Generate the directorate and add the user to it.
var municipality = await db.Municipalities.FindAsync(model.MunicipalityId);
var directorate = new Directorate
{
Action = MetaAction.Create,
ActionBy = user,
ActionDate = DateTime.Now,
Municipality = municipality,
Name = model.DirectorateName
};
db.Directorates.Add(directorate);
var directorateUser = new DirectorateUser
{
Directorate = directorate,
User = user
};
db.DirectorateUsers.Add(directorateUser);
// Expire the token so that it can't be used again.
municipality.TokenExpiryDate = DateTime.Now;
db.Entry(municipality).State = EntityState.Modified;
await db.SaveChangesAsync();
// Sign in the user and redirect to the dashboard.
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
return RedirectToAction("Index", "Dashboard");
}
}
return View(model);
}
catch (Exception ex)
{
TempData["err"] = ex;
return RedirectToAction("Create");
}
}

编辑

以下是每条评论的额外型号。。。

public class Directorate
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Municipality Municipality { get; set; }
public ApplicationUser ActionBy { get; set; }
public DateTime ActionDate { get; set; }
public MetaAction Action { get; set; }
}
public class DirectorateUser
{
public int Id { get; set; }
public virtual Directorate Directorate { get; set; }
public virtual ApplicationUser User { get; set; }
}
public class SubdirectorateUser
{
public int Id { get; set; }
public virtual Subdirectorate Subdirectorate { get; set; }
public virtual ApplicationUser User { get; set; }
}

您需要多对多关系。虽然您有一个User表和Directorates表,但DirectorateUsers表包含User/ApplicationUser和Directorates之间的多对多关系。因此,您必须自定义多对多关系的模型。

public class ApplicationUser
{
public ApplicationUser() 
{
this.Directorates = new HashSet<Directorate>();
}
....
public virtual ICollection<Directorate> Directorates { get; set; }
}

董事会模型具有

public class Directorate
{
public Directorate()
{
this.Users = new HashSet<ApplicationUser>();
}
public virtual ICollection<ApplicationUser> Users{ get; set; }
}

现在DbContext类看起来像。。。

public class AppDBContext : DBContext
{
public AppDBContext() : base("DefaultConnectionString")
{
}
public DbSet<ApplicationUser> Users{ get; set; }
//or public DbSet<User> Users{ get; set; } //if ApplicationUser doesn't work
public DbSet<Directorate> Directorates{ get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Configure a Many-to-Many Relationship using Fluent API
modelBuilder.Entity<User>() //or ApplicationUser
.HasMany<Directorate>(s => s.Directorates)
.WithMany(c => c.Users)
.Map(cs =>
{
cs.MapLeftKey("UserId");
cs.MapRightKey("DirectorateId");
cs.ToTable("DirectorateUser");
});
}
}

这种映射建立了良好的关系。请查看下面的多对多关系链接。https://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx

现在检查您的代码数据库。保存更改同步((;或者不等待简单的db。保存更改((。。希望这能奏效。请记住,您必须以正确的方式映射对象。

我看到,当您创建Directorate和DirectorateUser时,您使用的是;用户";变量,该变量可能没有引用数据库中的变量。

使用下面的变量代替";用户";创建Directorate,DirectorateUser可以解决该问题。

var userDb = await _userManager.FindByNameAsync(user.UserName)

对我来说,这个问题指向了这一点。

db.Entry(municipality).State = EntityState.Modified;
await db.SaveChangesAsync();

这只会启动与市政相关的保存更改。

但是,我认为你应该有这样的东西。

//set all objects that need to be updated in a modified state
db.Entry(municipality).State = EntityState.Modified;
db.Entry(directorate).State = EntityState.Modified;
db.Entry(directorateUser).State = EntityState.Modified;
//finally save all the changes to the database.
await db.SaveChangesAsync();

我就是这样做的。

我看到您正在使用UserManager访问IdentityDbContext。Identity框架使用IUserStore的一个实例将两者粘合在一起。但正如您所注意到的,每次操作都会立即保存更改。

默认实现UserStore已经有一个布尔属性AutoSaveChanges来防止在每个操作上保存,但是似乎没有明显的方法来访问这个属性。

您可以用自己的实现替换IUserStore服务(根据.NET Core 2.1中的UserManager';s AutoSaveChanges(;

public class CustomUserStore : UserStore<IdentityUser>
{
public CustomUserStore(ApplicationDbContext context)
: base(context)
{
AutoSaveChanges = false;
}
}
services.AddScoped<IUserStore<IdentityUser>, CustomUserStore>();

不过,您需要确保所有UserManager/SigninManager调用后面都有另一个显式保存。

或者,您可以添加IUserStore作为依赖项,假设它是UserStore的实例,并围绕您的方法更改AutoSaveChanges值;

private UserStore<IdentityUser, IdentityRole, DbContext> store;
public Controller(IUserStore<IdentityUser> store)
{
this.store = store as UserStore<IdentityUser, IdentityRole, DbContext>;
}
public async Task<ActionResult> Create(...){
try{
store.AutoSaveChanges = false;
...
}finally{
store.AutoSaveChanges = true;
}
}

请注意,您需要哪种UserStore泛型类型取决于您使用的IdentityContext泛型类型。

最新更新