Похоже, что выполнение raw SQL не является приоритетом для EF Core, поэтому до сих пор (EF Core 3.1) он предоставляет публично лишь несколько базовых c ограниченных методов. FromSql
требуется тип сущности или тип сущности без ключа , а ExecuteSqlRaw
/ ExecuteSqlInterpolated
- это "современный" мост к ADO. NET ExecuteNonQuery
, который возвращает затронутые строки.
Хорошо, что EF Core построен на основе сервисной архитектуры publi c, поэтому его можно использовать для добавления некоторых недостающих функций. Например, службы могут использоваться для создания так называемой IRelationalCommand , которая имеет все DbCommand
методы выполнения, в частности ExecuteScalar
, необходимые для SQL, о которых идет речь.
Так как Модель EF Core поддерживает последовательности, также есть сервис для создания IRelationalCommand
, необходимого для получения следующего значения (используется внутри генераторами значений HiLo).
С учетом сказанного ниже приведен пример реализации рассматриваемого пользовательского метода с использованием вышеупомянутых концепций:
using System;
using System.Globalization;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Update;
namespace Microsoft.EntityFrameworkCore
{
public static partial class CustomExtensions
{
public static long GetNextSequenceValue(this DbContext context, string name, string schema = null)
{
var sqlGenerator = context.GetService<IUpdateSqlGenerator>();
var sql = sqlGenerator.GenerateNextSequenceValueOperation(name, schema ?? context.Model.GetDefaultSchema());
var rawCommandBuilder = context.GetService<IRawSqlCommandBuilder>();
var command = rawCommandBuilder.Build(sql);
var connection = context.GetService<IRelationalConnection>();
var logger = context.GetService<IDiagnosticsLogger<DbLoggerCategory.Database.Command>>();
var parameters = new RelationalCommandParameterObject(connection, null, null, context, logger);
var result = command.ExecuteScalar(parameters);
return Convert.ToInt64(result, CultureInfo.InvariantCulture);
}
}
}