update one net many framework first asp c# entity-framework many-to-many

c# - net - Seguimiento de los cambios en Entity Framework para relaciones de muchos a muchos con el comportamiento



one to many entity framework (3)

Creo que el problema radica en la definición de su clase de Program y Group y en el método anulado de SaveChanges . Con la definición actual de las clases, el EF no puede usar proxies de seguimiento de cambios, que captura los cambios a medida que se realizan. En lugar de eso, el EF se basa en la detección de cambio de instantánea, que se realiza como parte del método SaveChanges . Dado que llama a base.SaveChanges() al final del método anulado, los cambios aún no se detectan cuando los solicita a ChangeTracker .

Tiene dos opciones: puede llamar a ChangeTracker.DetectChanges(); al comienzo del método SaveChanges o cambio de definición de sus clases para admitir los proxies de seguimiento de cambios.

public class Program { public int ProgramId { get; set; } public virtual ICollection<ProgramGroup> ProgramGroups { get; set; } } public class Group { public int GroupId { get; set; } public virtual ICollection<ProgramGroup> ProgramGroups { get; set; } }

Los requisitos básicos para crear proxies de seguimiento de cambios son:

  • Una clase debe ser declarada como pública.

  • Una clase no debe ser sellada

  • Una clase no debe ser abstracta.

  • Una clase debe tener un constructor público o protegido que no tenga parámetros.

  • Una propiedad de navegación que representa el "muchos" final de una relación debe tener acceso virtual público y establecer accesores

  • Una propiedad de navegación que representa el "muchos" final de una relación debe definirse como ICollection<T>

Actualmente estoy intentando utilizar el ChangeTracker de Entity Framework para fines de auditoría. Estoy anulando el método SaveChanges () en mi DbContext y creando registros para las entidades que se han agregado, modificado o eliminado. Aquí está el código para ese FWIW:

public override int SaveChanges() { var validStates = new EntityState[] { EntityState.Added, EntityState.Modified, EntityState.Deleted }; var entities = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && validStates.Contains(x.State)); var entriesToAudit = new Dictionary<object, EntityState>(); foreach (var entity in entities) { entriesToAudit.Add(entity.Entity, entity.State); } //Save entries first so the IDs of new records will be populated var result = base.SaveChanges(); createAuditLogs(entriesToAudit, entityRelationshipsToAudit, changeUserId); return result; }

Esto funciona muy bien para las entidades "normales". Sin embargo, para relaciones simples de muchos a muchos, tuve que extender esta implementación para incluir "Asociaciones Independientes" como se describe en this fantástica respuesta SO que accede a los cambios a través del ObjectContext así:

private static IEnumerable<EntityRelationship> GetRelationships(this DbContext context, EntityState relationshipState, Func<ObjectStateEntry, int, object> getValue) { context.ChangeTracker.DetectChanges(); var objectContext = ((IObjectContextAdapter)context).ObjectContext; return objectContext .ObjectStateManager .GetObjectStateEntries(relationshipState) .Where(e => e.IsRelationship) .Select( e => new EntityRelationship( e.EntitySet.Name, objectContext.GetObjectByKey((EntityKey)getValue(e, 0)), objectContext.GetObjectByKey((EntityKey)getValue(e, 1)))); }

Una vez implementado, esto también funcionó bien, pero solo para relaciones de muchos a muchos que usan una tabla de unión . Con esto, me refiero a una situación en la que la relación no está representada por una clase / entidad, sino solo por una tabla de base de datos con dos columnas, una para cada clave externa.

Sin embargo, hay ciertas relaciones de muchos a muchos en mi modelo de datos, donde la relación tiene "comportamiento" (propiedades). En este ejemplo, ProgramGroup es la relación de muchos a muchos que tiene una propiedad Pin :

public class Program { public int ProgramId { get; set; } public List<ProgramGroup> ProgramGroups { get; set; } } public class Group { public int GroupId { get; set; } public IList<ProgramGroup> ProgramGroups { get; set; } } public class ProgramGroup { public int ProgramGroupId { get; set; } public int ProgramId { get; set; } public int GroupId { get; set; } public string Pin { get; set; } }

En esta situación, no veo ningún cambio en un ProgramGroup (por ejemplo, si se cambia el Pin) en el DbContext ChangeTracker "normal", ni en el método de relación ObjectContext. Sin embargo, a medida que paso por el código, puedo ver que el cambio está en las Entidades del Estado de ObjectContext, pero su entrada tiene IsRelationship=false que, por supuesto, falla la .Where(e => e.IsRelationship) .

Mi pregunta es ¿por qué una relación de muchos a muchos con el comportamiento no aparece en el DbContext ChangeTracker normal ya que está representada por una clase / entidad real y por qué no está marcada como una relación en los StateEntries de ObjectContext? Además, ¿cuál es la mejor práctica para acceder a este tipo de cambios?

Gracias por adelantado.

EDITAR: En respuesta al comentario de @ FrancescCastells de que tal vez no definir explícitamente una configuración para el ProgramGroup sea ​​la causa del problema, agregué la siguiente configuración:

public class ProgramGroupConfiguration : EntityTypeConfiguration<ProgramGroup> { public ProgramGroupConfiguration() { ToTable("ProgramGroups"); HasKey(p => p.ProgramGroupId); Property(p => p.ProgramGroupId).IsRequired(); Property(p => p.ProgramId).IsRequired(); Property(p => p.GroupId).IsRequired(); Property(p => p.Pin).HasMaxLength(50).IsRequired(); }

Y aquí están mis otras configuraciones:

public class ProgramConfiguration : EntityTypeConfiguration<Program> { public ProgramConfiguration() { ToTable("Programs"); HasKey(p => p.ProgramId); Property(p => p.ProgramId).IsRequired(); HasMany(p => p.ProgramGroups).WithRequired(p => p.Program).HasForeignKey(p => p.ProgramId); } } public class GroupConfiguration : EntityTypeConfiguration<Group> { public GroupConfiguration() { ToTable("Groups"); HasKey(p => p.GroupId); Property(p => p.GroupId).IsRequired(); HasMany(p => p.ProgramGroups).WithRequired(p => p.Group).HasForeignKey(p => p.GroupId); }

Cuando se implementan, EF aún no muestra el grupo de programas modificado en el Change Tracker.


Entity Framework representa relaciones de muchos a muchos al no tener un entidad establecida para la tabla de unión en CSDL, en lugar de eso, lo administra a través de la asignación.

Nota: Entity Framework admite la relación de muchos a muchos solo cuando la tabla de unión NO incluye ninguna columna distinta de las PK de ambas tablas

usted debe tener que definir la propiedad de navegación para cupé con este proplem.

Este link puede ser de su ayuda.


Si bien el concepto de "relación con los atributos" se menciona en la teoría del modelado entidad-relación, en lo que respecta a Entity Framework, su clase ProgramGroup es una entidad. Probablemente lo esté filtrando sin saberlo con la x.Entity is BaseEntity La x.Entity is BaseEntity comprobación de x.Entity is BaseEntity en el primer fragmento de código.