![](/img/trans.png)
[英]EF 5 Code First: one-to-one and one-to-many associations between two entities
[英]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
表(這是我想要的),還將CoverPictureId
到Picture
表(這不是我想要的; 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
指定為Category
的CoverPicture
即使該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; }
}
這會強制您的不變量(業務規則)聲明...
Category
的CoverPicture
必須屬於該Category
(由數據庫強制執行)和 Category
只能有1個CoverPicture
(在代碼中強制執行) 您可以使用octavioccl提供的代碼執行類似操作,但此處提供的代碼可以生成更清晰,更易理解的物理數據模型。
要解決您的問題,請嘗試映射該關系,如下所示:
this.HasOptional(p => p.CoverPicture)
.WithMany().HasForeignKey(p=>p.CoverPictureId)
.WillCascadeOnDelete(false);
在一對一的關系中,一端必須是主要的 ,第二端必須是依賴的 。 在配置此類關系時,Entity Framework要求依賴項的主鍵也是外鍵。 使用您的配置,主體是Category
,dependend是Picture
。 這就是FK CoverPictureId
是int
而不是Guid
,因為這實際上是你的遷移代碼所解釋的Category
PK。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.