簡體   English   中英

EF Code First一對一和一對多映射

[英]EF Code First One-to-One AND One-to-Many mapping

我有以下模型,我試圖從相同的父和子實體構建一對一和一對多的關系。 一對多關系適用於我當前的映射,但我正在努力添加新的一對一關系(對於CoverPicture屬性)。 以下是相關模型和EF映射代碼:

Category.cs:

public int Id { get; set; }
public string Name { get; set; }
public Guid? CoverPictureId { get; set; }
public virtual Picture CoverPicture { get; set; }
public virtual ICollection<Picture> Pictures { get; set; }

Picture.cs:

public Guid Id { get; set; }
public string FileName { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }

相關類別EntityTypeConfiguration<Category>映射(不正確):

this.HasOptional(t => t.CoverPicture)
    .WithRequired()
    .Map(m => m.MapKey("CoverPictureId"))
    .WillCascadeOnDelete(false);

相關圖片EntityTypeConfiguration<Picture>映射(正確):

this.HasRequired(t => t.Category)
    .WithMany(t => t.Pictures)
    .HasForeignKey(k => k.CategoryId);

當我嘗試為新的CoverPicture屬性添加遷移時,EF嘗試將一個CoverPictureId列添加到Category表(這是我想要的),還將CoverPictureIdPicture表(這不是我想要的; Picture已經有了鍵定義和映射)。

這是由EF搭建的Up()遷移代碼:

AddColumn("dbo.Category", "CoverPictureId", c => c.Guid());
AddColumn("dbo.Picture", "CoverPictureId", c => c.Int());
CreateIndex("dbo.Picture", "CoverPictureId");
AddForeignKey("dbo.Picture", "CoverPictureId", "dbo.Category", "Id");

我究竟做錯了什么?

我不確定您使用的是哪個版本的EF,但是較新版本不允許您執行您嘗試執行的映射類型,您將收到以下錯誤:

在'YourProject.Category'類型上聲明的導航屬性'Pictures'已配置了沖突的多重性。

那為什么呢? 讓我們看一下你的映射,以及你用簡單的英語告訴Entity Framework:

this.HasRequired(t => t.Category)  //A Picture must have 1 Category
.WithMany(t => t.Pictures)         //A Category can have many Pictures


this.HasOptional(t => t.CoverPicture) //A Category may or may not have 1 Picture
.WithRequired()                       //A Picture must have 1 Category

與octavioccl的答案相比:

this.HasOptional(p => p.CoverPicture) //A Category may or may not have 1 Picture 
.WithMany()                           //A Picture can have many Categories

從WithRequired到WithMany的更改是交換放置外鍵的位置。 現在你有了你正在尋找的映射......有點:

CreateTable(
    "dbo.Categories",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            Name = c.String(),
            CoverPicture_Id = c.Guid(),
        })
    .PrimaryKey(t => t.Id)
    .ForeignKey("dbo.Pictures", t => t.CoverPicture_Id)
    .Index(t => t.CoverPicture_Id);

CreateTable(
    "dbo.Pictures",
    c => new
        {
            Id = c.Guid(nullable: false),
            FileName = c.String(),
            Category_Id = c.Int(nullable: false),
        })
    .PrimaryKey(t => t.Id)
    .ForeignKey("dbo.Categories", t => t.Category_Id, cascadeDelete: true)
    .Index(t => t.Category_Id);

但是讓我們停下來思考一下。 您不僅基本上在兩個方向上定義了1對多的關系(不要與多對多關系混淆),而且還破壞了模型的完整性。 現在您可以將Picture指定為CategoryCoverPicture即使該Picture不屬於該Category 這不是你想要的,最終會讓你頭痛。 而不是在Category上明確定義CoverPicture屬性,這個怎么樣?

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Picture> Pictures { get; set; }

    public SetCoverPicture(Picture picture)
    {
        if(!Pictures.Contains(picture))
        {
            throw new ArgumentException("Picture is not in this Category");
        }
        var currentCoverPicture = Pictures.FirstOrDefault(p=p.IsCoverPicture == true);
        if(currentCoverPictur e!= null)
        {
            currentCoverPicture.IsCoverPicture = false;
        }
        picture.IsCoverPicture = true;
    }

}

public class Picture
{
    public Guid Id { get; set; }
    public string FileName { get; set; }
    public int Category_Id { get; set; }
    public virtual Category Category { get; set; }
    public bool IsCoverPicture { get; protected internal set; }
}

這會強制您的不變量(業務規則)聲明...

  1. CategoryCoverPicture必須屬於該Category (由數據庫強制執行)和
  2. 一個Category只能有1個CoverPicture (在代碼中強制執行)

您可以使用octavioccl提供的代碼執行類似操作,但此處提供的代碼可以生成更清晰,更易理解的物理數據模型。

要解決您的問題,請嘗試映射該關系,如下所示:

this.HasOptional(p => p.CoverPicture)
            .WithMany().HasForeignKey(p=>p.CoverPictureId)
            .WillCascadeOnDelete(false);

在一對一的關系中,一端必須是主要的 ,第二端必須是依賴的 在配置此類關系時,Entity Framework要求依賴項的主鍵也是外鍵。 使用您的配置,主體是Category ,dependend是Picture 這就是FK CoverPictureIdint而不是Guid ,因為這實際上是你的遷移代碼所解釋的Category PK。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM