简体   繁体   中英

Entity Framework not writing many to many relationship changes to the database

I have an entity, ApplicationUser , which has an ICollection of another entity, Brand . In my unit test, I am adding a Brand to the ICollection and I call SaveChanges() but nothing gets written to my junction table.

Here is some code:

ApplicationUser:

public class ApplicationUser : IdentityUser
    {
        [Required]
        [StringLength(50, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 2)]
        [DataType(DataType.Text)]
        public string FirstName { get; set; }
        [Required]
        [StringLength(50, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 2)]
        [DataType(DataType.Text)]
        public string LastName { get; set; }

        public virtual ICollection<Brand> Brands { get; set; }

        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    }

Here is Brand

public class Brand
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Product> Products { get; set; }
        public virtual ICollection<ApplicationUser> Users { get; set; }

        public Brand()
        {
            Products = new List<Product>();
            Users = new List<ApplicationUser>();
        }
    }

Here is my mapping for the junction table

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<ApplicationUser>()
                .HasMany(b => b.Brands)
                .WithMany(n => n.Users)
                .Map(m =>
                {
                    m.MapLeftKey("AspNetUsers.Id");
                    m.MapRightKey("Brand.Id");
                    m.ToTable("UserToBrand");
                });
        }

And here is where I am trying to write changes to db

public void UpdateUserInformation(ApplicationUser user)
        {
            using(ApplicationDbContext db = new ApplicationDbContext())
            {
                db.Database.Log = Console.WriteLine;
                db.Users.Attach(user);
                db.Entry(user).State = System.Data.Entity.EntityState.Modified;
                foreach(Brand b in user.Brands)
                {
                    db.Brands.Attach(b);
                    db.Entry(b).State = System.Data.Entity.EntityState.Modified;
                }
                db.SaveChanges();
            }
        }

With output the Database log, I can see the update SQL for the AspNetUser table and the Brand table but nothing for the UserToBrand table.

When working with disconnected object, you need to manage the synchronization manually, including the relationship state.

You either need to get the object first from the context to make everything in sync.

var userDb = db.Users.Find(user.Id);
// Updates scalar properties.
db.Entry(userDb).CurrentValues.SetValues(user);
foreach(Brand b in user.Brands)
{
    // Is still required to prevent EF adds new brand.
    db.Entry(b).State = EntityState.Modified;
    userDb.Brands.Add(b);
}
db.SaveChanges();

Or if you really want to use the disconnected object, you need to manually create the relationship.

db.Entry(user).State = EntityState.Modified;
foreach(Brand b in user.Brands)
{
    db.Entry(b).State = System.Data.Entity.EntityState.Modified;
    (IObjectContextAdapter)db).ObjectContext.ObjectStateManager
       .ChangeRelationshipState(user, b, u => u.Brands, EntityState.Added);
}
db.SaveChanges();

Btw, Attach method is redundant because it's same as changing the state to EntityState.Unchanged and then you change it again to EntityState.Modified after attaching.

More

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM