LINQ считает, что мне нужно дополнительное ВНУТРЕННЕЕ СОЕДИНЕНИЕ, но зачем? - PullRequest
2 голосов
/ 15 мая 2010

У меня есть запрос LINQ, который по какой-то причине генерирует дополнительный / дубликат INNER JOIN. Это приводит к тому, что запрос не возвращает ожидаемый результат. Если я вручную прокомментирую этот дополнительный JOIN из сгенерированного SQL, то получу, казалось бы, правильный вывод.

Можете ли вы определить, что я мог сделать в этом LINQ, чтобы вызвать этот дополнительный JOIN?

Спасибо.

Вот мой приблизительный LINQ

predicate=predicate.And(condition1);
predicate1=predicate1.And(condition2);
predicate1=predicate1.And(condition3);
predicate2=predicate2.Or(predicate1);
predicate=predicate.And(predicate2);
var ids = context.Code.Where(predicate); 
            var rs = from r in ids 
                     group r by r.PersonID into g 
                     let matchcount=g.Select(p => p.phonenumbers.PhoneNum).Distinct().Count() 
                     where matchcount ==2 
                     select new 
                  { 
                      personid = g.Key 
                  };

и вот сгенерированный SQL (дубликат соединения [t7])

Declare @p1 VarChar(10)='Home'
Declare @p2 VarChar(10)='111'
Declare @p3 VarChar(10)='Office'
Declare @p4 VarChar(10)='222'
Declare @p5 int=2

SELECT [t9].[PersonID] AS [pid]
FROM (
    SELECT [t3].[PersonID], (
        SELECT COUNT(*)
        FROM (
            SELECT DISTINCT [t7].[PhoneValue]
            FROM [dbo].[Person] AS [t4]
            INNER JOIN [dbo].[PersonPhoneNumber] AS [t5] ON [t5].[PersonID] = [t4].[PersonID]
            INNER JOIN [dbo].[CodeMaster] AS [t6] ON [t6].[Code] = [t5].[PhoneType]
            INNER JOIN [dbo].[PersonPhoneNumber] AS [t7] ON [t7].[PersonID] = [t4].[PersonID]
            WHERE ([t3].[PersonID] = [t4].[PersonID]) AND ([t6].[Enumeration] = @p0) AND ((([t6].[CodeDescription] = @p1) AND ([t5].[PhoneValue] = @p2)) OR (([t6].[CodeDescription] = @p3) AND ([t5].[PhoneValue] = @p4)))
            ) AS [t8]
        ) AS [value]
    FROM (
        SELECT [t0].[PersonID]
        FROM [dbo].[Person] AS [t0]
        INNER JOIN [dbo].[PersonPhoneNumber] AS [t1] ON [t1].[PersonID] = [t0].[PersonID]
        INNER JOIN [dbo].[CodeMaster] AS [t2] ON [t2].[Code] = [t1].[PhoneType]
        WHERE ([t2].[Enumeration] = @p0) AND ((([t2].[CodeDescription] = @p1) AND ([t1].[PhoneValue] = @p2)) OR (([t2].[CodeDescription] = @p3) AND ([t1].[PhoneValue] = @p4)))
        GROUP BY [t0].[PersonID]
        ) AS [t3]
    ) AS [t9]
WHERE [t9].[value] = @p5

Ответы [ 3 ]

0 голосов
/ 07 августа 2010

Попробуйте переписать с явным условием вместо абстрактной конструкции "предикат".Из того, что я вижу в SQL, эта композиция может выглядеть странно для синтаксического анализатора в отдельности, и одно соединение [t5], которое вы только что назвали dupe :-), служит для выполнения этого условия.

Также попробуйте рассказать нам, чтосиница, которую вы действительно хотите найти с помощью этого запроса, и попробуйте написать нормальный SQL, который делает то, что вы хотели.Я должен быть человеком :-) и мне это тоже кажется странным: -))

Технически говоря, вы принудительно выполняли двойное соединение, используя условие on в двух отдельных запросах (каждое присваивание переменной этотехнически отдельный запрос).

Кроме того, группирование по столбцу без агрегирования не всегда эквивалентно выбору отличного.В частности, выбор отличного в соединении может иметь приоритет над соединением - запросы являются деклатативными (могут подвергаться переупорядочению), и вы пытались заставить его быть процедурным.Итак, LINQ дал вам точную процедурную процедуру :-), а затем SQL переупорядочил в соответствии с правилами SQL :-))

Итак, сначала просто напишите нормальный SQL, а если вы не можете LINQ-ize, поместите его в sproc -в любом случае это будет ускоряться: -)

0 голосов
/ 19 августа 2010

Они не дублируются.Вы запрашиваете два разных значения из источника данных.

let matchcount=g.Select(p => p.phonenumbers.PhoneNum).Distinct().Count()

вызывает

        SELECT COUNT(*) 
        FROM ( 
            SELECT DISTINCT [t7].[PhoneValue] 
            FROM [dbo].[Person] AS [t4] 
            INNER JOIN [dbo].[PersonPhoneNumber] AS [t5] ON [t5].[PersonID] = [t4].[PersonID] 
            INNER JOIN [dbo].[CodeMaster] AS [t6] ON [t6].[Code] = [t5].[PhoneType] 
            INNER JOIN [dbo].[PersonPhoneNumber] AS [t7] ON [t7].[PersonID] = [t4].[PersonID] 
            WHERE ([t3].[PersonID] = [t4].[PersonID]) AND ([t6].[Enumeration] = @p0) AND ((([t6].[CodeDescription] = @p1) AND ([t5].[PhoneValue] = @p2)) OR (([t6].[CodeDescription] = @p3) AND ([t5].[PhoneValue] = @p4))) 
            ) AS [t8] 

, а

                     from r in ids   
                     group r by r.PersonID into g 

вызывает

    SELECT [t0].[PersonID]    
    FROM [dbo].[Person] AS [t0]    
    INNER JOIN [dbo].[PersonPhoneNumber] AS [t1] ON [t1].[PersonID] = [t0].[PersonID]    
    INNER JOIN [dbo].[CodeMaster] AS [t2] ON [t2].[Code] = [t1].[PhoneType]    
    WHERE ([t2].[Enumeration] = @p0) AND ((([t2].[CodeDescription] = @p1) AND ([t1].[PhoneValue] = @p2)) OR (([t2].[CodeDescription] = @p3) AND ([t1].[PhoneValue] = @p4)))    
    GROUP BY [t0].[PersonID]    
    ) AS [t3]   

Что касается ВНУТРЕННИХ СОЕДИНЕНИЙ, причина, по которой вы их получаете, заключается в связи между этими таблицами.Например, Person это 1..1 с PersonPhoneNumber (или 1 .. *).В любом случае я предполагаю, что PersonID на PersonPhoneNumber является значением FK и PK.Таким образом, в этом случае источник данных должен перейти к этой внешней таблице, чтобы увидеть, действительно ли существует значение для свойства навигации PersonPhoneNumber.Он делает это, выполняя ВНУТРЕННЕЕ СОЕДИНЕНИЕ для этой таблицы.

0 голосов
/ 27 мая 2010

Мне кажется, что .DISTINCT (). COUNT () обрабатывается отдельно переводом linq в sql

Я бы также поспорил, что план выполнения на SQL просто отбросил обман.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...