簡體   English   中英

只使用一個 SaveChanges 調用似乎沒有更新我的數據庫

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM