對映一到零或一

那麼讓我們再說一遍,你有以下模型:

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])

所以這意味著我們在模型中的 CarIdPersonId foregn 鍵屬性基本上被忽略了。它們位於資料庫中,但它們不是外來鍵,因為它可能是預期的。這是因為一對一對映不支援將 FK 新增到 EF 模型中。這是因為在關聯式資料庫中,一對一對映存在很大問題。

這個想法是每個人都可以擁有一輛汽車,而這輛汽車只能屬於那個人。或者可能存在人員記錄,其中沒有與他們相關聯的汽車。

那怎麼能用外來鍵表示呢?顯然,在 Car 中可能會有一個 PersonId,而在 tihuan 中可能會有一個 CarId。為了強制每個人只能擁有一輛車,PersonId 必須在 Car 中獨一無二。但是如果 PersonIdPeople 中是獨一無二的,那麼如何新增兩個或更多記錄,其中 PersonIdNULL(多個車輛沒有車主)?答:你不能(實際上,你可以在 SQL Server 2008 及更新版本中建立一個過濾的唯一索引,但讓我們暫時忘掉這個技術性;更不用說其他 RDBMS 了)。更不用說你指定關係的兩端的情況……

如果 PeopleCar 表具有相同主鍵(連線記錄中的值相同),則執行此規則的唯一真正方法。要做到這一點,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);
  }
}

不理想,但也許更好一點。但是,在使用此解決方案時,你必須保持警惕,因為它違反了通常的命名約定,這可能會讓你誤入歧途。這是從這個模型生成的模式:

因此,這種關係不是由資料庫模式強制實施的,而是由實體框架本身強制實施的。這就是為什麼你在使用它時必須非常小心,不要讓任何人直接使用資料庫。