È possibile aggiornare una relazione molti-a-molti in questo modo (come un esempio che dà all'utente 3 il ruolo 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();
}
Se la raccolta User.Roles
è dichiarato come virtual
il linea user.Roles.Add(role);
in effetti attiverà il caricamento lazy che significa che tutti i ruoli per l'utente vengono caricati prima dal database prima di aggiungere il nuovo ruolo.
Questo è di fatto fastidioso perché non è necessario caricare l'intera raccolta Roles
per aggiungere un nuovo ruolo all'utente.
Ma questo non significa che è necessario rimuovere la parola chiave virtual
e abbandonare del tutto il carico pigro. Si può solo spegnere lazy loading in questa situazione specifica:
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();
}
Modifica
Se si desidera aggiornare l'intera ruoli collezione di un utente io preferirei caricare i ruoli originali con eager loading (= Include
). Avete bisogno di questa lista in ogni caso, eventualmente, rimuovere alcuni ruoli, in modo che non c'è bisogno di aspettare fino a lazy loading li recupera dal database:
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();
}
Invece di caricare i nuovi ruoli dal database si può anche collegare in quanto sai nell'esempio il valore della proprietà chiave. Puoi anche rimuovere esattamente i ruoli mancanti invece di cancellare l'intera raccolta e invece di aggiungere nuovamente i ruoli esistenti:
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'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();
}
thx Slauma. Ho capito il caso in cui voglio aggiungere un nuovo ruolo alla collezione user.Roles. Quello che non riesco a capire è il caso generale in cui devo manipolare un insieme di ruoli. Ad esempio: user.Roles contiene 3,5 ruoli; quindi, ho scelto di aggiornare user.Roles in modo che contenga 1,2,5 (devo rimuovere 3 e devo aggiungere 1,2 in user.Roles). Funziona allo stesso modo? – frabiacca
@frabiacca: Vedi il mio Modifica. – Slauma
Ho provato ... e funziona !! :) thx so much slauma – frabiacca