Trouver un DbSet Générique spécifié dans un DbContext dynamiquement quand j'ai une entité

j'ai les classes suivantes et DbContext :

public class Order:BaseEntity
{
   public Number {get; set;}
}
Product:BaseEntity;
{
  public Name {get; set;} 
}

public class Context : DbContext
{
    ....
    public DbSet<Order> Orders { set; get; }
    public DbSet<Product> Products { set; get; }
    ....
}   

j'ai une liste d'objets qui veulent ajouter à mon contexte, aussi, mais je ne sais pas comment trouver DbSet générique approprié selon chaque type d'entité dynamiquement.

IList<BaseEntity> list = new List<BaseEntity>();
Order o1 = new Order();
o1.Numner = "Ord1";
list.Add(o1);

Product p1 = new Product();
p1.Name = "Pencil";
list.Add(p1);

Context cntx = new Context();  
foreach (BaseEntity entity in list)
{
      cntx.Set<?>().Add(entity);         
}

Comment faire?

20
demandé sur Masoud 2014-02-03 21:19:07

3 réponses

DbContext a une méthode appelée Set , que vous pouvez utiliser pour obtenir un non-générique DbSet , tels que:

var someDbSet = this.Set(typeof(SomeEntity));

donc dans votre cas:

foreach (BaseEntity entity in list)
{
      cntx.Set(entity.GetType()).Add(entity);         
}
27
répondu Pablo Romeo 2014-02-03 17:31:23

la question ne spécifie pas la version EF et la réponse proposée ne fonctionne plus pour Entity Framework Core (DbContext n'a pas de méthode d'ensemble non-générique dans EF core au moins à la date de cette réponse).

pourtant, vous pouvez encore avoir une méthode d'extension de travail en utilisant la réponse de Jon Skeet à cette question . Mon code est ajouté ci-dessous pour plus de commodité.

* * mise à jour: Ajout de l'appel de fonction générique retour D'IQueryable< T> grâce au commentaire de Shaddix.

    public static IQueryable Set(this DbContext context, Type T)
    {

        // Get the generic type definition
        MethodInfo method = typeof(DbContext).GetMethod(nameof(DbContext.Set), BindingFlags.Public | BindingFlags.Instance);

        // Build a method with the specific type argument you're interested in
        method = method.MakeGenericMethod(T);

        return method.Invoke(context, null) as IQueryable;
    }

    public static IQueryable<T> Set<T>(this DbContext context)
    {
        // Get the generic type definition 
        MethodInfo method = typeof(DbContext).GetMethod(nameof(DbContext.Set), BindingFlags.Public | BindingFlags.Instance);

        // Build a method with the specific type argument you're interested in 
        method = method.MakeGenericMethod(typeof(T)); 

        return method.Invoke(context, null) as IQueryable<T>;
    } 
9
répondu user3141326 2018-02-22 07:45:26

en plus de Pablo réponse:

Vous pouvez ajouter une classe à votre projet:

namespace System.Data.Entity
{
  public static class EntityFrameworkExtensions
  {
    public static IEnumerable<object> AsEnumerable(this DbSet set)
    {
      foreach (var entity in set)
        yield return entity;
    }
  }
}

cette classe, ajouter une méthode D'extension AsEnumerable à DbSet instance et quand vous voulez l'utiliser par exemple pour Count ou filter une rangée quelconque:

var someDbSet = this.Set(typeof(SomeEntity));
var count = (from a in someDbSet.AsEnumerable() select a).Count();
1
répondu combo_ci 2017-07-21 03:58:59