Изменение типа данных в модели при сохранении данных (Entity Framework Core) - PullRequest
0 голосов
/ 21 октября 2018

Я изучаю ядро ​​Entity Framework и хочу выполнить миграцию, изменив тип данных на пользовательский, сохранив при этом данные.У меня есть следующая модель:

public class PageDataSections
{
    [Key]
    public int PageDataSectionId { get; set; }
    public string DataText { get; set; }
}

, которая преобразуется в эту:

public class PageDataSections
{
    [Key]
    public int PageDataSectionId { get; set; }
    public Translation DataText { get; set; }
}

В то время как класс Translation следующий:

public class Translation
{
    [Key]
    public int TranslationId { get; set; }
    public string TranslateEN { get; set; }
    public string TranslateRU { get; set; }
    public string TranslateUA { get; set; }
}

Созданная миграция:

public partial class ChangeDataTextColumn : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {

            migrationBuilder.AddColumn<int>(
                name: "DataTextTranslationId",
                table: "PageDataSections",
                nullable: true);

            migrationBuilder.DropColumn(
                name: "DataText",
                table: "PageDataSections");      

            migrationBuilder.CreateIndex(
                name: "IX_PageDataSections_DataTextTranslationId",
                table: "PageDataSections",
                column: "DataTextTranslationId");

            migrationBuilder.AddForeignKey(
                name: "FK_PageDataSections_Translations_DataTextTranslationId",
                table: "PageDataSections",
                column: "DataTextTranslationId",
                principalTable: "Translations",
                principalColumn: "TranslationId",
                onDelete: ReferentialAction.Restrict);

            migrationBuilder.Sql(@"
            INSERT INTO Translations(TranslateRU)
            OUTPUT inserted.TranslationId
            VALUES(SELECT DataText FROM PageDataSections)
            INTO PageDataSections(DataTextTranslationId)
");
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropForeignKey(
                name: "FK_PageDataSections_Translations_DataTextTranslationId",
                table: "PageDataSections");

            migrationBuilder.DropIndex(
                name: "IX_PageDataSections_DataTextTranslationId",
                table: "PageDataSections");

            migrationBuilder.DropColumn(
                name: "DataTextTranslationId",
                table: "PageDataSections");

            migrationBuilder.AddColumn<string>(
                name: "DataText",
                table: "PageDataSections",
                nullable: true);
        }
    }

Но Visual Studio жалуется на эту одну ошибку:

fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
      Failed executing DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

                  INSERT INTO Translations(TranslateRU)
                  OUTPUT inserted.TranslationId
                  VALUES(SELECT DataText FROM PageDataSections)
                  INTO PageDataSections(DataTextTranslationId)
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near the keyword 'SELECT'.
Incorrect syntax near ')'.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
ClientConnectionId:14012b7c-68b2-4f43-9db1-b685734a2e37
Error Number:156,State:1,Class:15
Failed executing DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

            INSERT INTO Translations(TranslateRU)
            OUTPUT inserted.TranslationId
            VALUES(SELECT DataText FROM PageDataSections)
            INTO PageDataSections(DataTextTranslationId)
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near the keyword 'SELECT'.
Incorrect syntax near ')'.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:14012b7c-68b2-4f43-9db1-b685734a2e37
Error Number:156,State:1,Class:15
Incorrect syntax near the keyword 'SELECT'.
Incorrect syntax near ')'.

Может кто-нибудь помочь, пожалуйста?

РЕДАКТИРОВАТЬ

После ответа @Fabio я попробовал его код

