代码之家  ›  专栏  ›  技术社区  ›  Justin

使用ef中的基类创建iqueryable<t>扩展

  •  0
  • Justin  · 技术社区  · 7 年前

    我试图在基类上创建可重用的搜索查询,这样就不必为每个dervived类重复相同的代码,但我无法让实体框架发挥良好的作用。

    我有三门课: 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 only supports casting EDM primitive or enumeration types with IEntity interface

    最终他们都会返回错误:

    linq-to-entities只支持将edm原语或枚举类型转换为具有方向性接口的类型。

    最后,我想在基类属性上定义一个查询,但输出子类。现在看来我需要复制/粘贴每个派生类的方法。

    2 回复  |  直到 7 年前
        1
  •  0
  •   Servy    7 年前

    而不是接受 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);
    }
    
        2
  •  -1
  •   Justin    7 年前

    经过大量的实验,解决方案是创建抽象的基类

    public abstract class CMEntityBase
    {
    
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public abstract decimal ID { get; set; }
    
    
        [StringLength(50)]
        public abstract string Name { get; set; }
    
        ....
    }
    

    在静态扩展类中定义我的扩展, 这里的关键是使用。选择(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);
    

    事件使用我的“casting”函数转换为视图模型

                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,
                ...
            }
        }
     }