Configuration 实体框架Fluent API在相关对象的sql中生成额外列

Configuration 实体框架Fluent API在相关对象的sql中生成额外列,configuration,entity-framework-6,ef-fluent-api,Configuration,Entity Framework 6,Ef Fluent Api,我有一个预先存在的数据模型,最初使用EF4访问。更新到EF 6,遇到配置语法更改的问题,并正确定义要查询的关系 在这个特定的例子中,我的外键关系在SQL中生成两列,一列是我定义的,另一列是不知从何而来的 我有以下两个对象-Company和AppUser: public class Company : EntityBase, IComparable<Company> { public string Name { get; set; } public virtual IL

我有一个预先存在的数据模型,最初使用EF4访问。更新到EF 6,遇到配置语法更改的问题,并正确定义要查询的关系

在这个特定的例子中,我的外键关系在SQL中生成两列,一列是我定义的,另一列是不知从何而来的

我有以下两个对象-Company和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; }
}
然而,当我查询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”:


我的配置有什么问题?

使用
EntityTypeConfiguration
的主要缺陷是配置关系。问题在于,关系通常涉及两个实体,但只需要(正确地)配置一次。配置必须准确反映当前的导航和FK属性

在您的情况下,您有两个相同关系的配置:

公司:

应用程序用户:

注意第二个配置中的无参数
和多个

根据经验,始终在一个位置配置关系。由于
Has
方法需要导航属性,而
With
方法不需要导航属性,因此请在具有导航属性的实体的配置中执行此操作。如果两个实体都具有关系的导航属性,则使用其中一个(但仍然只执行一次)

应用于您的场景,因为您的两个实体都有导航属性,请从
Company
配置中删除现有行,并在
AppUser
配置中使用以下命令:

HasRequired(u => u.Company).WithMany(c => c.AppUsers).Map(m => m.MapKey("CompanyID"));
HasMany(c => c.AppUsers).WithRequired(u => u.Company).Map(m => m.MapKey("CompanyID"));
或者从
AppUser
配置中删除现有行,并在
公司
配置中使用以下内容:

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

看来是我自己解决的。我将公司配置修改为:

 HasMany(c => c.AppUsers).WithRequired(u=>u.Company).Map(u=>u.MapKey("CompanyId"));
并更改了AppUserConfiguration

 HasRequired(u => u.Company);
显然,通过将映射定义移动到主要对象(Company),我告诉EF-Company可以被许多用户使用,用户必须有一个Company,并将其标识为“CompanyId”


谢谢你的详细解释——正如你所看到的,我解决了这个问题,但我不清楚为什么。你的解释澄清了-我只需要在一个地方定义关系。按照这种想法,我从AppUserConfiguration中完全删除了对Company的引用,并将定义保留在Company中,得到了相同的SQL。也就是说,你有没有想过应该在哪里定义关系?我认为,在“子”(用户)依赖于“母公司”(公司)的情况下,关系最好在“子公司”中定义。WRT导航-在这种情况下,如果我们在实体之间导航,它将从用户导航到公司,因此进一步强调,至少在这种情况下,关系定义属于用户(以及最终的AppSystems——一旦我在迁移对象时着手将其重新合并到我的项目中……),正如我所提到的,当您具有双向导航时,这只是一个品味问题。但是当您使用单向导航时(有些人只放置集合,有些人只放置引用),那么您必须从具有导航属性的实体开始-
Has
方法需要属性访问器,
with
具有无参数重载。
HasMany(c => c.AppUsers).WithRequired(u => u.Company).Map(m => m.MapKey("CompanyID"));
 HasMany(c => c.AppUsers).WithRequired(u=>u.Company).Map(u=>u.MapKey("CompanyId"));
 HasRequired(u => u.Company);
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])