web-dev-qa-db-ja.com

エンティティがある場合、DbContextで指定された汎用DbSetを動的に検索します

次のクラスと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; }
    ....
}   

コンテキストに追加したいオブジェクトのリストもありますが、各エンティティタイプに応じて適切なジェネリックDbSetを動的に見つける方法がわかりません。

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);         
}

どうやってやるの?

26
Masoud

DbContextにはSetというメソッドがあり、これを使用して、次のような非汎用DbSetを取得できます。

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

あなたの場合:

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

質問はEFバージョンを指定しておらず、提案された回答はEntity Frameworkコアでは機能しません(少なくともこの回答の日付では、DbContextのEFコアには非ジェネリックセットメソッドがありません)。

それでも、 この質問 に対するJon Skeetの回答を使用して、有効な拡張メソッドを使用できます。便宜上、以下に私のコードを追加します。

**更新:ジェネリック関数呼び出しを追加し、ShaddixからのコメントのおかげでIQueryable <T>を返すようにしました。

    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>;
    } 
18
user3141326

パブロの答えに加えて:

プロジェクトにクラスを追加できます。

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

このクラスは、拡張メソッドAsEnumerableDbSetインスタンスに追加し、たとえばCountまたはfilter some rowの場合に使用します。

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