2016-12-27 17 views
7

データベースに3種類の製品があり、すべての製品に独自のテーブルがあります(Product1,Product2Product3など)。ほとんどの製品テーブルは同じスキーマを持ちます。私は別のテーブルで別々のタイプの製品を入手するという要件があります。Entity Frameworkの複数の類似したエンティティタイプの一般的なクエリ

私は現在の製品は、各製品タイプのための1つを取得するための3つの方法があります:呼び出しの製品は、私は、製品の種類を受け入れ、それぞれのメソッドを呼び出すWEBAPI方法がありますが

public List<Product1> GetProduct1Data() { 
    //.... 
    context.Product1.Where(..).Tolist(); 
} 

public List<Product2> GetProduct2Data() { 
    //.... 
    context.Product2.Where(..).Tolist(); 
} 

public List<Product3> GetProduct3Data() { 
    //.... 
    context.Product3.Where(..).Tolist(); 
} 

を:

public IHttpActionResult GetProducts(ProductType product) 
{ 
    ///.... 
    // Ii have to call repositories according to product parameter 
} 

Entity Frameworkには、1つのメソッドだけでテーブルを選択できる方法がありますか?

答えて

9

インターフェイス制約のある汎用メソッドを使用できます。あなたが適用されますが、エンティティクラスに共通しているプロパティのインターフェイスを作成

public partial class Product1 { 
    public string Column1 { 
     get; 
     set; 
    } 

    public string Column2 { 
     get; 
     set; 
    } 
} 


public partial class Product2 { 
    public string Column1 { 
     get; 
     set; 
    } 

    public string Column2 { 
     get; 
     set; 
    } 
} 


public partial class Product3 { 
    public string Column1 { 
     get; 
     set; 
    } 

    public string Column2 { 
     get; 
     set; 
    } 
} 

...

interface IProduct { 
    string Column1 { 
     get; 
     set; 
    } 

    string Column2 { 
     get; 
     set; 
    } 
} 

...:

あなたはこれらの自動生成されたPOCOクラスを持っています生成されたクラス(新しいコードファイルでは、クラスはそれを可能にするために部分的です):

これで、クエリ用の汎用メソッドを作成できます。あなたはそれあなたのDbSet秒にそれを適用する拡張メソッド作ることができます。

static class ProductExtensions { 
    public static List<T> GetProducts<T>(this DbSet<T> products) 
     where T : IProduct { 

     var productQry = 
      from product in products 
      where product.Column1 == "Example" 
      select product; 
     return productQry.ToList(); 
    } 
} 

あなたはDbSetの上、この拡張メソッドを使用することができます。

List<Product1> product1List = context.Product1s.GetProducts(); 
List<Product2> product2List = context.Product2s.GetProducts(); 
List<Product3> product3List = context.Product3s.GetProducts(); 

あなたが持っている唯一の制限が列ということですあなたのテーブルに本当に同じ名前とタイプが必要です。 EFは明示的なインタフェース実装を認識しません。一方、テーブルは完全に同一である必要はありません。列の一部(一致する必要がある部分)のインターフェースを定義することができ、残りは異なることがあります。

+0

拡張方法を教えてください。 –

+0

@Imranbutt:Googleはあなたの友人です:http://www.google.com/#q=extension+methods – Sefe

+0

基本的に私は「製品からの製品」のラインと混同しています。「製品のソースから」という意味ですか?それ以外の場合、それは完全にうまくいっている@sefe –

1

提供される回答は最も洗練された解決策ですが、私は代替案を考えています。ビューへのマッピングです。

表は主に読み出しおよび集約方法で使用される様々な製品が(一度に多くの種類から読み出さ)場合、それらのすべての景色を作成してマッピングすることが便利であり得る:

CREATE VIEW ProductAggregated 
AS 
SELECT 1 AS ProdTypeId, ProdId AS ProductId, Name AS ProductName   -- other product columns may come here 
UNION ALL 
SELECT 2 AS ProdTypeId, Id AS ProductId, ProdName AS ProductName   -- different columns names may be harmonized with aliasing 
-- other product types table may be entered here 

ビューにPOCO地図:

public enum ProdType 
{ 
    None = 0,     -- as default value, if needed 
    ProdType1 = 1, 
    ProdType2 = 2 
    ProdType3 = 3 
} 

public class ProductAggregated 
{ 
    public int ProdTypeId { get; set; } 
    public string ProductName { get; set; } 
    // other properties come here 
} 

関連する製品タイプを列挙に定義されてもよいです

あなたは簡単に自然条件に基づいて製品を選択することがあります。

// all products 
var allProducts = context.ProductAggregateds.ToList(); 

// all products of certain types 
var types = new List<int> { (int)ProdType.ProdType1, (int)ProdType.ProdType3 }; 
var only13Products = context.ProductAggregateds 
    .Where(p => types.Contains(p.ProductTypeId) 
    .ToList(); 

新製品タイプが作成され、その特定の列を扱っていないアプリケーションは、ちょうどALLビューにUNIONを追加し、すべてが正常に動作する必要がありますされている場合。

+0

はい、これは解決策である可能性があります。 –

+0

ビューにマップすることができます。欠点は、エンティティクラスを直接ビューにマップするときにナビゲーションプロパティを追加できないことです。ビューに変換するテーブルにマップするときは、DBからmodleを更新するたびに手動作業を繰り返す必要があります( – Sefe

+0

)。また、データベースの第1のアプローチでは、設計者自身がキーであることを知ることができず、警告を出力します。明らかに、あなたのソリューションは優れています(個人的には、SQLのものよりもC#のアプローチが好きです)。しかし、多くの製品タイプがあり、C#のサービスレイヤとは無関係な場合、これが考えられます。また、SQLのような "インターフェイスのような"使用を可能にします。 – Alexei

関連する問題