C# EF Core-在EF Core 3.1或5中,什么是MapToStoredProcess替换
EF Core中没有C# EF Core-在EF Core 3.1或5中,什么是MapToStoredProcess替换,c#,entity-framework-core,C#,Entity Framework Core,EF Core中没有MapToStoredProcess,这很遗憾,因为它允许Add方法隐藏是否使用存储过程 我已经看过EF Core 3.1和5,但找不到推荐的替代品。所以,如果我有下面的代码,我应该如何/在哪里设置并调用一个插入存储过程或针对它选择存储过程 public class DatabaseModel : DbContext { public virtual DbSet<Office> Offices { get; set; } public Datab
MapToStoredProcess
,这很遗憾,因为它允许Add
方法隐藏是否使用存储过程
我已经看过EF Core 3.1和5,但找不到推荐的替代品。所以,如果我有下面的代码,我应该如何/在哪里设置并调用一个插入存储过程或针对它选择存储过程
public class DatabaseModel : DbContext
{
public virtual DbSet<Office> Offices { get; set; }
public DatabaseModel(DbContextOptions<DatabaseModel> options) : base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder) {}
}
公共类数据库模型:DbContext
{
公共虚拟数据库集办公室{get;set;}
公共数据库模型(DbContextOptions):基本(选项)
{ }
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder){}
}
感谢您的帮助。EF CORE中不支持MapToStoredProcess。 您可以使用
FromSqlRaw
方法执行存储过程
var result = ctx.ParameterDetails.FromSqlRaw("EXEC dbo.get_nextparam @UserId={0}", userId).ToList();
注意:这目前没有实现SQL SERVER所做的批量插入,要使多个表使用相同的表名,您需要实现 您可以创建一个覆盖Microsoft.EntityFrameworkCore.Update.IUpdateSqlGenerator的实现,并在注册时对其执行
ReplaceService
。我已成功重写Sql Server中的插入操作
在我的例子中,直接调用存储过程不是一个选项,因为我正在尝试将一个项目从EF 6升级到EF Core,而只需进行最小的更改
正在注册DbContext:
services.AddDbContext((sp,选项)=>
{
选择权
.UseSqlServer(连接字符串)
.ReplaceService();
});
MapToProcedureUpdateSqlGenerator
使用Microsoft.EntityFrameworkCore.SqlServer.Update.Internal;
使用Microsoft.EntityFrameworkCore.Update;
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
命名空间efcoremaptostoredprocesses
{
//小心此实现,因为它会发出警告
//这是一个支持实体框架核心基础设施的内部API
//并且不受与公共API相同的兼容性标准的约束。
公共类MaptopProcedureUpdateSqlGenerator:SqlServerUpdateSqlGenerator
{
公共MapToProcedureUpdateSqlGenerator(更新SqlGeneratorDependencies依赖项):基础(依赖项)
{
}
公共覆盖结果映射AppendInsertOperation(StringBuilder命令StringBuilder,ModificationCommand命令,int命令位置)
{
如果(command==null)抛出新的ArgumentNullException(nameof(command));
如果(commandStringBuilder==null)抛出新的ArgumentNullException(nameof(commandStringBuilder));
if(_tableInsertProcs.TryGetValue(command.TableName,out字符串procName))
{
var name=command.TableName;
var schema=command.schema;
var operations=command.ColumnModifications;
var writeOperations=operations.Where(o=>o.IsWrite.ToList();
AppendExecCommandHeader(commandStringBuilder、procName、schema、writeOperations);
if(operations.Any(=>u.IsRead))
{
返回resultsMapping.LastInResultSet;
}
返回resultsMapping.NoResultSet;
}
其他的
{
返回base.AppendInsertOperation(commandStringBuilder、command、commandPosition);
}
}
///
///附加用于执行存储过程的SQL片段
///
///SQL应附加到的生成器。
///过程的名称。
///表架构,或使用默认架构。
///表示要插入的数据的操作。
受保护的虚拟空AppendExecCommandHeader(
StringBuilder命令StringBuilder,
字符串名,
字符串模式,
IReadOnlyList操作)
{
如果(commandStringBuilder==null)抛出新的ArgumentNullException(nameof(commandStringBuilder));
if(string.IsNullOrWhiteSpace(name))抛出新的ArgumentException(“必需”,nameof(name));
如果(operations==null)抛出新的ArgumentNullException(nameof(operations));
commandStringBuilder.Append(“EXEC”);
标识符(commandStringBuilder、名称、架构);
如果(operations.Count>0)
{
commandStringBuilder
.AppendJoin(
操作,
(此项、名称、模式),
(sb,o,p)=>
{
if(o.IsWrite)
{
var(g,n,s)=p;
如果(!o.UseCurrentValueParameter)
{
抛出新的NotSupportedException(“不支持的文本”);
}
其他的
{
g、 GenerateParameterNamePlaceholder(sb,o.ColumnName);
commandStringBuilder.Append(“”);
g、 GenerateParameterNamePlaceholder(sb,o.ParameterName);
}
}
其他的
{
某人追加(“违约”);
}
});
commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator);
}
}
//todo使用依赖项进行配置
私人阅读
services.AddDbContext<ExampleDbContext>((sp, options) =>
{
options
.UseSqlServer(connectionString)
.ReplaceService<IUpdateSqlGenerator, MapToProcedureUpdateSqlGenerator>();
});
using Microsoft.EntityFrameworkCore.SqlServer.Update.Internal;
using Microsoft.EntityFrameworkCore.Update;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace EFCoreMapToStoredProcedures
{
// careful with this implementation as it gives warning
// This is an internal API that supports the Entity Framework Core infrastructure
// and not subject to the same compatibility standards as public APIs.
public class MapToProcedureUpdateSqlGenerator : SqlServerUpdateSqlGenerator
{
public MapToProcedureUpdateSqlGenerator(UpdateSqlGeneratorDependencies dependencies) : base(dependencies)
{
}
public override ResultSetMapping AppendInsertOperation(StringBuilder commandStringBuilder, ModificationCommand command, int commandPosition)
{
if (command == null) throw new ArgumentNullException(nameof(command));
if (commandStringBuilder == null) throw new ArgumentNullException(nameof(commandStringBuilder));
if (_tableInsertProcs.TryGetValue(command.TableName, out string procName))
{
var name = command.TableName;
var schema = command.Schema;
var operations = command.ColumnModifications;
var writeOperations = operations.Where(o => o.IsWrite).ToList();
AppendExecCommandHeader(commandStringBuilder, procName, schema, writeOperations);
if (operations.Any(_ => _.IsRead))
{
return ResultSetMapping.LastInResultSet;
}
return ResultSetMapping.NoResultSet;
}
else
{
return base.AppendInsertOperation(commandStringBuilder, command, commandPosition);
}
}
/// <summary>
/// Appends a SQL fragment for excuting a stored procedure
/// </summary>
/// <param name="commandStringBuilder"> The builder to which the SQL should be appended. </param>
/// <param name="name"> The name of the procedure. </param>
/// <param name="schema"> The table schema, or <see langword="null" /> to use the default schema. </param>
/// <param name="operations"> The operations representing the data to be inserted. </param>
protected virtual void AppendExecCommandHeader(
StringBuilder commandStringBuilder,
string name,
string schema,
IReadOnlyList<ColumnModification> operations)
{
if (commandStringBuilder == null) throw new ArgumentNullException(nameof(commandStringBuilder));
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("required", nameof(name));
if (operations == null) throw new ArgumentNullException(nameof(operations));
commandStringBuilder.Append("EXEC ");
SqlGenerationHelper.DelimitIdentifier(commandStringBuilder, name, schema);
if (operations.Count > 0)
{
commandStringBuilder
.AppendJoin(
operations,
(this, name, schema),
(sb, o, p) =>
{
if (o.IsWrite)
{
var (g, n, s) = p;
if (!o.UseCurrentValueParameter)
{
throw new NotSupportedException("literals not supported");
}
else
{
g.SqlGenerationHelper.GenerateParameterNamePlaceholder(sb, o.ColumnName);
commandStringBuilder.Append(" = ");
g.SqlGenerationHelper.GenerateParameterNamePlaceholder(sb, o.ParameterName);
}
}
else
{
sb.Append("DEFAULT");
}
});
commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator);
}
}
// todo make configurable with dependencies
private readonly Dictionary<string, string> _tableInsertProcs = new Dictionary<string, string>()
{
["OrderItems"] = "InsertOrderItem"
};
}
}