在LINQ to Entities中使用自定义方法/扩展方法的变通方法

时间:2011-02-01 19:32:14

标签: linq c#-4.0 linq-to-entities extension-methods

我已经定义了一个执行数据库交互的GenericRepository类。

 protected GenericRepository rep = new GenericRepository();

在我的BLL课程中,我可以查询数据库,如:

public List<Album> GetVisibleAlbums(int accessLevel)
{
    return rep.Find<Album>(a => a.AccessLevel.BinaryAnd(accessLevel)).ToList();  
}  

BinaryAnd是一种扩展方法,它逐位检查两个int值。例如AccessLevel=5 =&gt; AccessLevel.BinaryAnd(5)AccessLevel.binaryAnd(1)都返回true。

但是我无法在LINQ查询中使用此扩展方法。我得到一个运行时错误如下:
LINQ to Entities does not recognize the method 'Boolean BinaryAnd(System.Object, System.Object)' method, and this method cannot be translated into a store expression.

还尝试将其更改为自定义方法,但没有运气。解决方法有哪些?

我是否应该获取所有专辑,然后通过foreach循环迭代它们并选择与AccessLevels匹配的专辑?

3 个答案:

答案 0 :(得分:8)

我意识到这已经有了一个公认的答案,我只是想发布这个以防有人想尝试编写LINQ表达式拦截器。

所以......这就是我做的可翻译自定义扩展方法:Code Sample

我不认为这是一个完成的解决方案,但它应该为任何勇敢的人看到它完成提供一个良好的起点。

答案 1 :(得分:7)

IQueryable<T>上使用实体框架和查询时,您只能使用core extension methods and CLR methods defined for your EF provider。这是因为查询直接转换为SQL代码并在服务器上运行。

您可以流式传输整个集合(使用.ToEnumerable()),然后在本地查询,或将其转换为可由提供商直接转换为SQL的方法。

话虽如此,basic bitwise operations are supported

  

当操作数是数字类型时,按位AND,OR,NOT和XOR运算符也映射到规范函数。

因此,如果你重写它不使用方法,并且只是直接对值进行按位操作,它应该根据需要工作。尝试以下内容:

public List<Album> GetVisibleAlbums(int accessLevel)
{
    return rep.Find<Album>(a => (a.AccessLevel & accessLevel > 0)).ToList();  
}

(我不确定你当前的扩展方法是如何工作的 - 上面会检查是否有任何标志返回true,这似乎与你的陈述相符......)

答案 2 :(得分:1)

有很多方法可以在EF将其转换为SQL之前更改linq查询,此时您必须将“外部”方法转换为EF可翻译的构造。

请参阅我的前一个问题How to wrap Entity Framework to intercept the LINQ expression just before execution?和我的EFWrappableFields extension,这些问题仅适用于包装字段。