找到了一个完美的解决方法!在实体框架 6.1.3 上测试。
无法将<
运算符与字节数组一起使用,因为 C# 类型系统会阻止这种情况(应该如此)。但是您可以做的是使用表达式构建完全相同的语法,并且有一个漏洞可以让您解决这个问题。
第一步
如果您不想要完整的解释,您可以跳到解决方案部分。
如果你不熟悉表达式,这里是MSDN 的速成课程。
基本上,当您键入时queryable.Where(obj => obj.Id == 1)
,编译器实际上输出的内容与您键入的内容相同:
var objParam = Expression.Parameter(typeof(ObjType));
queryable.Where(Expression.Lambda<Func<ObjType, bool>>(
Expression.Equal(
Expression.Property(objParam, "Id"),
Expression.Constant(1)),
objParam))
该表达式是数据库提供程序解析以创建您的查询的内容。这显然比原来的要冗长得多,但它也允许您像进行反射一样进行元编程。冗长是这种方法的唯一缺点。与此处的其他答案相比,它有一个更好的缺点,例如必须编写原始 SQL 或无法使用参数。
就我而言,我已经在使用表达式,但在您的情况下,第一步是使用表达式重写您的查询:
Foo lastFoo = GetSomeFoo();
var fooParam = Expression.Parameter(typeof(Foo));
var recent = MyContext.Foos.Where(Expression.Lambda<Func<Foo, bool>>(
Expression.LessThan(
Expression.Property(fooParam, nameof(Foo.Version)),
Expression.Constant(lastFoo.Version)),
fooParam));
<
如果我们尝试在byte[]
对象上使用,这就是我们绕过编译器错误的方法。现在,我们得到了运行时异常,而不是编译器错误,因为Expression.LessThan
尝试查找byte[].op_LessThan
并在运行时失败。这就是漏洞的来源。
漏洞
为了摆脱那个运行时错误,我们将告诉Expression.LessThan
使用什么方法,这样它就不会尝试找到byte[].op_LessThan
不存在的默认方法 ( ):
var recent = MyContext.Foos.Where(Expression.Lambda<Func<Foo, bool>>(
Expression.LessThan(
Expression.Property(fooParam, nameof(Foo.Version)),
Expression.Constant(lastFoo.Version),
false,
someMethodThatWeWrote), // So that Expression.LessThan doesn't try to find the non-existent default operator method
fooParam));
伟大的!现在我们所需要的只是MethodInfo someMethodThatWeWrote
从带有签名的静态方法创建的,bool (byte[], byte[])
以便类型在运行时与我们的其他表达式匹配。
解决方案
您需要一个小的DbFunctionExpressions.cs。这是一个截断的版本:
public static class DbFunctionExpressions
{
private static readonly MethodInfo BinaryDummyMethodInfo = typeof(DbFunctionExpressions).GetMethod(nameof(BinaryDummyMethod), BindingFlags.Static | BindingFlags.NonPublic);
private static bool BinaryDummyMethod(byte[] left, byte[] right)
{
throw new NotImplementedException();
}
public static Expression BinaryLessThan(Expression left, Expression right)
{
return Expression.LessThan(left, right, false, BinaryDummyMethodInfo);
}
}
用法
var recent = MyContext.Foos.Where(Expression.Lambda<Func<Foo, bool>>(
DbFunctionExpressions.BinaryLessThan(
Expression.Property(fooParam, nameof(Foo.Version)),
Expression.Constant(lastFoo.Version)),
fooParam));
笔记
不适用于 Entity Framework Core 1.0.0,但我在那里打开了一个问题以获得更全面的支持,而无需表达式。(EF Core 不起作用,因为它经历了一个阶段,它使用and参数复制LessThan
表达式,但不复制我们用于漏洞的参数。)left
right
MethodInfo