Comments 18
Ого, наконец-то годная статейка.
Надо полагать, автор заодно захочет похвастаться знанием, как переопределить штатный QueryProvider у старого доброго Linq-2-Sql? Чтобы это добро все у меня заработало из коробки.
штатный провайдер просто не умеет конвертировать вызовы к Format в нужную форму для обращения к БД
он в принципе не умеет работать с string.Format. а это именно то, во что разворачивается интерполирование.
Но тут есть проблемы:
1) Не весь LINQ будет транслирован в Expression Tree, например такой не будет:
context.Select(x = > {
if(x.Age < 18)
return "Underage";
else
return "Adult";
}
2) LINQ который удастся транслировать в Expression Tree, может быть не транслируем в SQL, в таких случаях EF Core 2.1 сделает запрос к базе данных с тем SQL запросом, который смог транслировать, а остальное обработает в памяти, но это поведение можно переопределить и он станет падать каждый раз, когда не может полностью разобрать Expression Tree.
Кстати ReSharper выделяет самые очевидные «проблемные» места запроса.
x => x != ""
Серьёзно?
а как же
string.IsNullOrEmpty(x)
?
Ваше решение подвержено проблеме с методом Include:
_context.Humans
.Select(x => $"Name: {x.Name} Age: {x.Age}")
.Include(x => x.Foo) // Теперь выражение, переданное в Select, спрятано внутри константы
.ReWrite() // И ReWrite его не видит
При этом решение этой проблемы осложнено тем, что каждый DbSet в EF — это ConstantExpression ссылающийся сам на себя. Решается эта проблема как-то так:
private readonly HashSet<IQueryable> visiting = new HashSet<IQueryable>();
protected override Expression VisitConstant(ConstantExpression node)
{
var value = node.Value as IQueryable;
if (value == null) return node;
if (!visiting.Add(value)) return node;
try
{
var expr = value.Expression;
var newExpr = Visit(expr);
if (expr == newExpr) return node;
var newValue = value.Provider.CreateQuery(newExpr);
return Expression.Constant(newValue, node.Type);
}
finally
{
visiting.Remove(value);
}
}
Позанудствую… не помешала бы пара строк в начале, о том для кого статья и что мы из нее узнаем. Да, есть теги, и секунд за 20 понимаешь, что это про C#, которого ты в глаза никогда не видел, но все же..
string human = _context.Humans
.Select(x => $"Name: {x.Name} Age: {x.Age}")
.ReWrite()
.First();
в полученной строке присутствуют лишние кавычки " в начале строки.
Помогаем Queryable Provider разобраться с интерполированными строками