EF 自动迁移不适用于虚拟属性

Posted

技术标签:

【中文标题】EF 自动迁移不适用于虚拟属性【英文标题】:EF Automatic Migration not working with virtual property 【发布时间】:2012-06-13 08:38:08 【问题描述】:

我正在尝试首先对实体框架和代码使用自动迁移。我为我的班级添加了新属性(团队也是自定义班级):

public virtual Team SecondTeam  get; set; 

我在更新数据库时遇到问题。在我编写命令后,我在控制台中得到了这个:

SQL Server Compact 不支持直接重命名列。到 在 SQL Server Compact 中重命名列,您需要重新创建它。

通常正在更新工作(我尝试添加简单的 int 道具,它只是更新)但如果那是虚拟的,我会遇到问题。谁能帮我这个? 谢谢

编辑:Update-Database -Verbose 之后的所有行

Using NuGet project 'Project'.  
Using StartUp project 'Project'.  
Target database is: '|DataDirectory|database.sdf' (DataSource: |DataDirectory|database.sdf, Provider: System.Data.SqlServerCe.4.0, Origin: Configuration). 
No pending explicit migrations. 
Applying automatic migration: 201206130828142_AutomaticMigration. 
Direct column renaming is not supported by SQL Server Compact. To rename a column in SQL Server Compact, you will need to recreate it.

编辑2: 我要更改数据库的播放器类:

public class Player
    
        [Key]
        public int PlayerID  get; set; 

        [Required]
        public string Name  get; set; 
        [Required]
        public string Surname  get; set; 
        public string Nickname  get; set; 
        public DateTime Birth  get; set; 

        public string PhotoUrl  get; set; 
        public string Post  get; set; 

        public int TeamID  get; set; 
        public virtual Team Team  get; set; 

        public int SecondTeamID  get; set; 
        public virtual Team SecondTeam  get; set; 

        public int UserId  get; set; 
        public virtual User User  get; set; 
    

团队班级:

public class Team
    
        [Key]
        public int TeamID  get; set; 
        public string Name  get; set; 

        public string League  get; set; 
        public string Trainings  get; set; 

        public string PhotoUrl  get; set; 

        public int CoachID  get; set; 
        public int AassistantID  get; set; 
        public int ManagerID  get; set; 

        public virtual ICollection<Player> Players  get; set; 

        public bool showPosts  get; set; 
    

这是 EF 生成的 SQL:

CREATE TABLE "Players" (
    "PlayerID" int not null identity,
    "Name" nvarchar(4000) not null,
    "Surname" nvarchar(4000) not null,
    "Nickname" nvarchar(4000) null,
    "Birth" datetime not null,
    "PhotoUrl" nvarchar(4000) null,
    "Post" nvarchar(4000) null,
    "TeamID" int not null,
    "SecondTeamID" int not null,
    "UserId" int not null,
    "Team_TeamID" int null,
    "Team_TeamID1" int null,
    "SecondTeam_TeamID" int null,
    PRIMARY KEY ("PlayerID")
);

ALTER TABLE "Players" ADD CONSTRAINT "Team_Players" FOREIGN KEY ("Team_TeamID") REFERENCES "Teams"("TeamID");
ALTER TABLE "Players" ADD CONSTRAINT "Player_Team" FOREIGN KEY ("Team_TeamID1") REFERENCES "Teams"("TeamID");
ALTER TABLE "Players" ADD CONSTRAINT "Player_SecondTeam" FOREIGN KEY ("SecondTeam_TeamID") REFERENCES "Teams"("TeamID");
ALTER TABLE "Players" ADD CONSTRAINT "Player_User" FOREIGN KEY ("UserId") REFERENCES "Users"("UserID") ON DELETE CASCADE;

【问题讨论】:

运行 Update-Database -Script 以查看它试图重命名的内容,或使用 -Verbose 选项了解更多信息。 我试过了,但对我没有多大帮助。 将生成的 SQL 和您的实体的整个代码发布到您的问题中。看来 EF 认为您重命名了属性而不是添加新属性。 除了virtual Team SecondTeam 之外还有int SecondTeamID 之类的字段的任何具体原因?该列是多余的,我有一种预感,它可能会混淆变更检测逻辑。 【参考方案1】:

我知道这是一个老问题,但我认为这个解决方案以后会很有用。

