【问题标题】:Linq: IQueryable extension methods works on DBSet but not on ICollectionLinq:IQueryable 扩展方法适用于 DBSet,但不适用于 ICollection
【发布时间】:2019-04-23 00:09:54
【问题描述】:

我有一个项目包 实体框架 6.1.0

我正在使用 DB-First 模型

一些模型实体以这种方式扩展:

public interface IVersionable{
int VersionId{get;set;}
}
public interface IEditable{
bool IsEditable{get;set;}
}
public interface IFullFeatures:IVersionable,IEditable{}
public partial EntityOne:IFullFeatures{
   //This is the extension partial class for the auto-generated model class EntityOne that already has interface properties
}
public partial EntityTwo:IFullFeatures{
   //This is the extension partial class for the auto-generated model class EntityTwo that already has interface properties
}

自动生成的类 EntityOne 和 EntityTwo 具有 IFullFeatures 所需的所有属性,对于 EntityTwo 自动生成的文件,我们有这个 ICollection:

public virtual ICollection<EntityOne> EntityOne {get;set;}

我终于有了扩展方法:

public static class FeaturesExtensionMethod{
     public static IQueryable<T> FilterEditable<T>(this IQueryable<T> source) where T:class,IEditable{
         return source.Where(s=>s.IsEditable);
     }
     public static IQueryable<T> FilterVersion<T>(this IQueryable<T> source, int versionId) where T:class,IVersionable{
         return source.Where(s=>s.VersionId==versionId);
     }
     public static IQueryable<T> FullFilter<T>(this IQueryable<T> source, int versionId) where T:class,IVersionable{
         return source.FilterEditable().FilterVersion(versionId);
     }
}

然后,当我在运行时执行这个:

var everyEntitiTwo=ctx.EntityTwo.FullFilter(4).ToList();

没问题,它工作正常并且过滤...但是在运行时我改为执行此操作:

var test= ctx.EntityTwo.Include("EntityOne").Select(et=>et.EntityOne.AsQueryAble().FullFilter(4)).ToList()

我收到此错误:

LINQ to Entities 无法识别方法“FullFilter”方法,并且该方法无法转换为存储表达式。

所以问题是:我的扩展方法有什么问题?为什么我在第二种情况下得到这个错误,甚至在第一种情况下都没有?

谢谢。

更新

感谢 Jon Hanna,我受到了这种替代方法的启发,以达到相同的结果:

我创建了一个“代理类”来获取过滤器,因为 Expression > 它是强类型的,我需要更通用的东西:

public static FilterProxies{
    public static GetProxiedFilter<T>(int versionId, bool onlyEditable) where T: class, IFullFeatures{
       Expression<Func<T,bool>> filteredExp
       if(onlyEditable){
          filteredExp=(iff=>iff.VersioneId==versionId&&iff.IsEditable);
       }
       else{
          filteredExp=(iff=>iff.VersioneId==versionId); 
       }
       return filteredExp;
   }
}

那么,在使用中:

var filter=FilterProxies.GetProxiedFilter<EntityOne>(4,true);
var test= ctx.EntityTwo.Include("EntityOne").Select(et=>et.EntityOne.AsQueryAble().Where(filter)).ToList()

希望对更新这篇文章有所帮助,感谢 Jon 激励我应用此解决方案

【问题讨论】:

标签: c# entity-framework extension-methods


【解决方案1】:

EF 无法将方法 FullFilter 转换为 SQL,因为您使用的是 LINQ to Entities。您可能需要使用 Linq to Objects

ctx.EntityTwo.ToList() 在您的方法之前,因此它首先获取您的对象列表,然后使用该列表执行您的方法,这样做您正在执行 LINQ To Objects

【讨论】:

    【解决方案2】:
    ctx.EntityTwo.FullFilter(4).ToList();
    

    立即变成了

    ctx.EntityTwo.Where(s => s.IsEditable).Where(s => s.VersionId == 4).ToList();
    

    这当然是 Entity Framework 可以处理的。

    var test= ctx.EntityTwo.Include("EntityOne").Select(et=>et.EntityOne.AsQueryAble().FullFilter(4)).ToList()
    

    因为可查询扩展的使用是查询中并作用于不同类型的可查询,所以方法调用是传递给实体框架的表达式的一部分,它不知道什么FullFilter() 确实如此,并且在这一点上窒息。

    【讨论】:

    • thx,但是我该如何处理这个问题,以及为什么 LINQ 的扩展方法被承认? et.EntityOne.AsQueryable().Where(....) 据我所知不是问题,那么……我该怎么办?
    • Entity Framework 确实知道 WhereSelect 等。您可以编写一些产生适当的 Expression&lt;Func&lt;EntityOne, IQueryable&lt;EntityTwo&gt;&gt;&gt; 的内容,以传递给 Select
    • 这似乎“为酱汁”付出了太多努力......但我非常感谢你,如果你有一些例子我会很高兴看到他们,以便与Linq一起成长SQL
    • 再次感谢 Jon Hanna,我解决并更新了帖子,解释了我的做法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 2019-09-23
    • 1970-01-01
    • 2013-04-10
    • 2013-09-21
    相关资源
    最近更新 更多