Я заменяю Dapper на EF Core в проекте. В частности, используя новые функции Database.SqlQuery и Database.ExecuteSql с EF Core. Мне нравится, как они используют FormattableString для обработки параметров SQL.
Однако я не понимаю, что делать, если я хочу использовать как интерполяцию строк, так и фигурные скобки для параметров с помощью FormattableStrings? Ниже приведен пример версии Dapper и нерабочей версии EF Core. Я бы не хотел, чтобы «subSql» передавался в качестве параметра, а просто создавал строку. Как бы я подошел к этому?
public IEnumerable<Something> GetSomethingWithDapper(string id, bool enabled, string type)
{
var subSql = switch (type) {
case "A":
"TableA";
break;
case "B":
"TableB";
break;
};
var sql = $"SELECT * FROM {subSql} WHERE Id = @id";
// My dapper request here
}
public IEnumerable<Something> GetSomethingWithEFCore(string id, string type)
{
var subSql = switch (type) {
case "A":
"TableA";
break;
case "B":
"TableB";
break;
};
FormattableString sql = $"SELECT * FROM {subSql} WHERE Id = {id}";
// My EF Core request here
}
Мы используем как Dapper, так и EF Core. Действуйте только тогда, когда нам нужно получить данные, которые не являются просто представлением моделей. Эти части я хотел бы заменить сейчас, поскольку EF Core поддерживает это.
Почему бы не добавить его в модель? И зачем отходить от Дэппера? Support
и Is Better
не одно и то же. Очевидно, вы отображаете всю таблицу, так почему же Something
не является частью модели?
Это ответ на ваш вопрос?: stackoverflow.com/a/50452479/25070013
@PekoMiko Нет, я вообще ничего не вижу в этом ответе о строгой интерполяции?
@PanagiotisKanavos Я полагаю, вы понимаете, что мой пример не является реальным случаем, а только отражает проблему с интерполяцией строк? Я не думаю, что вам нужно чрезмерно анализировать структуру модели в этом примере. Сегодня мы используем 90% EF Core и 10% Dapper. Мы просто хотели бы заменить последние 10%, которые у нас есть, на Dapper, поскольку раньше это было невозможно сделать в EF Core. Я большой поклонник Dapper, но хотел бы уменьшить количество необходимых пакетов. Я прекрасно осведомлен о сильных сторонах пакета, поэтому вам не придется меня убеждать :)
Вы изначально задаете неправильный вопрос. Вы пытаетесь использовать интерполяцию для двух разных целей: создания параметризованного запроса и построения строки запроса. Это просто не сработает. Вам придется создать строку "SELECT * FROM TableA WHERE Id = {id}"
, прежде чем создавать FormattableString, которая ожидает параметр id
.
@PanagiotisKanavos Отлично! Это именно то, о чем я прошу. Как мне следует это сделать! Как бы я это сделал?
Эквивалент Dapper в любом случае не использует форматируемые строки, это FromSqlRaw
. Вы можете написать FromSqlRaw(sql,id)
так же, как вы это сделали с Dapper. И я по-прежнему предпочитаю Dapper для этого, потому что, хотя Марк Гравелл сейчас работает в Microsoft, Dapper более зрелый, в то время как команда EF Core выпустила эту функцию всего пару лет назад. У Dapper уже есть версия, которая поддерживает встроенную компиляцию, а EF Core — нет.
Итак, реальный вопрос заключается в том, как избежать фигурных скобок при интерполяции строк?.... Используйте двойные фигурные скобки...
@Селвин, нет, это не так. В форматируемой строке нет экранированных параметров. Что-то является либо текстом, либо параметром. FromSql
рассматривает все параметры в форматируемой строке как параметры запроса. Нельзя сказать, что половина параметров должна использоваться для интерполяции строк, а половина — для параметров запроса.
Эквивалентом QueryAsync<Something>(sql,id)
Dapper является SqlQueryRaw, а не SqlQuery
или FromSql
. SqlQuery
и FromSql
будут обрабатывать все параметры в FormattableString как параметры запроса. Невозможно определить, что некоторые из этих параметров следует использовать для интерполяции строк, а некоторые — для других целей.
При использовании SqlQueryRaw эквивалентом con.Query<int>(sql,new {id})
Dapper является context.Database.SqlQueryRaw<int>(sql,new{id})
, например:
var id= new SqlParameter("id", 45);
var ids = context.Database
.SqlQueryRaw<int>("SELECT Id from TableX where id=@id",@id)
.ToList();
Или
var sql=$"SELECT Id from {table} where id=@id";
var ids = context.Database
.SqlQueryRaw<int>("SELECT Id from TableX where id=@id",id)
.ToList();
Это также показано в документации EF SQL-запрос , в разделе Динамический SQL и параметры:
Если вы решили, что хотите динамически создавать свой SQL, вам придется использовать FromSqlRaw, который позволяет интерполировать переменные данные непосредственно в строку SQL вместо использования параметра базы данных:
var columnName = "Url";
var columnValue = new SqlParameter("columnValue", "http://SomeURL");
var blogs = context.Blogs
.FromSqlRaw($"SELECT * FROM [Blogs] WHERE {columnName} = @columnValue", columnValue)
.ToList();
Если вы используете EF Core, почему вы вообще используете необработанный SQL? EF Core — это ORM, а не драйвер базы данных. Он пытается создать впечатление работы с объектами в памяти, а не с таблицами и строками. Задача EF — генерировать запросы на основе сущностей и их отношений, а не ваша. Вместо этого кода все, что вам действительно нужно, это
var customer=context.Customers.Find(id);
. А если вам нужны заказы клиента,var customer=context.Customers.Include(c=>c.Orders).Find(id);