C# EF4代码优先-疯狂嵌套的UNION ALL和重复联接?
我有一个类,它的“默认get方法”中包含了很多include,如下所示: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
_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可能是一条出路?