Ответ 1
Вы можете обновить отношения "многие-ко-многим" таким образом (в качестве примера, который дает пользователю 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
объявлена как virtual
, строка user.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<Role>(); // necessary, if you are using POCOs
user.Roles.Add(role);
context.SaveChanges();
}
Edit
Если вы хотите обновить всю коллекцию ролей пользователя, я бы предпочел загружать оригинальные роли с нетерпением загрузки (= Include
). Вам нужен этот список в любом случае, чтобы удалить некоторые роли, поэтому вам не нужно ждать, пока ленивая загрузка не извлечет их из базы данных:
var newRolsIds = new List<int> { 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<int> { 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 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();
}