簡體   English   中英

創建IQueryable <T> EF中使用基類擴展

[英]Create IQueryable<T> extension using base class in EF

我試圖在我的基類上創建可重用的搜索查詢,所以我不必為每個派生的類重復相同的代碼,但是我無法使實體框架發揮出色。

我有3個類別:CMEntityBase CMSite CMSiteServer

Site和SiteServer都派生自具有共同屬性(ID,名稱等)的CMEntityBase

我想定義一些通用搜索:例如GetByName

using (var db = new LNOSCMDataModel())
            {
                db.Configuration.LazyLoadingEnabled = false;
                var servers = db.CMSiteServers.
                    AsNoTracking().
                    GetByName(id,Active).
                    ConvertToAPIVM().ToList();
}

我嘗試過幾種定義GetByName的方法:

基類:

    public static IQueryable<CMEntityBase> GetByName(this IQueryable<CMEntityBase> Entities, string Name, bool Active = true)
    {
        return Entities.Where(ss => ss.Name == Name && ss.Active == Active || Active == false);//.Cast<IEntity>();
    }

仿制葯:

public static IQueryable<T> GetByName<T>(this IQueryable<CMEntityBase> Entities, string Name, bool Active = true) where T : CMEntityBase
        {
            return Entities.Where(ss => ss.Name == Name && ss.Active == Active || Active == false).Cast<T>();
        }

我試過將基類定義為接口,並使用T:class,IEntity(interface)泛型->這種方法來自: LINQ to Entities僅支持使用IEntity接口轉換EDM基本類型或枚舉類型

最終他們都返回錯誤:

LINQ to Entities僅支持使用IEntity接口轉換EDM基本類型或枚舉類型。

最終,我想在基類屬性上定義查詢,但輸出子類。 現在看來,我需要根據派生類復制/粘貼我的方法。

與其接受一個與您想要的類型不同的IQueryable並嘗試進行強制轉換(如錯誤指示所示,不支持該類型),您只需接受一個已經屬於您查詢的實際類型的IQueryable ,這樣無需投放。 在這種情況下,就像在原始查詢中使用泛型類型(而不是基本類型)一樣簡單:

public static IQueryable<T> GetByName<T>(this IQueryable<T> Entities, string Name, bool Active = true)
    where T : CMEntityBase //or the interface that specifies the needed members
{
    return Entities.Where(ss => ss.Name == Name && ss.Active == Active || Active == false);
}

經過大量實驗,解決方案是將基類創建為抽象類

public abstract class CMEntityBase
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public abstract decimal ID { get; set; }


    [StringLength(50)]
    public abstract string Name { get; set; }

    ....
}

在靜態擴展類中定義我的擴展, 這里的關鍵是使用.Select(e => e as T)將其轉換回子類

public static partial class CMEntityBaseExtensions
{
    public static IQueryable<T> GetByName<T>(this IQueryable<T> Entities, string Name, bool Active = true) where T : CMEntityBase
    {
        return Entities.Where(ss => ss.Name == Name && ss.Active == Active || Active == false).
                 Select(e => e as T); // cast back to child!
    }
}

然后我可以在我的控制器中使用它:

 var servers1 = db.CMSiteServers
                .AsNoTracking().
                GetByName(id, Active);

和事件使用我的“廣播”功能轉換為視圖模型

            var servers = servers1.
                ConvertToAPIVM().ToList();

看起來像這樣:

public static partial class CMSiteServerExtensions
{
    public static IQueryable<CMSiteServerAPIVM> ConvertToAPIVM(this IQueryable<CMSiteServer> Servers)
    {
        return Servers.Select(ss => new CMSiteServerAPIVM()
        {
            SiteServerID = ss.ID,
            Name = ss.Name,
            Description = ss.Description,
            ...
        }
    }
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM