使用迁移更新代码优先数据库

Posted

技术标签:

【中文标题】使用迁移更新代码优先数据库【英文标题】:Updating a code-first database with migrations 【发布时间】:2018-02-24 11:13:12 【问题描述】:

我已经通过this question here 的答案,到目前为止,没有任何提及适用或解决了这个问题。

编辑

我尝试过的:

更新了 __MigrationHistory 表中的 ContextKey 列。 从旧版本的项目中复制了所有旧迁移。

问题

我刚刚在我的应用程序中遇到了一个错误,该错误是由应该链接 2 个表的列中的 0 值引起的。因此,我更新了我的数据模型以构建它们之间的关系:

public class ContactGroup

    public int Id  get; set; 
    public string Name  get; set; 

public class Contact

    public int Id  get; set; 
    public ContactGroup ContactGroup  get; set; 
    // other contact columns go here

我拥有的其他表之一称为 Campaigns,所以现在添加了一个设置我的外键的迁移,我想update-database

这是我的问题所在,因为我收到一条错误消息:

数据库中已经有一个名为“Campaigns”的对象。

我知道数据库中已经有一个具有此名称的对象,因为它是我正在与之建立关系的对象之一。

这是由实体框架生成的迁移

public partial class StructuredRelationships : DbMigration

    public override void Up()
    
        CreateTable(
            "dbo.Campaigns",
            c => new
                
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(),
                    Client = c.String(),
                    EmailAddress = c.String(),
                    PhoneNumber = c.String(),
                    FaxNumber = c.String(),
                    PhysicalAddress = c.String(),
                    PostalAddress = c.String(),
                    DateSent = c.DateTime(),
                    SmtpServerAddress = c.String(),
                    SmtpServerPort = c.Int(nullable: false),
                    SmtpServerUser = c.String(),
                    SmtpServerPassword = c.String(),
                    Deleted = c.Boolean(nullable: false),
                    SendInterval = c.Int(nullable: false),
                )
            .PrimaryKey(t => t.Id);
        
        CreateTable(
            "dbo.ContactGroups",
            c => new
                
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(),
                    Deleted = c.Boolean(nullable: false),
                )
            .PrimaryKey(t => t.Id);
        
        CreateTable(
            "dbo.Contacts",
            c => new
                
                    Id = c.Int(nullable: false, identity: true),
                    ContactGroupId = c.Int(nullable: false),
                    CompanyName = c.String(),
                    Salutation = c.String(),
                    FirstName = c.String(),
                    LastName = c.String(),
                    EmailAddress = c.String(),
                    Telephone = c.String(),
                    DirectTel = c.String(),
                    Mobile = c.String(),
                    BroadDesignation = c.String(),
                    Designation = c.String(),
                    EmployeeCount = c.Int(nullable: false),
                    EmployeeCountBand = c.String(),
                    SaTelProvince = c.String(),
                    SaBroadArea = c.String(),
                    Town = c.String(),
                    Suburb = c.String(),
                    Type = c.String(),
                    SpecificBusinessClassification = c.String(),
                    ReferenceNumber = c.String(),
                    Deleted = c.Boolean(nullable: false),
                )
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.ContactGroups", t => t.ContactGroupId, cascadeDelete: true)
            .Index(t => t.ContactGroupId);
        
        CreateTable(
            "dbo.Emails",
            c => new
                
                    Id = c.Int(nullable: false, identity: true),
                    CampaignId = c.Int(nullable: false),
                    TemplateId = c.Int(nullable: false),
                    Sender = c.String(),
                    From = c.String(),
                    FromAddress = c.String(),
                    ReplyTo = c.String(),
                    ReplyToAddress = c.String(),
                    Subject = c.String(),
                    Body = c.String(),
                    Footer = c.String(),
                    DateCreated = c.DateTime(nullable: false),
                    Deleted = c.Boolean(nullable: false),
                )
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Campaigns", t => t.CampaignId, cascadeDelete: true)
            .Index(t => t.CampaignId);
        
        CreateTable(
            "dbo.EmailSends",
            c => new
                
                    Id = c.Int(nullable: false, identity: true),
                    CampaignId = c.Int(nullable: false),
                    EmailId = c.Int(nullable: false),
                    ContactGroupId = c.Int(nullable: false),
                    SendDate = c.DateTime(nullable: false),
                    TotalRecipients = c.Int(nullable: false),
                    TotalSent = c.Int(nullable: false),
                    TotalFailed = c.Int(nullable: false),
                    Status = c.String(),
                    CompletedDate = c.DateTime(),
                    Deleted = c.Boolean(nullable: false),
                    TrackerUrl = c.String(),
                )
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Campaigns", t => t.CampaignId, cascadeDelete: true)
            .ForeignKey("dbo.ContactGroups", t => t.ContactGroupId, cascadeDelete: true)
            .ForeignKey("dbo.Emails", t => t.EmailId, cascadeDelete: true)
            .Index(t => t.CampaignId)
            .Index(t => t.EmailId)
            .Index(t => t.ContactGroupId);
        
        CreateTable(
            "dbo.EmailTemplates",
            c => new
                
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(),
                    Markup = c.String(),
                    Deleted = c.Boolean(nullable: false),
                )
            .PrimaryKey(t => t.Id);
        
    
    
    public override void Down()
    
        DropForeignKey("dbo.EmailSends", "EmailId", "dbo.Emails");
        DropForeignKey("dbo.EmailSends", "ContactGroupId", "dbo.ContactGroups");
        DropForeignKey("dbo.EmailSends", "CampaignId", "dbo.Campaigns");
        DropForeignKey("dbo.Emails", "CampaignId", "dbo.Campaigns");
        DropForeignKey("dbo.Contacts", "ContactGroupId", "dbo.ContactGroups");
        DropIndex("dbo.EmailSends", new[]  "ContactGroupId" );
        DropIndex("dbo.EmailSends", new[]  "EmailId" );
        DropIndex("dbo.EmailSends", new[]  "CampaignId" );
        DropIndex("dbo.Emails", new[]  "CampaignId" );
        DropIndex("dbo.Contacts", new[]  "ContactGroupId" );
        DropTable("dbo.EmailTemplates");
        DropTable("dbo.EmailSends");
        DropTable("dbo.Emails");
        DropTable("dbo.Contacts");
        DropTable("dbo.ContactGroups");
        DropTable("dbo.Campaigns");
    

那么现在解决此问题并应用此迁移的最佳方法是什么?

【问题讨论】:

【参考方案1】:

只需从生成的迁移中删除针对dbo.CampaignsCreateTable 方法。对于未来的迁移,这不会被添加,因为模型实际上是在 __MigrationHistory 表中序列化的,并且它知道您已经对其采取了行动。

这会记录在__MigrationHistory 表中的Model 列中,并且它知道Campaigns 已经存在并且不会尝试再次创建它。

希望对你有帮助

【讨论】:

以上是关于使用迁移更新代码优先数据库的主要内容,如果未能解决你的问题,请参考以下文章

调试代码优先的实体框架迁移代码

实体框架代码优先迁移 - 我可以针对以前的迁移

C# 代码优先迁移,向上/向下?

使用迁移文件更新生产数据库

代码优先更新数据库错误“ApplicationDbContext”上下文已更改

在实体优先迁移中为新Guid列添加默认值