entity framework更新多对多关系:虚拟与否

我一年以来一直在使用EF4(不是代码优先),所以我真的不是它的专家。 我对使用保存n更新的多对多关系表示怀疑。

我在stackoverflow上找到了某个地方(我再也找不到url),一个解决方案 – 更新现有的多对多关系 – 就是不要声明“虚拟”属性; 但是,如果我这样做,引擎无法轻松加载数据。

你能解释一下原因吗? Otherwire,你能帮我找一些关于这个主题的很酷的文档吗?

谢谢

您可以通过这种方式更新多对多关系(作为向用户3提供角色5的示例):

using (var context = new MyObjectContext()) { var user = context.Users.Single(u => u.UserId == 3); var role = context.Roles.Single(r => r.RoleId == 5); user.Roles.Add(role); context.SaveChanges(); } 

如果将User.Roles集合声明为virtualuser.Roles.Add(role); 确实会触发延迟加载,这意味着在添加新角色之前,首先从数据库加载用户的所有角色。

这实际上令人不安,因为您不需要加载整个Roles集合来向用户添加新角色。

但这并不意味着您必须删除virtual关键字并完全放弃延迟加载。 您可以在这种特定情况下关闭延迟加载:

 using (var context = new MyObjectContext()) { context.ContextOptions.LazyLoadingEnabled = false; var user = context.Users.Single(u => u.UserId == 3); var role = context.Roles.Single(r => r.RoleId == 5); user.Roles = new List(); // necessary, if you are using POCOs user.Roles.Add(role); context.SaveChanges(); } 

编辑

如果要更新用户的整个角色集合,我更愿意使用预先加载(= Include )加载原始角色。 无论如何你都需要这个列表来删除一些角色,所以你不需要等到延迟加载从数据库中取出它们:

 var newRolsIds = new List { 1, 2, 5 }; using (var context = new MyObjectContext()) { var user = context.Users.Include("Roles") .Single(u => u.UserId == 3); // loads user with roles, for example role 3 and 5 var newRoles = context.Roles .Where(r => newRolsIds.Contains(r.RoleId)) .ToList(); user.Roles.Clear(); foreach (var newRole in newRoles) user.Roles.Add(newRole); context.SaveChanges(); } 

您可以附加它们,而不是从数据库中加载新角色,因为您在示例中知道了键属性值。 您还可以删除完全缺少的角色,而不是清除整个集合,而不是重新添加现有角色:

 var newRolsIds = new List { 1, 2, 5 }; using (var context = new MyObjectContext()) { var user = context.Users.Include("Roles") .Single(u => u.UserId == 3); // loads user with roles, for example role 3 and 5 foreach (var role in user.Roles.ToList()) { // Remove the roles which are not in the list of new roles if (!newRoleIds.Contains(role.RoleId)) user.Roles.Remove(role); // Removes role 3 in the example } foreach (var newRoleId in newRoleIds) { // Add the roles which are not in the list of user's roles if (!user.Roles.Any(r => r.RoleId == newRoleId)) { var newRole = new Role { RoleId = newRoleId }; context.Roles.Attach(newRole); user.Roles.Add(newRole); } // Adds roles 1 and 2 in the example } // The roles which the user was already in (role 5 in the example) // have neither been removed nor added. context.SaveChanges(); }