web-dev-qa-db-fra.com

Trouver un DbSet générique spécifié dans un DbContext de manière dynamique lorsque 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 aussi une liste d'objets que je souhaite ajouter à mon contexte, mais je ne sais pas comment trouver le générique DbSet approprié en fonction de chaque type d'entité de manière dynamique. 

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 puis je faire ça?

23
Masoud

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

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

Donc dans votre cas:

foreach (BaseEntity entity in list)
{
      cntx.Set(entity.GetType()).Add(entity);         
}
34
Pablo Romeo

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 toujours utiliser une méthode d'extension 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 renvoyant également 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>;
    } 
13
user3141326

En plus de Pablo répondre:

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 ajoute une méthode Extention AsEnumerable à DbSet et lorsque vous souhaitez l’utiliser par exemple pour Count ou filter une ligne:

var someDbSet = this.Set(typeof(SomeEntity));
var count = (from a in someDbSet.AsEnumerable() select a).Count();
0
combo_ci