我已经定义了一个执行数据库交互的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匹配的专辑?
答案 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,这些问题仅适用于包装字段。