除非您确定代码仅限于调试环境,否则请勿使用RecreateDatabaseIfModelChanges 功能。如果它在生产代码中出现问题(并且您可能并不总是在发布前查看 DAL)意外的数据丢失很容易成为一个问题。

如果您正确使用迁移,您会看到 EF 为您生成如下代码:

namespace Migrations_CE

    using System;
    using System.Data.Entity.Migrations;

    public partial class TargetInventoryChange : DbMigration
    
        public override void Up()
        
            RenameColumn(table: "dbo.TargetInventoryItems", name: "MatchedPrinter_ID", newName: "MatchedPrinterID");
            AddColumn("dbo.TargetInventoryItems", "CustomerID", c => c.String(maxLength: 40));
            AlterColumn("dbo.TargetInventoryItems", "Name", c => c.String(maxLength: 100));
        

        public override void Down()
        
            AlterColumn("dbo.TargetInventoryItems", "Name", c => c.String(maxLength: 4000));
            DropColumn("dbo.TargetInventoryItems", "CustomerID");
            RenameColumn(table: "dbo.TargetInventoryItems", name: "MatchedPrinterID", newName: "MatchedPrinter_ID");
        
    

在这个特定的项目中,我保留了两组迁移,一组用于 SQL CE 数据库,一组用于 SQL Server。在为 Compact 版本进行迁移时,我偶然发现了您的问题。

我只是按照错误消息的说明解决了它。 请注意,这会导致您正在重命名的列上的数据丢失。小心。

这个例子解决了外键的情况,这是(我相信)最糟糕的情况之一,因为 EF 自己生成列、FK 约束和自动索引。

public override void Up()

    //RenameColumn(table: "dbo.TargetInventoryItems", name: "MatchedPrinter_ID", newName: "MatchedPrinterID");
    DropIndex("dbo.TargetInventoryItems", "IX_MatchedPrinter_ID");
    DropForeignKey("dbo.TargetInventoryItems", "FK_dbo.TargetInventoryItems_dbo.CustPrinters_MatchedPrinter_ID");
    DropColumn("dbo.TargetInventoryItems", "MatchedPrinter_ID");
    AddColumn("dbo.TargetInventoryItems", "MatchedPrinterID", c => c.Int());
    AddForeignKey("dbo.TargetInventoryItems", "MatchedPrinterID", "dbo.CustPrinters", "ID");
    CreateIndex("dbo.TargetInventoryItems", "MatchedPrinterID", unique: false);

如果您不知道索引的名称,可以使用 SQL CE 工具箱 (http://sqlcetoolbox.codeplex.com/) 查看特定表。您将看到一个索引列表,您可以在其中找到要删除的名称。

对于 FK 约束,您必须查询 INFORMATION_SCHEMA,例如再次使用 SQL CE 工具箱,查询类似

SELECT * FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS

根据需要添加一些WHERE 条件。我希望这将在适当的 SQL 生成器上得到修复,但同时这实际上解决了问题 - 进行小的更改。

【讨论】:

也许是个愚蠢的问题,但是您如何维护第二组迁移? 我已经离开了那个项目,但我记得有一个自定义类设置为上下文的 DbConfiguration。在该类中,根据某些配置值(在我的应用程序的 XML 配置文件中),我确实实例化了 SQL CE 或 SQLSrv 驱动程序和连接字符串。在更新配置并指定正确的“迁移”目录(/命名空间)后,我只是运行了用于管理迁移的 powershell EF 工具。迁移器也一样:从正确的命名空间中选择正确的配置类。【参考方案2】:

我认为如果您遵循此示例 Steven Sanderson - MvcScaffolding: One-to-Many Relationships 并在开发期间使用该功能在启动时根据 Scott Guthrie - Code-First Development with Entity Framework 4 博客重新创建数据库。 (搜索段落Taking advantage of SQL CE 4The RecreateDatabaseIfModelChanges Feature

【讨论】:

以上是关于EF 自动迁移不适用于虚拟属性的主要内容,如果未能解决你的问题,请参考以下文章

子类化迁移器不适用于命名空间迁移

EF:禁用时自动迁移正在运行

EF6 Migration 自动迁移未执行

EF CodeFirst 数据库创建与迁移

用于更改列数据类型的 EF 迁移

EF 自动迁移向后兼容