2012-01-15 13 views
17

Ho utilizzato EF4 (non prima di codice) da un anno, quindi non sono davvero un esperto con esso. Ho un dubbio sull'uso della relazione molti-a-molti per quanto riguarda il salvataggio dell'aggiornamento.struttura entità aggiornamento relazione molti a molti: virtuale o non

Ho letto da qualche parte su StackOverflow (non riesco più a trovare l'url) che una soluzione - per aggiornare una relazione molti-a-molti esistente - è di non dichiarare la proprietà "virtuale"; ma, se faccio così, il motore non può caricare dati con un caricamento facile.

Potete spiegarmi il motivo? Otherwire, potresti aiutarmi a trovare alcuni documenti interessanti su questo tema?

thx

risposta

56

È 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(); 
} 
+0

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

+1

@frabiacca: Vedi il mio Modifica. – Slauma

+1

Ho provato ... e funziona !! :) thx so much slauma – frabiacca

Problemi correlati