C# EF4代码优先-疯狂嵌套的UNION ALL和重复联接?

C# EF4代码优先-疯狂嵌套的UNION ALL和重复联接?,c#,entity-framework-4,ef-code-first,C#,Entity Framework 4,Ef Code First,我有一个类,它的“默认get方法”中包含了很多include,如下所示: _dbContext.Users .Include(c => c.PublicContact) .Include(c => c.PrivateContact) .Include(c => c.Product) .Include(c => c.Languages) .Include(c => c.Categories) .Include(c =&g

我有一个类,它的“默认get方法”中包含了很多include,如下所示:

_dbContext.Users
    .Include(c => c.PublicContact)
    .Include(c => c.PrivateContact)
    .Include(c => c.Product)
    .Include(c => c.Languages)
    .Include(c => c.Categories)
    .Include(c => c.Memberships)
    .Include(c => c.SearchWords)
    .Include(c => c.Referals)
    .Include(c => c.Files)
    .Include(c => c.Articles);
public class BaseEntity : IEntity
{
    public BaseEntity()
    {
        DateTime createdTime = DateTime.Now;
        Created = createdTime;
        Modified = createdTime;
    }

    public int Id { get; set; }
    public byte[] Timestamp { get; set; }
    public DateTime Created { get; set; }
    public DateTime Modified { get; set; }
}
DECLARE @p__linq__0 int = 1,
        @p__linq__1 int = 153

