IDENTITY_INSERT 对于 .net core 2 中的多个表
IDENTITY_INSERT for multiple tables in .net core 2
我正在尝试将数据从现有数据库迁移到新数据库。旧数据库非常复杂,这意味着大多数表都与基于外部 ID 的许多其他表有关系。我遇到了这个用于插入 ID 的解决方案:
using (var context = new EmployeeContext())
{
context.Employees.Add(new Employee { EmployeeId = 100, Name = "John Doe" });
context.Employees.Add(new Employee { EmployeeId = 101, Name = "Jane Doe" });
context.Database.OpenConnection();
try
{
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employees ON");
context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employees OFF");
}
finally
{
context.Database.CloseConnection();
}
foreach (var employee in context.Employees)
{
Console.WriteLine(employee.EmployeeId + ": " + employee.Name);
}
}
来自此 Microsoft 指南:https://docs.microsoft.com/en-us/ef/core/saving/explicit-values-generated-properties
有没有办法在应用 context.SaveChanges();
之前在多个表上设置 IDENTITY_INSERT
?
没有。查看 IDENTITY_INSERT 的文档。 https://docs.microsoft.com/en-us/sql/t-sql/statements/set-identity-insert-transact-sql
它明确指出:
At any time, only one table in a session can have the IDENTITY_INSERT
property set to ON. If a table already has this property set to ON,
and a SET IDENTITY_INSERT ON statement is issued for another table,
SQL Server returns an error message that states SET IDENTITY_INSERT is
already ON and reports the table it is set ON for.
我在从存储在 json 文件中的对象树中播种数据时遇到了同样的问题。
示例:
jsonData = System.IO.File.ReadAllText(@"Data\InputParameters.json");
var inputParameters = JsonConvert.DeserializeObject<List<ParameterCategory>> jsonData, settings);
context.AddRange(inputParameters);
context.SaveChanges();
查看 EFCore 资源后,我想到了以下解决方案:
1.创建一个新的class"SqlServerUpdateSqlGeneratorInsertIdentity"负责为每个插入操作打开和关闭Identity_Insert:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore.SqlServer.Update.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Update;
/// <summary>
/// SqlServerUpdateSqlGenerator with Insert_Identity.
/// </summary>
public class SqlServerUpdateSqlGeneratorInsertIdentity : SqlServerUpdateSqlGenerator
{
/// <summary>
/// Initializes a new instance of the <see cref="SqlServerUpdateSqlGeneratorInsertIdentity"/> class.
/// </summary>
/// <param name="dependencies">The dependencies.</param>
public SqlServerUpdateSqlGeneratorInsertIdentity(UpdateSqlGeneratorDependencies dependencies)
: base(dependencies)
{
}
/// <inheritdoc/>
public override ResultSetMapping AppendBulkInsertOperation(
StringBuilder commandStringBuilder,
IReadOnlyList<ModificationCommand> modificationCommands,
int commandPosition)
{
var columns = modificationCommands[0].ColumnModifications.Where(o => o.IsWrite).Select(o => o.ColumnName)
.ToList();
var schema = modificationCommands[0].Schema;
var table = modificationCommands[0].TableName;
GenerateIdentityInsert(commandStringBuilder, table, schema, columns, on: true);
var result = base.AppendBulkInsertOperation(commandStringBuilder, modificationCommands, commandPosition);
GenerateIdentityInsert(commandStringBuilder, table, schema, columns, on: false);
return result;
}
private void GenerateIdentityInsert(
StringBuilder builder,
string table,
string schema,
IEnumerable<string> columns,
bool on)
{
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
builder.Append("IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE").Append(" [name] IN (")
.Append(string.Join(", ", columns.Select(stringTypeMapping.GenerateSqlLiteral)))
.Append(") AND [object_id] = OBJECT_ID(").Append(
stringTypeMapping.GenerateSqlLiteral(
Dependencies.SqlGenerationHelper.DelimitIdentifier(table, schema))).AppendLine("))");
builder.Append("SET IDENTITY_INSERT ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(table, schema)).Append(on ? " ON" : " OFF")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
}
}
2.用继承的新的"SqlServerUpdateSqlGenerator"替换原来的"SqlServerUpdateSqlGenerator":
在 Startup.cs - ConfigureServices 中使用以下代码:
services.AddDbContext<YourDataContext>(options =>
{
options.UseSqlServer(YourConnectionString);
options.ReplaceService<ISqlServerUpdateSqlGenerator, SqlServerUpdateSqlGeneratorInsertIdentity>();
});
或 in YourDataContext.cs - OnConfiguring 使用这个(未测试):
options.ReplaceService<ISqlServerUpdateSqlGenerator, SqlServerUpdateSqlGeneratorInsertIdentity>();
播种后可能需要将服务配置重置为原始配置。就我而言,它不是。
希望对某人有所帮助...
我正在尝试将数据从现有数据库迁移到新数据库。旧数据库非常复杂,这意味着大多数表都与基于外部 ID 的许多其他表有关系。我遇到了这个用于插入 ID 的解决方案:
using (var context = new EmployeeContext())
{
context.Employees.Add(new Employee { EmployeeId = 100, Name = "John Doe" });
context.Employees.Add(new Employee { EmployeeId = 101, Name = "Jane Doe" });
context.Database.OpenConnection();
try
{
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employees ON");
context.SaveChanges();
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT dbo.Employees OFF");
}
finally
{
context.Database.CloseConnection();
}
foreach (var employee in context.Employees)
{
Console.WriteLine(employee.EmployeeId + ": " + employee.Name);
}
}
来自此 Microsoft 指南:https://docs.microsoft.com/en-us/ef/core/saving/explicit-values-generated-properties
有没有办法在应用 context.SaveChanges();
之前在多个表上设置 IDENTITY_INSERT
?
没有。查看 IDENTITY_INSERT 的文档。 https://docs.microsoft.com/en-us/sql/t-sql/statements/set-identity-insert-transact-sql
它明确指出:
At any time, only one table in a session can have the IDENTITY_INSERT property set to ON. If a table already has this property set to ON, and a SET IDENTITY_INSERT ON statement is issued for another table, SQL Server returns an error message that states SET IDENTITY_INSERT is already ON and reports the table it is set ON for.
我在从存储在 json 文件中的对象树中播种数据时遇到了同样的问题。
示例:
jsonData = System.IO.File.ReadAllText(@"Data\InputParameters.json");
var inputParameters = JsonConvert.DeserializeObject<List<ParameterCategory>> jsonData, settings);
context.AddRange(inputParameters);
context.SaveChanges();
查看 EFCore 资源后,我想到了以下解决方案:
1.创建一个新的class"SqlServerUpdateSqlGeneratorInsertIdentity"负责为每个插入操作打开和关闭Identity_Insert:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore.SqlServer.Update.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Update;
/// <summary>
/// SqlServerUpdateSqlGenerator with Insert_Identity.
/// </summary>
public class SqlServerUpdateSqlGeneratorInsertIdentity : SqlServerUpdateSqlGenerator
{
/// <summary>
/// Initializes a new instance of the <see cref="SqlServerUpdateSqlGeneratorInsertIdentity"/> class.
/// </summary>
/// <param name="dependencies">The dependencies.</param>
public SqlServerUpdateSqlGeneratorInsertIdentity(UpdateSqlGeneratorDependencies dependencies)
: base(dependencies)
{
}
/// <inheritdoc/>
public override ResultSetMapping AppendBulkInsertOperation(
StringBuilder commandStringBuilder,
IReadOnlyList<ModificationCommand> modificationCommands,
int commandPosition)
{
var columns = modificationCommands[0].ColumnModifications.Where(o => o.IsWrite).Select(o => o.ColumnName)
.ToList();
var schema = modificationCommands[0].Schema;
var table = modificationCommands[0].TableName;
GenerateIdentityInsert(commandStringBuilder, table, schema, columns, on: true);
var result = base.AppendBulkInsertOperation(commandStringBuilder, modificationCommands, commandPosition);
GenerateIdentityInsert(commandStringBuilder, table, schema, columns, on: false);
return result;
}
private void GenerateIdentityInsert(
StringBuilder builder,
string table,
string schema,
IEnumerable<string> columns,
bool on)
{
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
builder.Append("IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE").Append(" [name] IN (")
.Append(string.Join(", ", columns.Select(stringTypeMapping.GenerateSqlLiteral)))
.Append(") AND [object_id] = OBJECT_ID(").Append(
stringTypeMapping.GenerateSqlLiteral(
Dependencies.SqlGenerationHelper.DelimitIdentifier(table, schema))).AppendLine("))");
builder.Append("SET IDENTITY_INSERT ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(table, schema)).Append(on ? " ON" : " OFF")
.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
}
}
2.用继承的新的"SqlServerUpdateSqlGenerator"替换原来的"SqlServerUpdateSqlGenerator":
在 Startup.cs - ConfigureServices 中使用以下代码:
services.AddDbContext<YourDataContext>(options =>
{
options.UseSqlServer(YourConnectionString);
options.ReplaceService<ISqlServerUpdateSqlGenerator, SqlServerUpdateSqlGeneratorInsertIdentity>();
});
或 in YourDataContext.cs - OnConfiguring 使用这个(未测试):
options.ReplaceService<ISqlServerUpdateSqlGenerator, SqlServerUpdateSqlGeneratorInsertIdentity>();
播种后可能需要将服务配置重置为原始配置。就我而言,它不是。
希望对某人有所帮助...