mar*_*c_s 4 sql-server sequence entity-framework-core ef-core-3.1
我正在编写一个新的 ASP.NET Core Web API,我的要求之一是能够利用 EF Core 3.1 获取SQL Server 中定义的序列的下一个值作为我需要存储的记录的 ID .
我正在努力寻找一种方法来做到这一点 - 在 EF 6.x 中,我直接在DbContext后代上使用了一种方法,如下所示:
public int GetNextSequenceValue()
{
var rawQuery = Database.SqlQuery<int>("SELECT NEXT VALUE FOR dbo.TestSequence;");
var task = rawQuery.SingleAsync();
int nextVal = task.Result;
return nextVal;
}
Run Code Online (Sandbox Code Playgroud)
对于高达 2.1 的 EF Core,我本来可以Database.ExecuteSqlCommand()用来运行 SQL 代码段并返回结果。但似乎在 EF Core 3.x 中,我不走运....
我知道有.FromSqlRaw()和.FromSqlInterpolated方法DbSet- 但因为我只需要返回序列的下一个值 (an INT),这不会飞。而且我也知道这些方法也存在于context.Database看起来非常接近我在 EF 6.x 中的级别 - 但在这里,这些方法只会返回受影响的行数 - 我还没有找到方法从 中发回新值SEQUENCE。
难道真的是在 EF Core 3.x 中,我必须真正求助于古老的 ADO.NET 代码来获取该值??有没有真的没有办法来执行任意SQL代码片段,并取回从上下文一些成果?
如果你想运行一个任意的 TSQL 批处理并返回一个标量值,你可以这样做:
var p = new SqlParameter("@result", System.Data.SqlDbType.Int);
p.Direction = System.Data.ParameterDirection.Output;
context.Database.ExecuteSqlRaw("set @result = next value for some_seq", p);
var nextVal = (int)p.Value;
Run Code Online (Sandbox Code Playgroud)
小智 7
在流畅的 api 配置中,您可以创建迁移,将 ID 自动设置为序列中的下一个值
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("OrderNumbers");
modelBuilder.Entity<Order>()
.Property(o => o.OrderNo)
.HasDefaultValueSql("NEXT VALUE FOR shared.OrderNumbers");
}
Run Code Online (Sandbox Code Playgroud)
用于创建序列:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("OrderNumbers", schema: "shared")
.StartsAt(1000)
.IncrementsBy(5);
}
Run Code Online (Sandbox Code Playgroud)
从这里阅读更多信息:https://www.talkingdotnet.com/use-sql-server-sequence-in-entity-framework-core-primary-key/
看起来执行原始 SQL 不是 EF Core 的优先级,所以到目前为止(EF Core 3.1)它只公开提供了一些基本的有限方法。FromSql需要实体类型或无键实体类型,和ExecuteSqlRaw/ExecuteSqlInterpolated是ExecuteNonQuery返回受影响行的ADO.NET 的“现代”桥梁。
好消息是 EF Core 构建在公共服务架构之上,因此可用于添加一些缺失的功能。例如,服务可用于构建所谓的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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5528 次 |
| 最近记录: |