简体   繁体   中英

EF4 code-first - insanely nested UNION ALL and duplicated joins?

I have a class with quite a few includes in its 'default get method', like this:

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

Users inherit from BaseEntity that looks like this:

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

When query against that, trying to find a specific user it takes several seconds (actually almost a whole minute) - so i added a profiler and almost fell down the chair observing the actual SQL generated...

Its a loooooooong SQL - i tried pasting it into gmail to email a friend, but gmail (in chrome) lagged me out. Needless to say, i won't be pasting it all here, just give you a jist of what's wrong.

It starts out like this:

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], 

As you can see, it selects from 'UnionAll6' which is because it nests these insane selects in 6 (SIX!) levels.

When i look into the inner nesting (UnionAll1) i find that it's actually nested even deeper - this time it selects from something called [Limit1], [Limit2], etc. where it does selecting against fields with the right names, like this '[Limit1].[EmailAddress] AS [EmailAddress]'. At this level (along with selecting Limit1.EmailAddress) i also find this:

CAST(NULL AS varchar(1)) AS [C2], 
CAST(NULL AS datetime2) AS [C3], 
CAST(NULL AS varchar(1)) AS [C4], 

All this selecting is actually nested again this time from something like this:

(SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[EmailAddress] AS [EmailAddress], 
    [Extent1].[LongDescription] AS [LongDescription], 
    [Extent1].[Modified] AS [Modified], 

This level seems to be the last one, and some heavy left outer join is performed (actually some of it is against an extra nested select). This is then UNION ALL with some other crap, looking excatly the same.

I have some many-to-many relations - they are defined like this in the configuration:

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

I'm running against the CTP 4 'v4.0.30319' and i want to upgraded, but doing so breaks a lot of stuff - my configuration doesn't work since a lot has been changed it seems. I would rewrite the whole stuff by upgrading if that solves this insane nesting problem, but i don't see how it would?

Ok, so i decided to not inherit from a base and instead implement an interface with the same properties my base had. This makes me break DRY since i'll need to re-implement all the same properties on all my entities. I can keep inheritance on the configurations though, so it's not all bad.

The generated SQL looks better now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM