注意:当前尚未实现SQL Server的批量插入,如果要使用相同的表名进行多个操作,您需要实现AppendBulkInsertOperation。
您可以创建一个实现,覆盖Microsoft.EntityFrameworkCore.Update.IUpdateSqlGenerator
并在注册时进行ReplaceService
。我已经成功地重写了Sql Server中的插入操作。
在我的情况下,直接调用存储过程不是一个选项,因为我正在尝试将项目从EF 6升级到具有更少更改的EF Core。
注册DbContext:
services.AddDbContext<ExampleDbContext>((sp, options) =>
{
options
.UseSqlServer(connectionString)
.ReplaceService<IUpdateSqlGenerator, MapToProcedureUpdateSqlGenerator>();
});
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
{
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);
}
}
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);
}
}
private readonly Dictionary<string, string> _tableInsertProcs = new Dictionary<string, string>()
{
["OrderItems"] = "InsertOrderItem"
};
}
}