我正在尝试在基类上创建可重用的搜索查询,因此不必为每个派生的类重复使用相同的代码,但是我无法使实体框架正常运行。
我有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:泛型,IEntity(接口) ->这种方法来自:LINQ to Entities only supports casting EDM primitive or enumeration types with IEntity interface
最终它们都返回错误:
LINQ to Entities仅支持使用IEntity接口转换EDM基本类型或枚举类型。
最后,我想在基类属性上定义查询,但输出子类。现在看来,我需要按派生类复制/粘贴我的方法。
答案 0 :(得分:0)
与其接受与您想要的类型不同的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);
}
答案 1 :(得分:-1)
经过大量实验,解决方案是将基类创建为抽象
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,
...
}
}
}