對映一到零或一
那麼讓我們再說一遍,你有以下模型:
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
}
public class Car
{
public int CarId { get; set; }
public string LicensePlate { get; set; }
}
public class MyDemoContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Car> Cars { get; set; }
}
現在你想要設定它以便你可以表達以下規格:一個人可以有一輛或零車,而且每輛車都屬於一個人(關係是雙向的,所以如果 CarA 屬於 PersonA,那麼 PersonA’擁有’CarA)。
所以讓我們稍微修改一下模型:新增導航屬性和外來鍵屬性:
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public int CarId { get; set; }
public virtual Car Car { get; set; }
}
public class Car
{
public int CarId { get; set; }
public string LicensePlate { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
和配置:
public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
public CarEntityTypeConfiguration()
{
this.HasRequired(c => c.Person).WithOptional(p => p.Car);
}
}
到這個時候,這應該是不言自明的。汽車有一個必需的人( HasRequired()
),該人有一輛可選的汽車( WithOptional()
)。同樣,配置此關係的哪一方並不重要,只要在使用 Has / With 和 Required / Optional 的正確組合時要小心。從 Person
方面來看,它看起來像這樣:
public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
{
public PersonEntityTypeConfiguration()
{
this.HasOptional(p => p.Car).WithOptional(c => c.Person);
}
}
現在讓我們看一下 db 模式:
仔細觀察:你可以看到 People
中沒有 FK 來指代 Car
。此外,Car
中的 FK 不是 PersonId
,而是 CarId
。這是 FK 的實際指令碼:
ALTER TABLE [dbo].[Cars] WITH CHECK ADD CONSTRAINT [FK_dbo.Cars_dbo.People_CarId] FOREIGN KEY([CarId])
REFERENCES [dbo].[People] ([PersonId])
所以這意味著我們在模型中的 CarId
和 PersonId
foregn 鍵屬性基本上被忽略了。它們位於資料庫中,但它們不是外來鍵,因為它可能是預期的。這是因為一對一對映不支援將 FK 新增到 EF 模型中。這是因為在關聯式資料庫中,一對一對映存在很大問題。
這個想法是每個人都可以擁有一輛汽車,而這輛汽車只能屬於那個人。或者可能存在人員記錄,其中沒有與他們相關聯的汽車。
那怎麼能用外來鍵表示呢?顯然,在 Car
中可能會有一個 PersonId
,而在 tihuan 中可能會有一個 CarId
。為了強制每個人只能擁有一輛車,PersonId
必須在 Car
中獨一無二。但是如果 PersonId
在 People
中是獨一無二的,那麼如何新增兩個或更多記錄,其中 PersonId
是 NULL
(多個車輛沒有車主)?答:你不能(實際上,你可以在 SQL Server 2008 及更新版本中建立一個過濾的唯一索引,但讓我們暫時忘掉這個技術性;更不用說其他 RDBMS 了)。更不用說你指定關係的兩端的情況……
如果 People
和 Car
表具有相同主鍵(連線記錄中的值相同),則執行此規則的唯一真正方法。要做到這一點,Car
中的 CarId
必須既是 PK 又是人民 PK 的 FK。這使整個架構變得混亂。當我使用它時,我寧願在 Car
PersonId
中命名 PK / FK,並相應地配置它:
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public virtual Car Car { get; set; }
}
public class Car
{
public string LicensePlate { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
}
public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
public CarEntityTypeConfiguration()
{
this.HasRequired(c => c.Person).WithOptional(p => p.Car);
this.HasKey(c => c.PersonId);
}
}
不理想,但也許更好一點。但是,在使用此解決方案時,你必須保持警惕,因為它違反了通常的命名約定,這可能會讓你誤入歧途。這是從這個模型生成的模式:
因此,這種關係不是由資料庫模式強制實施的,而是由實體框架本身強制實施的。這就是為什麼你在使用它時必須非常小心,不要讓任何人直接使用資料庫。