2017-02-16 17 views
0

我有一個預先存在的數據模型,最初使用EF 4來訪問。更新到EF 6,遇到配置語法更改的問題,並定義要正確查詢的關係。實體框架Fluent API在相關對象上的sql中生成額外的列

在這種特定的情況下,我的外鍵關係是在SQL生成兩列,一個我定義,一個不知從何處......

我有以下兩個對象 - 公司與APPUSER:

public class Company : EntityBase, IComparable<Company> 
{ 
    public string Name { get; set; } 
    public virtual IList<AppSystem> AppSystems { get; set; } 
    public virtual IList<AppUser> AppUsers { get; set; } 
    public string PortalCustomerName { get; set; } 
} 

public class AppUser : EntityBase 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Email { get; set; } 
    public virtual Company Company { get; set; } 
    public FlowStatus FlowStatus { get; set; } 
    public virtual IList<AppUserRole> AppUserRoles { get; set; } 
} 

public abstract class EntityBase 
{ 
    /// <summary> 
    /// The id assigned by the system. 
    /// </summary> 
    public virtual int Id { get; set; } 
} 

配置爲兩類:

public class CompanyConfiguration : EntityTypeConfiguration<Company> 
    public CompanyConfiguration() 
    { 
     ToTable("Company"); 
     Property(c => c.Id).HasColumnName("CompanyID"); 
     Property(c => c.Name).HasMaxLength(50).IsRequired(); 
     Property(c => c.PortalCustomerName).HasMaxLength(50).IsRequired(); 
     HasMany(c => c.AppSystems); 
     HasMany(c => c.AppUsers); 
    } 
} 

public class AppUserConfiguration : EntityTypeConfiguration<AppUser> 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="AppUserConfiguration"/> class with default values. 
    /// </summary> 
    public AppUserConfiguration() 
    { 
     ToTable("AppUser"); 
     Property(u => u.Id).HasColumnName("AppUserId"); 
     Property(u => u.Email).HasMaxLength(256).IsRequired(); 
     Property(u => u.FirstName).HasMaxLength(50); 
     Property(u => u.LastName).HasMaxLength(50); 
     Property(u => u.FlowStatus.Value).HasColumnName("FlowStatus"); 
     HasRequired(u => u.Company).WithMany().Map(m => m.MapKey("CompanyID")); 
    } 
} 

數據模型: enter image description hereenter image description here

當我查詢的公司,沒問題,我得到一個匹配

SELECT 
[Extent1].[CompanyID] AS [CompanyID], 
[Extent1].[Name] AS [Name], 
[Extent1].[PortalCustomerName] AS [PortalCustomerName] 
FROM [dbo].[Company] AS [Extent1] 
WHERE N'Joe''s Diner' = [Extent1].[Name] 
ORDER BY [Extent1].[Name] ASC 

但是SQL,當我詢問我在與查詢問題AppUsers。通過上面的配置中,我得到一個正確的請求CompanyId但我也得到一個額外的列,Company_Id1:

SELECT 
[Extent1].[AppUserId] AS [AppUserId], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[LastName] AS [LastName], 
[Extent1].[Email] AS [Email], 
[Extent1].[FlowStatus] AS [FlowStatus], 
[Extent1].[CompanyID] AS [CompanyID], 
**[Extent1].[Company_Id1] AS [Company_Id1]** 
FROM [dbo].[AppUser] AS [Extent1] 
WHERE ([Extent1].[AppUserId] > 0) AND (N'Joe' = [Extent1].[LastName]) 

但如果我刪除映射和剛剛結束了「的hasMany()」的配置,正確的地圖消失,Company_Id1變成「Company_Id」:

SELECT 
[Extent1].[AppUserId] AS [AppUserId], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[LastName] AS [LastName], 
[Extent1].[Email] AS [Email], 
[Extent1].[FlowStatus] AS [FlowStatus], 
[Extent1].[Company_Id] AS [Company_Id] 
FROM [dbo].[AppUser] AS [Extent1] 
WHERE ([Extent1].[AppUserId] > 0) AND (N'Joe' = [Extent1].[LastName]) 

我的配置有什麼問題?

回答

1

使用EntityTypeConfiguration的主要缺陷是配置關係。問題在於,關係通常涉及兩個實體,但需要配置(正確)一次。該配置必須完全反映當前的導航和FK屬性。

你的情況,你有一個兩個confilicting配置和相同的關係:

公司:

HasMany(c => c.AppUsers); 

APPUSER:

HasRequired(u => u.Company).WithMany().Map(m => m.MapKey("CompanyID")); 

注意參數的WithMany在第二種配置。作爲一個經驗法則,總是在一個地方配置關係。由於Has方法需要導航屬性,而With不需要,所以在具有導航屬性的實體的配置中執行此操作。如果兩個實體都具有關係的導航屬性,則使用其中一個(但仍然只能執行一次)。

適用於您的情況,因爲兩者的實體具有導航屬性,無論是從Company配置中刪除現有的線路,並使用在AppUser配置如下:

HasRequired(u => u.Company).WithMany(c => c.AppUsers).Map(m => m.MapKey("CompanyID")); 

AppUser配置中刪除現有的線和使用在Company配置如下:

HasMany(c => c.AppUsers).WithRequired(u => u.Company).Map(m => m.MapKey("CompanyID")); 
+0

感謝您的詳細解釋 - 你可以看到我解決了這個問題,但我不是原因不清楚。你的解釋澄清 - 我只需要在一個地方定義關係。遵循這一思路,我完全從AppUserConfiguration中刪除了對公司的引用,並在公司中保留了定義並獲得了相同的SQL。這就是說 - 關於何處正確定義關係的想法是什麼?我認爲,在「孩子」(用戶)依賴於「父母」(公司)的情況下,該關係在「孩子」中會更好地定義。 –

+0

WRT導航 - 在這種情況下,如果我們在所有實體之間導航,它將從一個用戶到另一個公司,從而進一步強調,至少在這種情況下,關係定義屬於用戶(最終是AppSystems - 一旦我得到在我移植物體時將其重新合併到我的項目中......) –

+1

正如我所提到的,當您有雙向導航時,這只是一個品味問題。但是當你有單向導航的時候(有些人只把集合,只有一些引用),那麼你必須從具有導航屬性的實體開始 - 「Has'方法需要屬性訪問器,'With'具有無參數的重載。 –

-1

貌似我解決了它自己。我修改CompanyConfiguration到:

HasMany(c => c.AppUsers).WithRequired(u=>u.Company).Map(u=>u.MapKey("CompanyId")); 

而改變AppUserConfiguration

HasRequired(u => u.Company); 

顯然是由映射定義移動到主對象(公司)我告訴EF - 公司可以由許多用戶使用,用戶必須有一個公司,並確定其爲「CompanyId」

SELECT 
[Extent1].[AppUserId] AS [AppUserId], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[LastName] AS [LastName], 
[Extent1].[Email] AS [Email], 
[Extent1].[FlowStatus] AS [FlowStatus], 
[Extent1].[CompanyId] AS [CompanyId] 
FROM [dbo].[AppUser] AS [Extent1] 
WHERE ([Extent1].[AppUserId] > 0) AND (N'Joe' = [Extent1].[LastName])