tutorial framework first example español code entity-framework dbcontext inheritance dbset

entity-framework - first - entity framework tutorial



Hereda de DbSet<T> con el propósito de agregar propiedad (4)

He encontrado una respuesta que funciona para mí. Declaro mis propiedades de DbSet como mi interfaz derivada en mi contexto, por ejemplo:

IDerivedDbSet<Customer> Customers { get; set; } IDerivedDbSet<CustomerOrder> CustomerOrders { get; set; }

Mi implementación incluye un IDbSet privado que se asigna en el constructor, por ejemplo:

public class DerivedDbSet<T> : IDerivedDbSet<T> where T : class { private readonly IDbSet<T> _dbSet; public DerivedDbSet(IDbSet<T> dbSet) { this._dbSet = dbSet; } ... }

Mi implementación de una interfaz derivada de DbContext oculta el método Set <> () así:

new public IDerivedSet<TEntity> Set<TEntity>() where TEntity : class { //Instantiate _dbSets if required if (this._dbSets == null) { this._dbSets = new Dictionary<Type, object>(); } //If already resolved, return stored reference if (this._dbSets.ContainsKey(typeof (TEntity))) { return (IDerivedSet<TEntity>) this._dbSets[typeof (TEntity)]; } //Otherwise resolve, store reference and return var resolvedSet = new GlqcSet<TEntity>(base.Set<TEntity>()); this._dbSets.Add(typeof(TEntity), resolvedSet); return resolvedSet; }

El DbContext derivado devuelve un IDerivedSet recién construido o elige su referencia en caché en un diccionario. En el DbContext derivado, invoco un método del constructor que usa type reflection para pasar por las propiedades de DbContexts y asigna un valor / referencia usando su propio método Set. Mira aquí:

private void AssignDerivedSets() { var properties = this.GetType().GetProperties(); var iDerivedSets = properties.Where(p => p.PropertyType.IsInterface && p.PropertyType.IsGenericType && p.PropertyType.Name.StartsWith("IDerivedSet") && p.PropertyType.GetGenericArguments().Count() == 1).ToList(); foreach (var iDerivedSet in iDerivedSets) { var entityType = iDerivedSet.PropertyType.GetGenericArguments().FirstOrDefault(); if (entityType != null) { var genericSet = this.GetType().GetMethods().FirstOrDefault(m => m.IsGenericMethod && m.Name.StartsWith("Set") && m.GetGenericArguments().Count() == 1); if (genericSet != null) { var setMethod = genericSet.MakeGenericMethod(entityType); iDerivedSet.SetValue(this, setMethod.Invoke(this, null)); } } } }

Funciona un placer para mí. Mi clase de contexto tiene propiedades de conjunto navegables de mi tipo de conjunto que implementa una interfaz derivada heredando IDbSet. Esto significa que puedo incluir métodos de consulta en mi tipo de conjunto, de modo que las consultas sean comprobables por unidad, en lugar de usar las extensiones estáticas de la clase Queryable. (Los métodos Queryable son invocados directamente por mis propios métodos).

¿Hay alguna forma de heredar de DbSet? Quiero agregar algunas propiedades nuevas, como esta:

public class PersonSet : DbSet<Person> { public int MyProperty { get; set; } }

Pero no sé cómo crear una instancia en mi DbContext

public partial MyContext : DbContext { private PersonSet _personSet; public PersonSet PersonSet { get { _personSet = Set<Person>(); // Cast Error here _personSet.MyProperty = 10; return _personSet; } } }

¿Cómo puedo conseguir esto?


Lo resolví usando otra variable para crear una instancia del DbSet "normal".

private DbSet<Person> _persons { get; set; } public PersonDbSet<Person> Persons { get { return new PersonDbSet(_persons); } }

De esta forma, el marco de la entidad reconoce la Entidad, pero aún puedo usar mi propia clase DbSet.


Sé que esto es muy viejo y que el OP probablemente haya cambiado, pero me preguntaba lo mismo. EF rellena los DbSets dentro de su MyContext en tiempo de ejecución.

Acabo de crear MyDbSet <T> que hereda de DbSet <T> y reemplacé todas las referencias a DbSet <T> con mi clase derivada en MyContext. Al ejecutar mi programa, no pude crear una instancia de ninguna de las propiedades.

Luego intenté configurar las propiedades para IDbSet <T> ya que DbSet <T> implementa esta interfaz. Esto SI FUNCIONA

Investigando aún más, los constructores de DbSet están protegidos e internos (el protegido llama al interno de todos modos). Así que MS hizo que sea bastante difícil rodar tu propia versión. Es posible que pueda acceder a los constructores internos mediante la reflexión, pero es probable que EF no construya su clase derivada de todos modos.

Sugeriría escribir un método de extensión para conectar la funcionalidad en el objeto DbSet; sin embargo, está bloqueado si quiere almacenar el estado.


Una solución es crear una clase que implemente IDbSet y delegue todas las operaciones en una instancia DbSet real, para que pueda almacenar el estado.

public class PersonSet : IDbSet<Person> { private readonly DbSet<Person> _dbSet; public PersonSet(DbSet<Person> dbSet) { _dbSet = dbSet; } public int MyProperty { get; set; } #region implementation of IDbSet<Person> public Person Add(Person entity) { return _dbSet.Add(entity); } public Person Remove(Person entity) { return _dbSet.Remove(entity); } /* etc */ #endregion }

Luego, en su DbContext, ponga un getter para su Custom DbSet:

public class MyDbContext: DbContext { public DbSet<Person> People { get; set; } private PersonSet _personSet; public PersonSet PersonSet { get { if (_personSet == null) _personSet = new PersonSet( Set<Person>() ); _personSet.MyProperty = 10; return _personSet; } set { _personSet = value; } } }