【问题标题】:Add records using Entity Framework CF migrations使用 Entity Framework CF 迁移添加记录
【发布时间】:2015-12-30 14:17:03
【问题描述】:

我有一个表A和一个表B,关系如下:

表 A

Id
...

表 B

Id
TableA_Id  (foreign key table A)

我首先使用实体​​框架代码并已激活迁移。

我要做的是进行迁移,为表 B 的每个现有记录在表 A 中添加一条记录,然后在表 B 中添加对新表 A 行的外键引用。强>

我使用了以下命令并创建了一个空迁移:

Add-Migration <NameOfMyMigration> 

这导致了以下代码:

public partial class NameOfMyMigration : DbMigration
{
    public override void Up()
    {
        // This is where I want to write code that adds records
    }

    public override void Down()
    {
    }
}

【问题讨论】:

  • 在过去的好日子里,类似的事情会通过触发器来完成。只是说
  • blog.oneunicorn.com/2013/05/28/…(您可以从迁移配置类中播种)
  • 谢谢!我在种子类中添加了一些代码,根据需要添加记录。然而,为了让迁移触发种子逻辑,我必须让 Up 方法添加和删除一个虚拟列,否则种子代码将无法运行。这并没有让我觉得这是一个很棒的解决方案......有更好的方法来实现这一点吗? :)

标签: c# .net entity-framework entity-framework-migrations


【解决方案1】:

在阅读了 Alexander Derck 的问题 cmets 后,我最终得到了以下解决方案。我会把它贴在这里,以防其他人需要解决这个问题。

但是,我个人认为这更像是一种 hack 而不是解决方案,因此我仍然对解决这个问题的正确方法感兴趣。请勿在不质疑其有效性的情况下将此答案复制粘贴到您的生产环境中!

解决方案是在种子配置中添加一些代码。关注this link 了解更多信息(复制自 Alexander Derck 的评论)

种子代码大致如下:

foreach (var tableBData in context.TableB.ToList())
{
    if (tableB.TableA == null)
    {
        var tableA = new TableA();
        tableB.TableB = tableA;
    }

    context.SaveChanges();
}

然后是阴暗的东西:以下是引用的博客条目的摘录:

只要执行 Update-Database PowerShell 命令,[迁移种子] 就会运行。 除非正在使用迁移初始化程序,否则迁移种子 应用程序启动时不会执行该方法。

为了触发迁移(默认为空,即不包含任何实际修改),我在迁移逻辑中添加了以下代码:

public partial class NameOfMyMigration : DbMigration
{
    public override void Up()
    {
        AddColumn("dbo.TableA", "DummyField", c => c.Boolean(nullable: false, defaultValue: true));
        DropColumn("dbo.TableA", "DummyField");
    }

    public override void Down()
    {
    }
}

当然,仅当这是新版本之前的最后一次迁移时才需要此迁移,因为此迁移之后的任何迁移也会触发种子,因此不需要此迁移。

但我仍然觉得必须有更好的方法来解决这个问题?

【讨论】:

    【解决方案2】:

    使用自动迁移。

    按照此 MSDN 博客文章中的说明进行操作。 Automatic Migrations Walkthrough

    首先,您需要启用自动迁移。在 PM 控制台中,运行 Enable-Migrations -EnableAutomaticMigrations

    启用后,您可以使用命令 Add-MigrationUpdate-Database 为您完成所有繁重的工作。

    这会自动搭建你的 up 和 down 方法并将记录添加到数据库中。

    编辑:更新了当前版本的链接。

    【讨论】:

    • 虽然正确,但问题中已经明确说明迁移已经设置,并且我确实运行了 Add-Migration 命令来创建空迁移(因为没有涉及模型更改)
    • 是的,但“手动”迁移和自动迁移之间存在差异。启用自动迁移以便能够使用此解决方案。
    • 我看不到自动迁移如何帮助我用新数据填充现有表
    • 嗨@havardhu,我重读了你的问题,我相信你在问如何自动化一个过程来在TableA中添加对TableB具有forgien键的行。这是正确的吗?
    【解决方案3】:

    我不确定我是否了解您的需求,但我认为您的情况是您已经拥有 Code First 项目并且已经拥有充满数据的数据库,现在您想添加新表,所以首先我尝试联系您的情况:

     public class ApplicationDbContext : DbContext
        {
            public DbSet<ClassB> BList { get; set; }
    
            public ApplicationDbContext()
                : base("DefaultConnection", throwIfV1Schema: false)
            {
            }
    
            public static ApplicationDbContext Create()
            {
                return new ApplicationDbContext();
            }
    
        }
        public class ClassB
        {
            public ClassB()
            {
                BId = Guid.NewGuid().ToString();
    
            }
             [Key]
            public string BId { get; set; }
    
    
        }
    

    在种子方法中:

    protected override void Seed(ApplicationDbContext context)
        {
            //  This method will be called after migrating to the latest version.
    
            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            context.BList.AddOrUpdate(
    
              new ClassB { BId = Guid.NewGuid().ToString() },
              new ClassB { BId = Guid.NewGuid().ToString() },
              new ClassB { BId = Guid.NewGuid().ToString() }
            );
    
        }
    

    然后添加迁移 和更新数据库 现在我有一个名为 ClassBs 的表,有 3 行 然后创建 ClassAs 表:

    public class ClassA
        {
            public ClassA()
            {
                AId = Guid.NewGuid().ToString();
    
            }
            [Key]
            public string AId { get; set; }
    
    
        }
    

    并像以前一样将 DbSet 添加到上下文中:

    public DbSet<ClassA> AList { get; set; }
    

    在种子方法中:

        context.AList.AddOrUpdate(
    
          new ClassA { AId = Guid.NewGuid().ToString() },
          new ClassA { AId = Guid.NewGuid().ToString() },
          new ClassA { AId = Guid.NewGuid().ToString() }
        );
    

    现在我有两个具有一对多关系的表,就像你一样 最后,我现在可以逐行编辑 ClassB 表。 种子方法:

     protected override void Seed(ApplicationDbContext context)
        {
            //  This method will be called after migrating to the latest version.
    
            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
    
            var BArray = context.BList.ToArray();
            var AArray = context.AList.ToArray();
            for (int i = 0; i < BArray.Length; i++)
            {
                if (BArray.Length == AArray.Length)
                {
                    BArray[i].AID = AArray[i].AId;
    
                }
    
            }
            context.SaveChanges();
        }
    

    现在只需更新数据库
    它有效。

    【讨论】:

    • 不,这两个表都已经存在,它们之间的关系也是如此。唯一新的是,现在 TableA 中必须有一个相关行,这在以前不是必需的。因此,我需要一种适当的方法来播种数据而不引入任何模型更改。我找到了一个解决方案(请参阅我自己的答案),但它更像是一个 hack,而不是我书中的正确解决方案
    • 您不需要对种子数据进行任何模型更改,您只需在种子方法中编写代码,然后执行 update-database 即可。
    猜你喜欢
    • 2017-02-06
    • 1970-01-01
    • 2019-01-11
    • 2018-06-08
    • 2015-10-17
    • 2019-01-28
    • 1970-01-01
    • 2017-06-17
    • 1970-01-01
    相关资源
    最近更新 更多