为EntitySet <T>,IQueryable <T>和IEnumerable <T>创建可重用的谓词

Mat*_*s P 12 .net c# linq linq-to-sql

在我的LINQ to SQL设置中,我有各种表映射到基本上支持相同接口以支持版本控制的类,即

public interface IValid
{
    int? validTo { get; }
    int validFrom { get; }
}
Run Code Online (Sandbox Code Playgroud)

LINQ to SQL类派生自此接口,如下所示:

public partial class representationRevision : IValid
{
}
Run Code Online (Sandbox Code Playgroud)

现在我想定义一个DRY(不要重复自己)过滤的方式EntitySet<T>,IEnumerable<T>IQueryable<T>使得所得到的名单是有效的特定修订.我试过这样做:

public static class ExtensionMethods
{

    public static IQueryable<T> ValidFor<T>(this IQueryable<T> v, int? revision)
        where T : IValid
    {
        return v.Where(cr => ((cr.validFrom <= revision) &&
            ((cr.validTo == null) || (cr.validTo > revision)))
            || ((revision == null) && (cr.validTo == null))
            );
    }
}
Run Code Online (Sandbox Code Playgroud)

但是这给出了问题EntitySet<T>.我为EntitySet添加了一个特殊的实现,它首先调用AsQueryable(),但这会引发异常.没有被吓倒我尝试制作一个谓词,所以我可以使用这种Where(predicate)方法:

    public static Expression<Func<contentRevision, bool>> IsValidFor(int? revision)
    {
        return ((cr) => ((cr.validFrom <= revision) &&
            ((cr.validTo == null) || (cr.validTo > revision)))
            || ((revision == null) && (cr.validTo == null)));
    }
Run Code Online (Sandbox Code Playgroud)

.Where<contentRevision>(IsValidFor(revision))它一起使用会产生如下错误:

错误5'System.Data.Linq.EntitySet'不包含'Where'的定义和最佳扩展方法重载
'System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable,System.Func)'有一些无效的参数

请注意,这甚至没有使用IValid接口...我一直在尝试这个主题的各种变化(比如添加int参数),但它们似乎总是失败.有什么指示让我朝着正确的方向前进吗?

Ric*_*ard 5

不确定EntitySet<T>所以会关注IQueryable<T>IEnumerable<T>

为了允许 LINQ 提供程序评估IQueryable<T>用于其表达式参数的表达式树,需要确保保留底层接口。否则就做所有事情IEnumerable<T>(即,如果您可以将整个数据集拉入本地内存,然后在那里处理,而不是在数据库中,只需使用 LINQ to Objects)。

另一个选项是将 a 转换为 a的AsQueryable扩展方法(Queryable类的一部分),然后您可以共享其余代码。IEnumerable<T>IQueryable<T>

IQueryable<T> SomeSharedQuery(this IQueryable<T> source) {
    return source.(LINQ query operators...);
}
IQueryable<T> SomeSharedQuery(this IEnumerable<T> source) {
    return source.AsQueryable().SomeSharedQuery();
}
Run Code Online (Sandbox Code Playgroud)

所以你有共享代码,带有一个适配器方法。