Как выполнить SqlQuery с Entity Framework Core 2.1? - PullRequest
0 голосов
/ 18 мая 2018

В Entity Framework 6 я могу выполнить необработанный SQL-запрос к базе данных, используя следующую команду:

IEnumerable<string> Contact.Database.SqlQuery<string>("SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10");

В новом проекте я пытаюсь использовать Entity Framework Core 2.1.У меня есть необходимость выполнить сырой запрос SQL.При поиске я вижу, что расширение SqlQuery было изменено на FromSql.Однако FromSql существует только на DbSet<>, а не на DbContext.Database.

Как я могу запустить FromSql за пределами DbSet<>?Метод FromSql не существует в объекте базы данных DbContext.Database.FromSql<>.

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Я вижу, что расширение SqlQuery было изменено на FromSql

Но новый метод FromSql более рестриктивен, чем SqlQuery.Документация этого метода объясняет, что существуют некоторые ограничения, такие как:

Запросы SQL могут использоваться только для возврата типов сущностей, которые являются частью вашей модели..В нашем бэклоге есть усовершенствование , позволяющее возвращать специальные типы из необработанных запросов SQL .

Запрос SQL должен возвращать данные для всех свойств объекта илитип запроса .

[...]

Итак, в вашем случае используется следующий SQL-запрос:

SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10

Как сказано в документации, вы можете использовать FromSql только с сущностью или типом запроса .Ваш запрос SQL не возвращает все данные вашей сущности, определенные в вашей модели, но возвращает только один столбец вашей сущности.Между прочим, в EF Core 2.1 появилась новая функция, которая находится в версии-кандидате с 7 мая 2018 года. Microsoft заявляет:

EF Core 2.1 RC1 - это версия, готовая к работе, что означает, что как только выпроверьте, правильно ли ваше приложение работает с RC1, вы можете использовать его в рабочей среде и получить поддержку от Microsoft, но вам все равно следует обновить его до окончательного стабильного выпуска, как только он станет доступным.

Использование FromSql для типа запроса

Что такое тип запроса :

Модель EF Core теперь может включать типы запросов.В отличие от типов сущностей, типы запросов не имеют определенных ключей и не могут быть вставлены, удалены или обновлены (т.е. они доступны только для чтения), но они могут быть возвращены непосредственно запросами.Некоторые из сценариев использования для типов запросов: сопоставление с представлениями без первичных ключей, сопоставление с таблицами без первичных ключей, сопоставление с запросами, определенными в модели, использование в качестве типа возврата для запросов FromSql ()

Если вы хотите использовать функцию типа запроса в тексте SQL, сначала определите класс, назовем его MySuperClass:

public class MySuperClass
{
    public string Title { get; set; }
}

Затем в вашем классе DbContext определите свойство типа DbQuery<MySuperClass>как показано ниже:

public DbQuery<MySuperClass> MySuperQuery { get; set; }

Наконец, вы можете использовать FromSql на нем, как показано ниже:

var result = context.MySuperQuery.FromSql("SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10").ToList().First();
var title = result.Title;

Не хотите использовать DbQuery<T>

Если выне хотите использовать DbQuery<T> и не хотите определять класс, который содержит только одно свойство, тогда вы можете использовать ExecuteSqlCommandAsync, как @ vivek nuna в своем ответе (его ответ частично правильный).Но вы должны знать, что возвращаемое значение этого метода - это количество строк, затронутых вашим запросом.Также вы должны поместить свой заголовок в качестве выходного параметра, чтобы сделать ваш запрос хранимой процедурой.Используйте ExecuteSqlCommandAsync или ExecuteSqlCommand и после этого прочитайте выходной параметр, который вы передали при вызове метода.

Более простой способ без создания хранимой процедуры, поэтому без использования ExecuteSqlCommandAsync или ExecuteSqlCommand, заключается в следующемcode:

using (var context = new MyDbContext())
{
    var conn = context.Database.GetDbConnection();
    await conn.OpenAsync();
    var command = conn.CreateCommand();
    const string query = "SELECT a.title FROM a JOIN b ON b.Id = a.aId WHERE b.Status = 10";
    command.CommandText = query;
    var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        var title = reader.GetString(0);
        // Do whatever you want with title 
    }
}  

Вы можете сделать эту логику вспомогательным методом, который получит ваш SQL-запрос и вернет нужные данные.Но я рекомендую вам использовать Dapper.Net , который содержит множество вспомогательных методов, которые помогут легко справляться с RAW SQL, как мы делали выше, а также делиться соединением smae с DbContext.

0 голосов
/ 18 мая 2018

Вы можете использовать метод ExecuteSqlCommandAsync, который определен в RelationalDatabaseFacadeExtensions классе Microsoft.EntityFrameworkCore.Relational сборки следующим образом.

_databaseContext.Database.ExecuteSqlCommandAsync(<Your parameters>)
...