Linq:IQueryable 扩展方法适用于 DBSet 但不适用于 ICollection

Linq: IQueryable extension methods works on DBSet but not on ICollection

我有一个包含该包的项目 EntityFramework6.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,我得到了启发,采用了这种替代方法来达到相同的结果:

我做了一个 "proxy class" 来获取过滤器,因为 Expression < Func < entityOne,bool> > 它是强类型的,我需要更通用的东西:

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()

希望对更新此内容有所帮助 post,感谢 Jon 启发我应用此解决方案

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()

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

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

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