使用 Jet Engine 使用 Entity Framework(代码优先)重命名列(并保留数据)

Rename column (and preserve data) with Entity Framework (code first) using Jet Engine

我正在寻找一种解决方案来重命名 table 的列,使用 Entity Framework 代码首先迁移 Jet 引擎数据库提供程序(MS Access 数据库)来保留值。

我尝试了几种方法,其中 none 由于处理 Jet Engine 和 MS Access DB 而有效。

以下是我已经尝试过的模型更改和方法的详细信息:

模型更改

(我缩短了更改以保持清晰):

    ' OLD properties
    ' Public Property WebServiceState As ServiceStateType?
    ' Public Property WebServiceRegistrationDate As DateTime?
    ' Public Property WebServiceEndOfTrialDate As DateTime?
    ' Public Property WebServiceExpirationDate As DateTime?

    ' NEW
    Public Property WebServiceState As ServiceState

除了“WebService”之外,还有其他服务类型都具有相同的属性(注册日期,...)。因此我创建了一个新的 class ServiceState 来表示这些属性。

Public Class ServiceState
    Public Property State As ServiceStateType?
    Public Property RegistrationDate As DateTime?
    Public Property EndOfTrialDate As DateTime?
    Public Property ServiceStopAtDate As DateTime?
End Class

迁移

在迁移时,我必须将数据移动到新结构。我使用 PM-Console 和“add-migration”创建了一个迁移。这是 up 函数的自动生成代码:

    Public Overrides Sub Up()
        AddColumn("dbo.Services", "WebServiceState_State", Function(c) c.Int())
        AddColumn("dbo.Services", "WebServiceState_RegistrationDate", Function(c) c.DateTime())
        AddColumn("dbo.Services", "WebServiceState_EndOfTrialDate", Function(c) c.DateTime())
        AddColumn("dbo.Services", "WebServiceState_ServiceStopAtDate", Function(c) c.DateTime())

        DropColumn("dbo.Services", "WebServiceState")
        DropColumn("dbo.Services", "WebServiceRegistrationDate")
        DropColumn("dbo.Services", "WebServiceEndOfTrialDate")
        DropColumn("dbo.Services", "WebServiceExpirationDate")
    End Sub

使用此代码,数据将会丢失,因为新旧属性之间没有数据传输。

尝试过的方法

为了保留数据,我尝试了 How to rename a database column in Entity Framework 5 Code First migrations without losing data?.

中的以下方法

1。使用 RenameColumn

RenameColumn("dbo.Services", "WebServiceState", "WebServiceState_State")

这不起作用。 PM-Konsole 报告

Cannot rename objects with Jet

2。使用 SQL 进行更新

Sql("Update dbo.Services SET [WebServiceState_State] = [WebServiceState]")

也不行。它在 GenerteSqlStatementConcrete

上抛出错误

3。使用数据库上下文

在迁移Up方法中更改数据

恕我直言,这不是一个选项。它会导致不一致的状态,因为模型已经处于迁移后状态,但数据库在 tables 中仍然具有迁移前状态。模型和数据库不匹配,导致错误。

The model backing the 'DbContext' context has changed since the database was created. Consider using Code First Migrations to update the database.

为了完成这项工作,我必须禁用模型检查,我认为这不是一件好事。 (参考:

问题

如何根据我正在处理的上述限制(主要是由于 MS Access 数据库导致的 Jet 引擎)重命名列/保留迁移数据?

ms access 的主要问题是没有 SQL 语句重命名对象。唯一的方法是使用外部 DLL(通常是 ADOX)。

所以,如果你觉得没问题,你可以使用 IvanStoev 的建议。唯一的问题是您的列名与 属性 名称不匹配(但这只是一个内部问题)。

另一种可能是添加新列,将数据从旧列复制到新列并删除旧列。

另一种可能是您使用了ADOX。您可以使用此源代码

https://github.com/bubibubi/EntityFrameworkCore.Jet/blob/master/src/System.Data.Jet/AdoxWrapper.cs

如果未安装 ADOX,应用程序可以运行(但重命名会引发错误)。我正在使用它在用于 Microsoft 访问的 EF 核心提供程序中实现对象重命名。

调用的方法是重命名列。

在 EF 核心的提供程序中(仍处于测试阶段)它已实现。

除了我对bubi的回答的评论,这里是我最终使用的代码。请确保您使用的是 JetEntityFrameworkProvider 1.2.7 或更高版本。迁移不支持低于 SQL 的语句 (reference)。

Public Overrides Sub Up()
    AddColumn("dbo.Services", "WebServiceState_State", Function(c) c.Int())
    AddColumn("dbo.Services", "WebServiceState_RegistrationDate", Function(c) c.DateTime())
    AddColumn("dbo.Services", "WebServiceState_EndOfTrialDate", Function(c) c.DateTime())
    AddColumn("dbo.Services", "WebServiceState_ServiceStopAtDate", Function(c) c.DateTime())

    Sql("UPDATE Services SET [WebServiceState_State] = [WebServiceState]")
    Sql("UPDATE Services SET [WebServiceState_RegistrationDate] = [WebServiceRegistrationDate]")
    Sql("UPDATE Services SET [WebServiceState_EndOfTrialDate] = [WebServiceEndOfTrialDate]")
    Sql("UPDATE Services SET [WebServiceState_ServiceStopAtDate] = [WebServiceExpirationDate]")

    DropColumn("dbo.Services", "WebServiceState")
    DropColumn("dbo.Services", "WebServiceRegistrationDate")
    DropColumn("dbo.Services", "WebServiceEndOfTrialDate")
    DropColumn("dbo.Services", "WebServiceExpirationDate")
End Sub