2016-12-27 40 views
7

我有一個場景,我在數據庫中有3種類型的產品,並且所有產品都有自己的單獨表格(例如Product1Product2和和Product3)。幾乎所有的產品表都有相同的模式。我有要求在不同的表格中獲得不同類型的產品。實體框架中多個相似實體類型的常見查詢

我現在有3種方法得到的產品,一個用於每個產品類型:

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

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

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

雖然主叫產品我有接受的產品類型,並調用相應的方法的WebAPI方法:

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

Entity Framework是否有任何方法可以用一種方法選擇表格?

回答

9

您可以使用具有接口約束的通用方法。

當你擁有這些自動生成的POCO類:

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

...你所申請到你生成的類中(在新的代碼文件中 - 這些類只允許你這樣做):

partial class Product1 : IProduct {}; 
partial class Product2 : IProduct {}; 
partial class Product3 : IProduct {}; 

現在您可以爲您的查詢創建一個通用方法。你可以把它的擴展方法將它應用到你的DbSet S:

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 class ProductAggregated 
{ 
    public int ProdTypeId { get; set; } 
    public string ProductName { get; set; } 
    // other properties come here 
} 

相關產品類型可被定義爲一個枚舉:

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

根據自然條件,您可以輕鬆地選擇產品:

// 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(); 

如果創建了一個新的產品類型和應用程序不具有其特定的列處理,只需添加一個UNION ALL的視圖,並應當一切正常。

+0

是的,你是對的,這可能是解決方案... –

+0

你可以映射到一個視圖。缺點是,當您將實體類直接映射到視圖時,無法添加導航屬性。當您映射到一個表格並將其轉換爲視圖時,您需要在每次更新數據庫中的模型時重複手動操作, – Sefe

+0

這是正確的。另外,在數據庫第一種方法中,設計人員無法自行確定哪個是關鍵並輸出警告。顯然,你的解決方案更好(個人而言,我喜歡C#方法而不是SQL方法),但是如果有很多產品類型,並且它們與C#中的服務層無關,可以考慮這一點。它還允許在SQL中使用「接口」。 – Alexei