2012-01-15 14 views
17

He estado usando EF4 (no código primero) desde hace un año, así que no soy realmente un experto con eso. Tengo una duda al usar la relación muchos a muchos con respecto a la actualización de guardar n.marco de entidad actualización relación muchos a muchos: virtual o no

Leí en algún lugar en stackoverflow (ya no puedo encontrar la url) esa única solución - actualizar una relación existente de varios a muchos - es no declarar la propiedad "virtual"; pero, si lo hago de esta manera, el motor no puede cargar datos con una carga fácil.

¿Pueden por favor explicarme la razón? Otherwire, ¿podría ayudarme a encontrar algunos documentos geniales sobre este tema?

THX

Respuesta

56

Puede actualizar un muchos-a-muchos relación de esta manera (como un ejemplo que da el usuario 3 el papel 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(); 
} 

Si la colección User.Roles se declara como virtual la La línea user.Roles.Add(role); activará la carga diferida, lo que significa que todos los roles de para el usuario se cargan primero de la base de datos antes de agregar el nuevo rol.

Esto es, de hecho, preocupante porque no es necesario cargar toda la colección Roles para agregar un nuevo rol al usuario.

Pero esto no significa que tenga que eliminar la palabra clave virtual y abandonar por completo la carga diferida. Usted sólo puede desactivar la carga diferida en esta situación específica:

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

Editar

Si desea actualizar toda la colección de papeles de un usuario preferiría para cargar los papeles originales con carga ansiosa (= Include). Es necesario esta lista de todos modos para eliminar posiblemente algunos papeles, por lo que no es necesario esperar hasta que la carga diferida de ellos obtiene a partir de la base de datos:

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

En lugar de cargar las nuevas funciones de la base de datos también puede adjuntar ellos desde usted sabe en el ejemplo el valor de la propiedad clave. También puede eliminar exactamente las funciones que faltan en lugar de borrar toda la colección y en lugar de volver a agregar las funciones existentes:

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

th Slauma. Entendí el caso en el que deseo agregar un nuevo Rol al usuario de la colección. Roles. Lo que no puedo entender es el caso general en el que tengo que manipular un conjunto de Roles. Por ejemplo: user.Roles contiene 3,5 roles; luego, elijo actualizar user.Roles para que contenga 1,2,5 (tengo que eliminar 3 y tengo que agregar 1,2 en user.Roles). ¿Funciona de la misma manera? – frabiacca

+1

@frabiacca: ver mi edición. – Slauma

+1

¡Lo intenté ... y funciona! :) thx tanto slauma – frabiacca

Cuestiones relacionadas