简体   繁体   English

.NET Core 2中多个表的IDENTITY_INSERT

[英]IDENTITY_INSERT for multiple tables in .net core 2

I'm trying to migrate data from an existing database to a new one. 我正在尝试将数据从现有数据库迁移到新数据库。 The old database is very entangled, meaning most tables have relationships to many other tables based on foreign ids. 旧数据库非常纠结,这意味着大多数表都基于外部ID与许多其他表有关系。 I came across this solution for inserting ids: 我遇到了插入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);
    }
}

from this Microsoft guide: https://docs.microsoft.com/en-us/ef/core/saving/explicit-values-generated-properties 来自此Microsoft指南: https : //docs.microsoft.com/zh-cn/ef/core/saving/explicit-values-generation-properties

Is there a way to set IDENTITY_INSERT on multiple tables before applying context.SaveChanges(); 有没有一种方法可以在应用context.SaveChanges();之前在多个表上设置IDENTITY_INSERT context.SaveChanges(); ?

Nope. 不。 Look at the documentation of IDENTITY_INSERT. 查看IDENTITY_INSERT的文档。 https://docs.microsoft.com/en-us/sql/t-sql/statements/set-identity-insert-transact-sql https://docs.microsoft.com/zh-cn/sql/t-sql/statements/set-identity-insert-transact-sql

It clearly states: 它明确指出:

At any time, only one table in a session can have the IDENTITY_INSERT property set to ON. 任何时候,会话中只有一个表可以将IDENTITY_INSERT属性设置为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. 如果一个表的此属性已设置为ON,并且为另一个表发出了SET IDENTITY_INSERT ON语句,则SQL Server返回一条错误消息,指出SET IDENTITY_INSERT已经为ON,并报告其设置为ON的表。

I had the same Problem here while seeding data from an object tree stored in a json file. 从存储在json文件中的对象树中播种数据时,我在这里遇到了同样的问题。

Example: 例:

jsonData = System.IO.File.ReadAllText(@"Data\InputParameters.json");
var inputParameters = JsonConvert.DeserializeObject<List<ParameterCategory>> jsonData, settings);
context.AddRange(inputParameters);
context.SaveChanges();

After a look at the EFCore sources I came up with the following solution: 在查看了EFCore的源代码之后,我想出了以下解决方案:

1. Create a new class "SqlServerUpdateSqlGeneratorInsertIdentity" which is responsible for turning Identity_Insert on and off for each insert Operation: 1.创建一个新类“ 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. Replace the original "SqlServerUpdateSqlGenerator" by the inherited new one: 2.用继承的新的替换原来的“ SqlServerUpdateSqlGenerator”:

In Startup.cs - ConfigureServices use the following code: 在Startup.cs-ConfigureServices中,使用以下代码:

services.AddDbContext<YourDataContext>(options =>
{
    options.UseSqlServer(YourConnectionString);
    options.ReplaceService<ISqlServerUpdateSqlGenerator, SqlServerUpdateSqlGeneratorInsertIdentity>();
});

Or in YourDataContext.cs - OnConfiguring use this one (not tested): 在YourDataContext.cs-OnConfiguring中使用此选项(未经测试):

options.ReplaceService<ISqlServerUpdateSqlGenerator, SqlServerUpdateSqlGeneratorInsertIdentity>();

It may be necessary to reset the service configuration to it´s original after seeding. 播种后,可能有必要将服务配置重置为原始配置。 In my case it wasn´t. 就我而言,不是。

Hope that´ll help someone... 希望能帮助到某人...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 Entity Framework Core 中为多个表设置 SET IDENTITY_INSERT - Setting SET IDENTITY_INSERT for multiple tables in Entity Framework Core 当IDENTITY_INSERT设置为OFF时,无法在TABLE中为Identity列插入显式值; .NET Core 2.1 - Cannot insert explicit value for identity column in TABLE when IDENTITY_INSERT is set to OFF; .NET Core 2.1 如何在.net核心中插入具有自动递增字段的实体而又不弄乱SQL Server&#39;Identity_insert on&#39;? - How to insert an entity with autoincremented field in .net core without messing with SQL Server 'Identity_insert on'? .NET CORE MVC - IDENTITY_INSERT 在第二个值处设置为 OFF 错误 - .NET CORE MVC - IDENTITY_INSERT is set to OFF error at the second value SqlException:当 IDENTITY_INSERT 设置为 OFF ASP.NET Core 2.1 时,无法在表“类别”中插入标识列的显式值 - SqlException: Cannot insert explicit value for identity column in table 'Categories' when IDENTITY_INSERT is set to OFF ASP.NET Core 2.1 EF Core 无法保存 IDENTITY_INSERT 为 OFF 的实体 - EF Core failed to save entity with IDENTITY_INSERT is OFF 当 IDENTITY_INSERT 设置为 OFF 时,无法为标识列插入显式值。 (实体框架核心) - Cannot insert explicit value for identity column when IDENTITY_INSERT is set to OFF. (Entity Framework Core) identity_insert和同步问题 - identity_insert and synchronization issue Linq To Sql和identity_insert - Linq To Sql and identity_insert 实体框架7 IDENTITY_INSERT - Entity Framework 7 IDENTITY_INSERT
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM