2017-04-12 69 views
0

我有以下型號:增加0..1關係在EF代碼首先

public class ItemRental 
{ 
    [Key] 
    public Int32 ItemRentalId { get; set; } 

    public Int32 ItemId { get; set; } 
    public Int32 ChargeItemId { get; set; } 

    [ForeignKey("ItemId")] 
    public Item Item { get; set; } 

    [ForeignKey("ChargeItemId")] 
    public Item ChargeItem { get; set; } 
} 

public class Item 
{ 
    [Key] 
    public Int32 ItemId { get; set; } 

    public Int32? ItemRentalId { get; set; } 

    [ForeignKey("ItemRentalId")] 
    public ItemRental ItemRental { get; set; } 
} 

ItemRentalItem一個1..1關係,並與ChargeItem一個1..N關係。

問題是我需要一個關係,從Item回到ChargeItem,所以在Item上添加屬性ItemRentalId。這是可空的,因爲不是每個Item必須有ItemRental

是否有可能創建這種關係只是註釋?

我嘗試了一口流利的API:

 modelBuilder.Entity<Item>() 
        .HasOptional(m => m.ItemRental) 
        .WithRequired(c => c.ChargeItem) 
        .Map(p => p.MapKey("ItemRentalId")); 

但這樣做遷移後是不使用ChargeItemId的關係。

問題是,當我運行這個遷移它不承認作爲FK導航屬性ItemRentalId

回答

1

所以,如果我理解正確,你的問題是與一個映射到零或一個關係。 您遇到的是實體框架的一個設計特性。處理一對一關係(及其可選對象)很棘手,原因很多。當你這樣做時,你不能在你的模型—中指定外鍵,而是你的實體的主鍵也是主體端的外鍵,不能指定額外的FK。

有關詳細信息,請參閱下面的內容。


映射一到零或一個

所以我們可以說,你有以下型號:

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模式:

仔細查看:你可以看到,有沒有FK在People指到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中可能有PersonIdPeople中有CarId。爲了強制每個人只能有一輛車,PersonId必須是唯一的Car。但是,如果PersonIdPeople中是唯一的,那麼如何添加兩個或多個記錄,其中PersonIdNULL(多輛車沒有車主)?答:你不能(事實上,你可以在SQL Server 2008和更新的版本中創建一個過濾的唯一索引,但讓我們暫時忘記這個技術性問題;更別說其他RDBMS了)。更不用說您指定關係的兩端的情況...

如果PeopleCar表具有「相同」主鍵(連接記錄中的值相同),則唯一可行的方法是執行此規則, 。要做到這一點,CarIdCar必須是一個PK和一個FK的人民PK。這使得整個模式變得混亂。當我使用這個我寧願命名PK/FK在CarPersonId,並相應地對其進行配置:

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); 
    } 
} 

並不理想,但也許會好一點。但是,使用此解決方案時必須保持警惕,因爲它違背了通常的命名約定,可能會導致您誤入歧途。下面是從這個模型生成的架構:

所以這種關係不是由數據庫架構強制執行,但通過實體框架本身。這就是爲什麼當你使用這個時你必須非常小心,而不是讓任何人直接用數據庫來鍛鍊。

+0

那麼這是EF或Sql服務器的設計限制嗎?必須有辦法可以定義導航屬性的FK名稱權限? – YesMan85

+0

我想這是兩個。在關係型數據庫中有一個真正的1-1是不可能的,所以你必須在EF中做一些技巧。另外,如果向FK添加一個唯一約束,則只有一個1-1關聯纔是可行的。我想這就是EF進入並解決這些問題的原因,因爲它引入了這個限制。 –

+0

是的,我多玩了一會兒,我能夠在SQL服務器中以黑客的方式創建關係,但無法讓它在EF中工作。現在決定改變數據模型。 – YesMan85