迁移会创建意外的 ID 字段,但未明确指定

Posted

技术标签:

【中文标题】迁移会创建意外的 ID 字段,但未明确指定【英文标题】:Migration creates unexpected ID field, though not explicitly specified 【发布时间】:2019-06-07 08:38:27 【问题描述】:

C# Code First 迁移会创建额外的字段,即 [WebsiteUser_UserID] [int],但未明确指定。

我在引用父类字段[WebsiteUser].[UserID] 的子类(LessonComment) 中创建了一些属性,例如PostedByCensoredBy。但是,当我运行命令 Update-database -script 时,它会在子类中创建一个字段 [WebsiteUser_UserID]

WebsiteUser.cs

public partial class WebsiteUser

    public WebsiteUser()
    
        this.Courses = new List<Course>();
        this.LessonComments = new List<LessonComment>();
        this.UserLessons = new List<UserAssessLesson>();
    
    [Key]
    public int UserID  get; set; 
    [Required]
    public string Name  get; set; 
    [Required]
    public string Email  get; set; 

    [MaxLength(200)]
    [Required]
    [ScaffoldColumn(false)]
    public string PasswordHash  get; set; 

    [ForeignKey("Role")]
    public Nullable<int> RoleID  get; set;  

    public virtual Role Role  get; set; 
    public virtual ICollection<Course> Courses  get; set;  // New
    public virtual ICollection<LessonComment> LessonComments  get; set; 
    public virtual ICollection<UserAssessLesson> UserLessons  get; set; 

LessonComment.cs

public partial class LessonComment

    [Key]
    public int CommentID  get; set; 
    [MaxLength(500)]
    public string Comment  get; set;   

    [ForeignKey("CourseLesson")]
    public int LessonID  get; set; 

    [ForeignKey("PostedBy")]
    public int PostedByUserID  get; set; 

    public DateTime DatePosted  get; set;         

    //  CENSORSHIP DETAIL (If comment is censored)
    public Nullable<bool> IsCensored  get; set;   // Comment will not be displayed until verified
    [ForeignKey("CensoredBy")]
    public int CensoredByUserID  get; set; 
    public Nullable<DateTime> CensorDate  get; set; 
    [MaxLength(100)]
    public string CensorReason  get; set;   

    //  Navigation Properties
    public virtual CourseLesson CourseLesson  get; set; 
    public virtual WebsiteUser PostedBy  get; set; 
    public virtual WebsiteUser CensoredBy  get; set; 


SQL 脚本

CREATE TABLE [dbo].[WebsiteUser] (
[UserID] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max) NOT NULL,
[Email] [nvarchar](max) NOT NULL,
[PasswordHash] [nvarchar](200) NOT NULL,
[RoleID] [int],
CONSTRAINT [PK_dbo.WebsiteUser] PRIMARY KEY ([UserID])
)

CREATE TABLE [dbo].[LessonComment] (
[CommentID] [int] NOT NULL IDENTITY,
[Comment] [nvarchar](500),
[LessonID] [int] NOT NULL,
[PostedByUserID] [int] NOT NULL,
[DatePosted] [datetime] NOT NULL,
[Censored] [bit],
[CensoredByUserID] [int] NOT NULL,
[CensorDate] [datetime],
[CensorReason] [nvarchar](100),
[WebsiteUser_UserID] [int],  -- How is this created ???
CONSTRAINT [PK_dbo.LessonComment] PRIMARY KEY ([CommentID])
)
CREATE INDEX [IX_LessonID] ON [dbo].[LessonComment]([LessonID])
CREATE INDEX [IX_PostedByUserID] ON [dbo].[LessonComment]([PostedByUserID])
CREATE INDEX [IX_CensoredByUserID] ON [dbo].[LessonComment]([CensoredByUserID])
CREATE INDEX [IX_WebsiteUser_UserID] ON [dbo].[LessonComment]([WebsiteUser_UserID])    
ALTER TABLE [dbo].[LessonComment] ADD CONSTRAINT [FK_dbo.LessonComment_dbo.WebsiteUser_CensoredByUserID] FOREIGN KEY ([CensoredByUserID]) REFERENCES [dbo].[WebsiteUser] ([UserID]) ON DELETE CASCADE
ALTER TABLE [dbo].[LessonComment] ADD CONSTRAINT [FK_dbo.LessonComment_dbo.CourseLesson_LessonID] FOREIGN KEY ([LessonID]) REFERENCES [dbo].[CourseLesson] ([LessonID]) ON DELETE CASCADE
ALTER TABLE [dbo].[LessonComment] ADD CONSTRAINT [FK_dbo.LessonComment_dbo.WebsiteUser_PostedByUserID] FOREIGN KEY ([PostedByUserID]) REFERENCES [dbo].[WebsiteUser] ([UserID]) ON DELETE CASCADE
ALTER TABLE [dbo].[LessonComment] ADD CONSTRAINT [FK_dbo.LessonComment_dbo.WebsiteUser_WebsiteUser_UserID] FOREIGN KEY ([WebsiteUser_UserID]) REFERENCES [dbo].[WebsiteUser] ([UserID])  --No idea how this is created

预期结果是不应创建附加字段“[WebsiteUser_UserID] [int]”。

【问题讨论】:

你的 DbContext 在哪里? [ForeignKey("PostedBy")] 更改为 [ForeignKey("PostedByUserID")] 并将其放在您的导航属性中,对其他人也这样做。 问题是用于将 ForeignKey 映射到父类的 enityframework 遵循与子类中的父类名称相同的名称的属性。将 PostedByUserID 更改为 WebsiteUserId 或使用 fluent api 进行地图 阿明这不是解决方案。我应该将PostedByUserIDCensoredByUserID 都更改为WebsiteUserID;因为它们引用的是 WebsiteUser 类。一个类可以有 2 个名称完全相同的属性吗? 奥尔德特,我试过很多次;你没有时间尝试吗?定义导航有 3 种方法 1 public int PostedByUserID get; set; [ForeignKey("PostedByUserID")] public virtual WebsiteUser PostedBy get; set; 2 [ForeignKey("PostedBy")] public int PostedByUserID get; set; public virtual WebsiteUser PostedBy get; set; 在实体框架中定义外键的方法下阅读this 我发现了这个问题并回答了我自己的问题 【参考方案1】:

使用父类中的InverseProperty注解解决:

public partial class WebsiteUser

// ...
    [InverseProperty("PostedBy")] // Solved the problem
    public virtual ICollection<LessonComment> LessonComments  get; set; 

注意:由于子类中有超过 1 个外键(PostedBy、CensoredBy),因此需要在父类。

阅读以下[文章](http://www.entityframeworktutorial.net/code-first/inverseproperty-dataannotations-attribute-in-code-first.aspx"InverseProperty-Data Annotations-attribute-in-code-first")

【讨论】:

以上是关于迁移会创建意外的 ID 字段,但未明确指定的主要内容,如果未能解决你的问题,请参考以下文章

在 Codeigniter DBForge 迁移中创建唯一字段

实体框架代码首次迁移文件源代码控制

迁移错误后处于带有外键的奇怪状态

用于创建表并在两个字段上添加唯一索引的 Rails 迁移文件在迁移期间似乎被忽略了

迁移成功但未显示在数据库中

在 Laravel 迁移中创建一个具有自定义大小的小整数列