【问题标题】:HowTo update every row with unique value on migration using entity framework code first implementation如何使用实体框架代码优先实现更新具有唯一迁移值的每一行
【发布时间】:2018-01-18 19:02:02
【问题描述】:

我正在寻找一种适当的方法来扩展现有数据库,基于实体框架 6 代码优先实现,并为表中每个现有行的新字段添加唯一值。

到目前为止,我已经创建了一个添加新字段的迁移。

Up 方法如下所示:

Public Overrides Sub Up()
    AddColumn("dbo.Customers", "UniqueCode", Function(c) c.String(unicode:=False))
End Sub

我被困在应该用唯一(计算)值填充新字段的地方。为简单起见,假设数据库中的每个现有行都应在迁移时分配一个 GUID。

使用这样的 SQL 语句会更新具有相同 GUID 的所有行。但我需要它对每一行都是唯一的。

Sql("Update dbo.Customers SET UniqueCode = '" & Guid.NewGuid().ToString)

在 Up 方法中使用 foreach 似乎有点错误……在这种情况下,最佳实践是什么?

另外:我使用的数据库是access,所以不能使用newid()或者random()。 GUID 旨在成为以编程方式计算的值的虚拟对象。它将是客户其他一些属性的哈希值。所以它必须通过迁移来计算和更新。

【问题讨论】:

  • 新值可以在服务器端计算,还是需要应用程序代码来计算?如果可以在服务器端进行,您可以编写脚本并调用存储过程来计算和更新字段添加后Up 期间的数据。
  • 不确定我是否完全理解您的问题。新值是根据数据库客户记录中的一组现有值计算得出的,然后使用 SHA256 算法对其进行哈希处理。无需用户输入。
  • 我在问您是否可以完全在 stored proc 内计算和更新新字段,或者您是否真的需要根据不在数据库中的数据或使用不在数据库中的数据以编程方式计算它由数据库服务器支持。如果您可以在 proc 中执行此操作,则添加 proc 并在添加列的行之后的 Up 中调用它。
  • 感谢您的澄清。我不能在 proc 中进行,因为计算是基于数据库服务器不支持的方法。
  • 基于您正在处理的限制,我认为循环数据并逐行更新将是您唯一的选择。

标签: asp.net vb.net entity-framework ms-access jet-ef-provider


【解决方案1】:

我发现以下方法最适合我的情况。我建议将数据库和数据更改拆分为 2 次迁移,这样您就可以使用框架进行所有更改并完全上下兼容。

这里是我的方法的详细信息:

按照 Bradley Uffner 的建议,我遍历数据并逐行更新。但是,在同一个迁移中执行此操作会引发错误:

支持“DbContext”上下文的模型自数据库创建以来已更改。考虑使用 Code First 迁移来更新数据库。

在迁移过程中使用 DbContext 会导致状态不一致。模型已经处于迁移后状态,但数据库在表中仍然具有迁移前状态。模型和数据库不匹配,导致上述错误。为了完成这项工作,我必须禁用模型检查。

参考:Change data in migration Up method - Entity Framework

在上面的线程中,我发现了将数据库更改与数据更改分开的建议。这正是我所做的。

我创建了一个迁移来更新数据库

    Public Overrides Sub Up()
        AddColumn("dbo.Customers", "WebCode", Function(c) c.String(unicode := false))
    End Sub

    Public Overrides Sub Down()
        DropColumn("dbo.Customers", "WebCode")
    End Sub

运行Update-Database 命令。然后创建第二个迁移以进行数据更改。 UpDown 方法在创建时将为空。这是我用来逐行更新数据的代码。

    Public Overrides Sub Up()
        Dim DbContext As New Data.DbContext

        For Each customer In DbContext.Customers.Where(Function(x) String.IsNullOrEmpty(x.WebCode))
            customer.WebCode = GetWebCode(customer)
        Next

        DbContext.SaveChanges()
    End Sub

    Public Overrides Sub Down()
        Dim DbContext As New Data.DbContext

        For Each customer In DbContext.Customers
            customer.WebCode = Nothing
        Next

        MyDbContext.SaveChanges()
    End Sub

有些人可能会争论在 Down 方法中使用简单的 SQL,例如

SQL("Update dbo.Customers SET WebCode = NULL")

效率更高。我已经尝试过了,但在JetEntityFrameworkProvider.JetMigrationSqlGenerator.GenerateSqlStatmentConcrete 遇到了一个错误,我无法找到并修复它。它使 Visual Studio 崩溃。

【讨论】:

    【解决方案2】:

    如果您的数据库服务器是 SQL Server,您可以使用在数据库服务器上生成 GUID 的内置 newid() 函数

    https://docs.microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql

    查询将是

    Update dbo.Customers SET UniqueCode = newid()
    

    如果是 SQLite 数据库,请使用 random() 函数。

    【讨论】:

    • THX。我在最初的问题中添加了一些附加信息。我知道这些功能,但不能使用它们。我正在寻找一种使用程序计算值更新每一行的方法。
    • @Maddin:下次请记住在有人打扰回答之前将这些关键信息包含在您的问题中。我不知道您知道这些功能,也不知道您使用的是 Jet 引擎。
    猜你喜欢
    • 2013-12-29
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-31
    相关资源
    最近更新 更多