我试图在我的基类上创建可重用的搜索查询,这样我就不必为每个派生的类重复相同的代码,但我无法让实体框架很好地发挥作用。
我有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 (接口) -->这种方法来自:LINQ to Entities only supports casting EDM primitive or enumeration types with IEntity interface
最终,它们都会返回错误:
LINQ to Entities仅支持使用IEntity接口强制转换EDM基元或枚举类型。
最终,我希望在基类属性上定义一个查询,但输出子类。现在,我似乎需要复制/粘贴每个派生类的方法。
发布于 2018-12-10 21:18:04
您只需要接受查询已经具有的实际类型的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);
}
发布于 2018-12-10 21:08:14
经过大量实验之后,解决方案是将基类创建为抽象类
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 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,
...
}
}
}
https://stackoverflow.com/questions/53713668
复制