Найден обходной путь, который отлично работает!Протестировано на Entity Framework 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));
Примечания
Не работает на EntityFramework Core 1.0.0, но я открыл там проблему для более полной поддержки без выражений в любом случае.(EF Core не работает, поскольку проходит этап, на котором копирует выражение LessThan
с параметрами left
и right
, но не копирует параметр MethodInfo
, который мы используем для лазейки.)