migrationBuilder.Sql(@"
    INSERT Translations (TranslateRU)
    OUTPUT inserted.TranslationId INTO PageDataSections(DataTextTranslationId)
    (SELECT DataText FROM PageDataSections) 
");

, и он дал мне следующее:

fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
      Failed executing DbCommand (231ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

      INSERT Translations (TranslateRU)
          OUTPUT inserted.TranslationId INTO PageDataSections(DataTextTranslationId)
          (SELECT DataText FROM PageDataSections)
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'DataText'.
The target table 'PageDataSections' of the OUTPUT INTO clause cannot be on either side of a (primary key, foreign key) relationship. Found reference constraint 'FK_PageDataSections_Translations_DataTextTranslationId'.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
ClientConnectionId:3224c672-8dbd-4690-8953-ee6108b65cff
Error Number:207,State:1,Class:16
Failed executing DbCommand (231ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

INSERT Translations (TranslateRU)
    OUTPUT inserted.TranslationId INTO PageDataSections(DataTextTranslationId)
    (SELECT DataText FROM PageDataSections)
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'DataText'.
The target table 'PageDataSections' of the OUTPUT INTO clause cannot be on either side of a (primary key, foreign key) relationship. Found reference constraint 'FK_PageDataSections_Translations_DataTextTranslationId'.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
ClientConnectionId:3224c672-8dbd-4690-8953-ee6108b65cff
Error Number:207,State:1,Class:16
Invalid column name 'DataText'.
The target table 'PageDataSections' of the OUTPUT INTO clause cannot be on either side of a (primary key, foreign key) relationship. Found reference constraint 'FK_PageDataSections_Translations_DataTextTranslationId'.

Что кажется довольно странным, потому чтов таблице существует столбец: Database

ОБНОВЛЕНИЕ

Это способ обращения к внешнему ключу enter image description here

ОБНОВЛЕНИЕ С помощью этих запросов я добился некоторого результата, но он не изменяет строки, а скорее добавляет .. Как "обновить", а не "вставить"?

            migrationBuilder.Sql(@"ALTER TABLE Pages DROP CONSTRAINT FK_Pages_PageDataSections_PageDataSectionId");

            migrationBuilder.Sql(@"
                INSERT Translations (TranslateRU)
                OUTPUT inserted.TranslationId INTO PageDataSections(DataTextTranslationId)
                SELECT DataText FROM PageDataSections;
");


            migrationBuilder.Sql(@"ALTER TABLE Pages ADD CONSTRAINT FK_Pages_PageDataSections_PageDataSectionId FOREIGN KEY (PageDataSectionId) REFERENCES PageDataSections(PageDataSectionId)");

Ответы [ 2 ]

0 голосов
/ 21 октября 2018

Когда проблема сложная, я предпочитаю делить это.

Для этой миграции я сделаю 2 обновления:

  1. Создание и заполнение таблицы переводов
  2. Заполнение таблицы PageDataSections

1) Создание и заполнение таблицы переводов

См. Временный столбец Translations.PageDataSectionId

public partial class Update1 : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AddColumn<int>(
            name: "PageDataSectionOrigin",
            table: "Translations",
            nullable: true);

        migrationBuilder.Sql(@"
            INSERT INTO Translations (TranslateRU, PageDataSectionOrigin)
            SELECT DataText, PageDataSectionId FROM PageDataSections
        ");
    }
}

2) Заполнение таблицы PageDataSections

См. Временный столбец удален.

public partial class Update2 : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropColumn(
            name: "DataText",
            table: "PageDataSections");

        migrationBuilder.AddColumn<int>(
            name: "DataTextTranslationId",
            table: "PageDataSections",
            nullable: true);

        migrationBuilder.Sql(@"
            UPDATE PageDataSections SET DataTextTranslationId = (select TranslationId FROM Translations WHERE PageDataSectionOrigin=PageDataSectionId)
        ");

        migrationBuilder.DropColumn(
            name: "PageDataSectionOrigin",
            table: "Translations");
    }
}

Вы можете объединить эти два обновления в одно.

Я не знаю почему, но EF назвал столбец PageDataSection.DataText дляDataTextTranslationId.Но вы можете легко заменить это имя.

0 голосов
/ 21 октября 2018

Я думаю, что ваше заявление SQL недействительно.Весь оператор OUTPUT должен находиться между INSERT и вставленными значениями.
Кроме того, вам не нужно ключевое слово VALUES при использовании результата другого запроса.

migrationBuilder.Sql(@"
    INSERT Translations (TranslateRU)
    OUTPUT inserted.TranslationId INTO PageDataSections(DataTextTranslationId)
    (SELECT DataText FROM PageDataSections) 
");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...