Agregar / quitar muchas a muchas asociaciones en Entity Framework

Tengo tres tablas en mi base de datos de muestra:

Usuari@s

  • ID
  • Usuario
  • Contraseña

Roles

  • ID
  • Nombre
  • Descripción

Roles del usuario

  • ID de usuario
  • Identificación del rol

UserRoles es una tabla de búsqueda para simular una relación de varios a varios. Agregar registros a esta tabla permite asociar registros en Usuarios y Roles. Mi problema es que en Entity Framework interpreta correctamente esto como una relación de muchos a muchos y abstrae esa tabla de búsqueda.

Esto funciona muy bien la mayor parte del tiempo, pero no estoy seguro de qué hacer cuando quiero agregar / eliminar entradas de esa tabla de búsqueda. Puedo eliminar roles o usuarios, pero eso en realidad elimina los objetos, no solo su asociación entre sí.

Conozco una opción para agregar una columna ficticia a la tabla de búsqueda UserRoles. Eso obligará a Entity Framework a convertir la tabla de búsqueda en una entidad en toda regla, lo que me permitirá agregarlos y eliminarlos como objetos solitarios. Pero no necesito una columna ficticia y esto parece un truco. Busco mejores sugerencias.

preguntado el 19 de julio de 11 a las 12:07

3 Respuestas

Debería verse algo como esto:

Para eliminar la relación

user.Roles.Remove(existingRoleEntity);

Para agregar relación

user.Roles.Add(existingRoleEntity);

Respondido 19 Jul 11, 16:07

¿Cómo agregaría una entrada a la tabla de búsqueda? - Chev

@Alex: de la misma manera, pero usando Add en lugar de Remove. user.Roles.Add(role) or role.Users.Add(user). - StriplingGuerrero

¡Ajá! Yo no estaba al tanto de esto. En realidad, esta es una mejor solución para lo que queremos. - Chev

Puede utilizar las propiedades de navegación en las entidades:

(asumiendo que u es un objeto Usuario):

using (var db = new UserEntities())
{
    Role roleToRemove = db.Roles.Single(SelectRoleHere);
    User user = db.Users.Single(SelectUserHere);
    user.Roles.Remove(roleToRemove);
    db.SaveChanges();
}

EDITAR - Agregado SaveChanges basado en el comentario de Slauma.

Respondido 19 Jul 11, 16:07

Así que yo también lo haría, además de SaveChanges () :) - Slauma

Esto está bien, pero ¿cómo se agrega una relación también? - Chev

@Alex Ford: Reemplazar .Remove by .Add. - Slauma

Entendido, no estaba al tanto de esto. Lo acabo de probar en mi aplicación de muestra. ¡Funciona magníficamente! - Chev

He resuelto este problema antes simplemente agregando una columna de Incremento automático del identificador de clave privada a la tabla de búsqueda como Entity Framework siempre ocultará las tablas de búsqueda que solo contengan 2 columnas con claves externas para las tablas finales. A veces necesita agregar una entrada de búsqueda directamente usted mismo a través de Entity Framework y esto te ayudará a lograrlo.

Actualización del autor de la pregunta

Solo quería proporcionar una actualización sobre mi propia implementación de esta respuesta. Agregué una columna de identidad a la tabla de búsqueda y creé una clave única sobre las dos columnas de clave externa para evitar entradas de relación duplicadas en la tabla. Mi modelo ahora se ve así:

http://www.codetunnel.com/content/images/ManyToManyDynamic.jpg

Lo único que apesta es obtener una colección de todos los roles asociados que tendría que hacer esto:

List<Role> roles = new List<Role>();
foreach (UserRole userRole in myUser.UserRoles)
    roles.Add(userRole.Role);

Es un poco más de trabajo, pero a menos que haya un equivalente a user.Roles.Remove(role) (algo como user.Roles.Associate(existingRoleEntity)) entonces esta es mi única opción.

Actualizar:

List<Role> roles = new List<Role>();
foreach (UserRole userRole in myUser.UserRoles)
    roles.Add(userRole.Role);

Se puede lograr a través de:

IEnumerable<int> roleIDs = myUser.UserRoles.Select(r => r.RoleID);
IEnumerable<Role> roles = Entityies.Roles.Where(r => roleIDs.Contains(r.roleID);

Siempre puedes usar un clase pública parcial extender User tener una propiedad para devolver todos los roles usando lo anterior. Haga clic en el enlace para obtener detalles del public partial class cosas que di sobre otra pregunta.

contestado el 23 de mayo de 17 a las 12:05

No pensé en hacer de la columna ficticia una columna de identificador PK. No parece tan superfluo de esta manera. Necesito agregar y eliminar de esto para que sea una entidad tiene sentido. ¡Gran respuesta! - Chev

@Alex Ford: Realmente destruyes la relación de muchos a muchos de esta manera. Tenías que introducir una nueva entidad artificial y luego hacer dos relaciones de 1 a muchos. Se supone que la tabla de combinación en relaciones de muchos a muchos en EF está oculta en el modelo. - Slauma

@Slauma, hacer esto te permite agregar muchos Roles a una User, por ejemplo, sin cargar el User y agregarle roles. Puede ser útil agregarlos directamente y en casos más complicados puede ser necesario. - chris snowden

@Slauma, sé que destruí la abstracción. Sin embargo, es simplemente un paso adicional por hacer User.UserRoles.Single(some condition).Role y me da la posibilidad de agregar relaciones y eliminarlas. A menos que pueda proporcionar una forma de agregar relaciones a la tabla de búsqueda mientras mantiene la abstracción, esta es mi única opción. - Chev

Hacer esto también le permitiría agregar el mismo Role a una User varias veces, lo que realmente no modela muy bien una relación de varios a varios. A menos que tenga información específica que desee adjuntar a la relación, manténgase en la forma en que Entity Framework lo ha diseñado. Vea el comentario en mi publicación para obtener información sobre cómo agregar la relación. - StriplingGuerrero

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.