Расширение пользовательского запроса, работающее с NHibernate.C#

Место общения программистов C#
Anonymous
Расширение пользовательского запроса, работающее с NHibernate.

Сообщение Anonymous »

Я пытаюсь написать собственное расширение Linq, которое также можно выполнить в базе данных.
По сути, я хочу сделать это CollectionOfStrings.Where(x => !x .IsNullOrWhiteSpace) К сожалению, он не поддерживается.
=============== Что я пробовал ===== ========
Эта часть интересна только тем, у кого может возникнуть другая идея, отличная от приведенной ниже.
Есть обходной путь: Collection.Where(x => x != null && x.Trim() != string.Empty), но поскольку я использую его часто, это не лучшее решение.
Самым красивым решением было бы найти способ написать строковое расширение IsNullOrWhiteSpaceDB, которое работает, или как бы добавить метод IsNullOrWhiteSpace в базу данных программным способом. чтобы обеспечить поддержку.
Это была моя попытка создать работающий метод IsNullOrWhiteSpace, но он тоже не поддерживается:

Код: Выделить всё

public static bool IsNullOrWhiteSpaceDB(this string? str) =>
str == null || str.Trim() == String.Empty;
Итак, я начал писать предикат, и он работает нормально:

Код: Выделить всё

    public IQueryable GetAll() =>
GetAll().Select(x => x.property).Where(StringIsNotNullOrWhiteSpace).Distinct();

private static Expression StringIsNotNullOrWhiteSpace =>
x => x != null && x.Trim() != string.Empty;
=============== Текущая проблема =============
Тем не менее, мне бы хотелось иметь возможность запускать его с другой коллекцией, а не с коллекцией строк. Поэтому я попытался создать собственное расширение linq (вдохновленное этим решением (https://stackoverflow.com/a/40924558/9487478)):

Код: Выделить всё

public class QueryVisitor : ExpressionVisitor
{
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.IsStatic && node.Method.Name == "IsNullOrWhiteSpace")
{
//!(b.Diameter == null || b.Diameter.Trim() == string.Empty)
var arg = node.Arguments[0];
var argTrim = Expression.Call(arg, typeof(string).GetMethod("Trim", Type.EmptyTypes));

var exp = Expression.MakeBinary(ExpressionType.Or,
Expression.MakeBinary(ExpressionType.Equal, arg, Expression.Constant(null, arg.Type)),
Expression.MakeBinary(ExpressionType.Equal, argTrim, Expression.Constant(string.Empty, arg.Type))
);

return exp;
}

return base.VisitMethodCall(node);
}
}

public static class EfQueryableExtensions
{
public static IQueryable WhereEx(this IQueryable queryable, Expression where)
{
var visitor = new QueryVisitor();
return queryable.Where(visitor.VisitAndConvert(where, "WhereEx"));
}
}
А вот как на самом деле выглядит мое пользовательское расширение:

Код: Выделить всё

public static class QueryHelper
{
public static IQueryable WhereIsNotNullOrWhiteSpace(this IQueryable query, Expression expression)
{
var arg = expression.Body;
var argTrim = Expression.Call(arg, typeof(string).GetMethod("Trim", Type.EmptyTypes));

var exp = Expression.MakeBinary(ExpressionType.And,
Expression.MakeBinary(ExpressionType.NotEqual, arg, Expression.Constant(null, arg.Type)),
Expression.MakeBinary(ExpressionType.NotEqual, argTrim, Expression.Constant(string.Empty, arg.Type))
);

var lambda = Expression.Lambda(exp, expression.Parameters);
var result = query.Where(lambda);

return result;
}
}
После выполнения запроса.Where(lambda) в результате возникает внутреннее исключение:

Код: Выделить всё

NHibernate.Hql.Ast.ANTLR.QuerySyntaxException: A recognition error occurred.
"Исходная версия" тоже выдает ту же ошибку, поэтому я подумал, что это может быть созданное выражение ((x == null) или (x.Trim() == "") ) (скопировано из отладчика). На мой взгляд, это выглядит довольно хорошо, и я не понимаю причину ошибки.
Есть идеи? Мне будет приятно!

Подробнее здесь: https://stackoverflow.com/questions/647 ... nhibernate

Вернуться в «C#»