Сначала код EF4 - безумно вложенные UNION ALL и дублированные объединения? - PullRequest
3 голосов
/ 23 августа 2011

У меня есть класс с несколькими включениями в его «метод get по умолчанию», например:

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

Пользователи наследуют от BaseEntity, который выглядит следующим образом:

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

Когда вы пытаетесь найти конкретного пользователя, это занимает несколько секунд (фактически, почти целую минуту), поэтому я добавил профилировщик и чуть не упал на стул, наблюдая за фактическим сгенерированным SQL ...

Этоloooooooong SQL - я пытался вставить его в Gmail, чтобы отправить электронное письмо другу, но Gmail (в Chrome) отстает от меня.Само собой разумеется, я не буду здесь все это вставлять, просто расскажу вам, что не так.

Это начинается так:

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

Как видите, этовыбирает из 'UnionAll6', потому что он вкладывает эти безумные селекты в 6 (SIX!) уровней.

Когда я заглядываю во внутреннее вложение (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], 

Весь этот выбор фактически вложен снова на этот раз из чего-то вроде этого:

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

Этот уровень кажется последним, и выполняется некоторое тяжелое левое внешнее объединение (фактически, некоторые из них против дополнительного вложенного выбора).Тогда это UNION ALL с каким-то другим дерьмом, выглядящим точно так же.

У меня есть некоторые отношения многие-ко-многим - они определены следующим образом в конфигурации:

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Я работаю против CTP 4 'v4.0.30319', и я хочу обновить, но это ломает много вещей - моя конфигурация не работает, так как многое изменилось, кажется.Я бы переписал весь материал путем обновления, если бы это решило эту безумную проблему с вложенностью, но я не понимаю, как это будет?

1 Ответ

0 голосов
/ 31 августа 2011

Хорошо, поэтому я решил не наследовать от базы и вместо этого реализовать интерфейс с теми же свойствами, что и моя база.Это заставляет меня ломать СУХОЙ, так как мне нужно будет повторно реализовать все те же свойства на всех моих сущностях.Однако я могу сохранить наследование конфигураций, так что не все так плохо.

Сгенерированный SQL теперь выглядит лучше.

...