SELECT 
[UnionAll6].[C2] AS [C1], 
[UnionAll6].[C3] AS [C2], 
[UnionAll6].[C4] AS [C3],
...
[UnionAll6].[C121] AS [C121], 
[UnionAll6].[C122] AS [C122], 
[UnionAll6].[C123] AS [C123]
FROM  (SELECT 
        [UnionAll5].[C1] AS [C1], 
        [UnionAll5].[C2] AS [C2], 
        [UnionAll5].[C3] AS [C3], 
(SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[EmailAddress] AS [EmailAddress], 
    [Extent1].[LongDescription] AS [LongDescription], 
    [Extent1].[Modified] AS [Modified], 
用户从BaseEntity继承,如下所示:

_dbContext.Users
    .Include(c => c.PublicContact)
    .Include(c => c.PrivateContact)
    .Include(c => c.Product)
    .Include(c => c.Languages)
    .Include(c => c.Categories)
    .Include(c => c.Memberships)
    .Include(c => c.SearchWords)
    .Include(c => c.Referals)
    .Include(c => c.Files)
    .Include(c => c.Articles);
public class BaseEntity : IEntity
{
    public BaseEntity()
    {
        DateTime createdTime = DateTime.Now;
        Created = createdTime;
        Modified = createdTime;
    }

    public int Id { get; set; }
    public byte[] Timestamp { get; set; }
    public DateTime Created { get; set; }
    public DateTime Modified { get; set; }
}
DECLARE @p__linq__0 int = 1,
        @p__linq__1 int = 153

SELECT 
[UnionAll6].[C2] AS [C1], 
[UnionAll6].[C3] AS [C2], 
[UnionAll6].[C4] AS [C3],
...
[UnionAll6].[C121] AS [C121], 
[UnionAll6].[C122] AS [C122], 
[UnionAll6].[C123] AS [C123]
FROM  (SELECT 
        [UnionAll5].[C1] AS [C1], 
        [UnionAll5].[C2] AS [C2], 
        [UnionAll5].[C3] AS [C3], 
(SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[EmailAddress] AS [EmailAddress], 
    [Extent1].[LongDescription] AS [LongDescription], 
    [Extent1].[Modified] AS [Modified], 
当查询这个问题时,试图找到一个特定的用户需要几秒钟(实际上几乎是整整一分钟)-所以我添加了一个分析器,几乎摔倒在椅子上观察实际生成的SQL

这是一个非常糟糕的SQL——我试着将它粘贴到gmail中给朋友发电子邮件,但gmail(chrome)却落后了我。不用说,我不会把所有的东西都贴在这里,只是告诉你哪里出了问题

事情是这样开始的:

_dbContext.Users
    .Include(c => c.PublicContact)
    .Include(c => c.PrivateContact)
    .Include(c => c.Product)
    .Include(c => c.Languages)
    .Include(c => c.Categories)
    .Include(c => c.Memberships)
    .Include(c => c.SearchWords)
    .Include(c => c.Referals)
    .Include(c => c.Files)
    .Include(c => c.Articles);
public class BaseEntity : IEntity
{
    public BaseEntity()
    {
        DateTime createdTime = DateTime.Now;
        Created = createdTime;
        Modified = createdTime;
    }

    public int Id { get; set; }
    public byte[] Timestamp { get; set; }
    public DateTime Created { get; set; }
    public DateTime Modified { get; set; }
}
DECLARE @p__linq__0 int = 1,
        @p__linq__1 int = 153

SELECT 
[UnionAll6].[C2] AS [C1], 
[UnionAll6].[C3] AS [C2], 
[UnionAll6].[C4] AS [C3],
...
[UnionAll6].[C121] AS [C121], 
[UnionAll6].[C122] AS [C122], 
[UnionAll6].[C123] AS [C123]
FROM  (SELECT 
        [UnionAll5].[C1] AS [C1], 
        [UnionAll5].[C2] AS [C2], 
        [UnionAll5].[C3] AS [C3], 
(SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[EmailAddress] AS [EmailAddress], 
    [Extent1].[LongDescription] AS [LongDescription], 
    [Extent1].[Modified] AS [Modified], 
如你所见,它从“UnionAll6”中选择,这是因为它将这些疯狂的选择嵌套在6(六!)个级别中

当我查看内部嵌套(UnionAll1)时,我发现它实际上嵌套得更深——这一次它从名为[Limit1]、[Limit2]等的内容中进行选择。在这些内容中,它会根据具有正确名称的字段进行选择,如“[Limit1].[EmailAddress]AS[EmailAddress]”。在这个级别(以及选择Limit1.EmailAddress),我还发现:

CAST(NULL AS varchar(1)) AS [C2], 
CAST(NULL AS datetime2) AS [C3], 
CAST(NULL AS varchar(1)) AS [C4], 
这一次,所有这些选择实际上再次嵌套在如下位置:

_dbContext.Users
    .Include(c => c.PublicContact)
    .Include(c => c.PrivateContact)
    .Include(c => c.Product)
    .Include(c => c.Languages)
    .Include(c => c.Categories)
    .Include(c => c.Memberships)
    .Include(c => c.SearchWords)
    .Include(c => c.Referals)
    .Include(c => c.Files)
    .Include(c => c.Articles);
public class BaseEntity : IEntity
{
    public BaseEntity()
    {
        DateTime createdTime = DateTime.Now;
        Created = createdTime;
        Modified = createdTime;
    }

    public int Id { get; set; }
    public byte[] Timestamp { get; set; }
    public DateTime Created { get; set; }
    public DateTime Modified { get; set; }
}
DECLARE @p__linq__0 int = 1,
        @p__linq__1 int = 153

SELECT 
[UnionAll6].[C2] AS [C1], 
[UnionAll6].[C3] AS [C2], 
[UnionAll6].[C4] AS [C3],
...
[UnionAll6].[C121] AS [C121], 
[UnionAll6].[C122] AS [C122], 
[UnionAll6].[C123] AS [C123]
FROM  (SELECT 
        [UnionAll5].[C1] AS [C1], 
        [UnionAll5].[C2] AS [C2], 
        [UnionAll5].[C3] AS [C3], 
(SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[EmailAddress] AS [EmailAddress], 
    [Extent1].[LongDescription] AS [LongDescription], 
    [Extent1].[Modified] AS [Modified], 
这个级别似乎是最后一个级别,执行了一些较重的左外部联接(实际上,其中一些是针对额外的嵌套选择)。这是一个联盟,还有其他一些垃圾,看起来完全一样

我有一些多对多关系-它们在配置中的定义如下:

public class UsersConfiguration : EntityBaseConfiguration<Users>
{
    public UsersConfiguration()
    {
        HasMany(c => c.Languages).WithMany();
        HasMany(c => c.Categories).WithMany();
    }
}

public class EntityBaseConfiguration<T> : EntityConfiguration<T> where T : BaseEntity
{
    public EntityBaseConfiguration()
    {
        HasKey(e => e.Id);
        Property(e => e.Id).IsIdentity();
        Property(e => e.Timestamp).IsConcurrencyToken()
            .IsRequired()
            .HasStoreType("timestamp")
            .StoreGeneratedPattern = StoreGeneratedPattern.Computed;
        Property(e => e.Created)
            .StoreGeneratedPattern = StoreGeneratedPattern.None;
        Property(e => e.Modified)
            .StoreGeneratedPattern = StoreGeneratedPattern.None;
    }
}
公共类用户配置:EntityBaseConfiguration
{
公共用户配置()
{
HasMany(c=>c.Languages);
HasMany(c=>c.Categories);
}
}
公共类EntityBaseConfiguration:EntityConfiguration,其中T:BaseEntity
{
公共EntityBaseConfiguration()
{
HasKey(e=>e.Id);
属性(e=>e.Id).IsIdentity();
属性(e=>e.Timestamp).IsConcurrencyToken()
.IsRequired()
.HasStoreType(“时间戳”)
.StoreGeneratedPattern=StoreGeneratedPattern.Computed;
属性(e=>e.Created)
.StoreGeneratedPattern=StoreGeneratedPattern.None;
属性(e=>e.Modified)
.StoreGeneratedPattern=StoreGeneratedPattern.None;
}
}

我运行的是CTP4'v4.0.30319',我想升级,但这样做会破坏很多东西-我的配置不起作用,因为似乎有很多东西被更改了。如果这解决了这个疯狂的嵌套问题,我会通过升级来重写整个内容,但我不知道它会怎样?

好的,所以我决定不从基继承,而是实现一个与基具有相同属性的接口。这让我彻底崩溃,因为我需要在所有实体上重新实现所有相同的属性。不过,我可以在配置上保留继承,所以这并不都是坏事


生成的SQL现在看起来更好了。

显示用户实体的整个映射,并提及是否涉及任何继承。好的,我想我现在都明白了:)您的所有实体都是从
BaseEntity
派生的吗?只是为了测试,请尝试删除此继承。EF可能认为您的映射是一个大的TPC继承结构,可以解释这些联合。您在发布版本发布后很长时间继续使用CTP版本,这违反了您的软件许可证。你只有CTP的许可证,只要它还在测试版。您当然没有“上线”许可证。@Ladislav Mrnka:所有实体都源自BaseEntity,是的。我正在使用TPC,但即使我可以从博客文章中看到生成联合和嵌套,我仍然不明白为什么。TBT可能是一条出路?