[英]Using only one SaveChanges call doesn't seem to update my database
我正在用我的方法做幾件事; 就我而言,它們是必要的,但優化代碼並不是這個問題的目的。
在這種方法中,我創建了一個用戶,將用戶添加到一個角色,創建一個 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.SaveChangesAsync(); 或者不等待只是 db.SaveChanges().. 希望這可以工作。記住你必須以正確的方式映射你的對象。
我看到當您創建 Directorate 和 DirectorateUser 時,您正在使用“用戶”變量,該變量可能不是指數據庫中的變量。
使用以下變量而不是“user”來創建 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
一個實例將IUserStore
粘合在一起。 但正如您所注意到的,每次操作都會立即保存更改。
默認實現UserStore
已經有一個布爾屬性AutoSaveChanges
來防止在每個操作上AutoSaveChanges
,但是似乎沒有一種明顯的方法來訪問這個屬性。
你可以用你自己的實現替換IUserStore
服務(根據UserManager's AutoSaveChanges in .NET Core 2.1 );
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 泛型類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.