c# – 在EF 4.1 Code First中将分离的实体添加到1-many关系中
我试图使用EF 4.1 Code First来建模具有单个角色的用户的简单关系.当我尝试将具有新角色的现有用户保存到不同的上下文(使用不同的上下文来模拟客户端 – 服务器往返)时,我得到以下异常:
我期望创建一个新角色并与现有用户相关联. 注意事项:我想避免修改实体的结构(例如,通过引入实体上可见的外键属性),并且在数据库中我希望用户有一个指向Role的外键(不是其他方式).我也不准备转移到自我跟踪实体(除非没有别的办法). 以下是实体: public class User { public int UserId { get; set; } public string Name { get; set; } public Role CurrentRole { get; set; } } public class Role { public int RoleId { get; set; } public string Description { get; set; } } 这是我正在使用的映射: public class UserRolesContext : DbContext { public DbSet<User> Users { get; set; } public DbSet<Role> Roles { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<User>().HasKey(u => u.UserId); modelBuilder.Entity<Role>().HasKey(r => r.RoleId); modelBuilder.Entity<User>().HasRequired(u => u.CurrentRole); } } 我用这个预先填充数据库: public class UserInitializer : DropCreateDatabaseAlways<UserRolesContext> { protected override void Seed(UserRolesContext context) { context.Users.Add(new User() {Name = "Bob",CurrentRole = new Role() {Description = "Builder"}}); context.SaveChanges(); } } 最后,这是失败的测试: [TestMethod] public void CanModifyDetachedUserWithRoleAndReattach() { Database.SetInitializer<UserRolesContext>(new UserInitializer()); var context = new UserRolesContext(); // get the existing user var user = context.Users.AsNoTracking().Include(c => c.CurrentRole).First(u => u.UserId == 1); //modify user,and attach to a new role user.Name = "MODIFIED_USERNAME"; user.CurrentRole = new Role() {Description = "NEW_ROLE"}; var newContext = new UserRolesContext(); newContext.Users.Attach(user); // attachment doesn't mark it as modified,so mark it as modified manually newContext.Entry(user).State = EntityState.Modified; newContext.Entry(user.CurrentRole).State = EntityState.Added; newContext.SaveChanges(); var verificationContext = new UserRolesContext(); var afterSaveUser = verificationContext.Users.Include(c => c.CurrentRole).First(u => u.UserId == 1); Assert.AreEqual("MODIFIED_USERNAME",afterSaveUser.Name,"User should have been modified"); Assert.IsTrue(afterSaveUser.CurrentRole != null,"User used to have a role,and should have retained it"); Assert.AreEqual("NEW_ROLE",afterSaveUser.CurrentRole.Description,"User's role's description should have changed."); } } } 当然这是一个被覆盖的场景,我猜这是我在定义模型映射的方式中缺少的东西? 解决方法
你已经破坏了EF状态模型.您使用强制CurrentRole映射了您的实体,因此EF知道您不能拥有没有角色的现有用户.您还使用了
independent associations(在您的实体上没有暴露的FK属性).这意味着角色和用户之间的关系是另一个具有其状态的被跟踪条目.将角色分配给现有用户时,关系条目的状态设置为已添加,但现有用户不可能(因为它必须已分配角色),除非您将旧关系标记为已删除(或除非您正在使用新的关系)用户).在分离的场景中解决这个问题是
very hard,它导致代码必须在往返过程中传递有关旧角色的信息,并手动使用状态管理器或实体图本身.就像是:
Role newRole = user.CurrentRole; // Store the new role to temp variable user.CurrentRole = new Role { Id = oldRoleId }; // Simulate old role from passed Id newContext.Users.Attach(user); newCotnext.Entry(user).State = EntityState.Modified; newContext.Roles.Add(newRole); user.CurrentRole = newRole; // Reestablish the role so that context correctly set the state of the relation with the old role newContext.SaveChanges(); 最简单的解决方案是从数据库加载旧状态,并将更改从新状态合并到加载(附加)状态.通过暴露FK属性也可以避免这种情况. 顺便说一句.你的模型不是一对一的,而是一对一的角色可以分配给多个用户 – 如果是一对一的话,它会更复杂,因为你必须在创建一个新角色之前删除旧角色. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |