2010-05-15 3 views
2

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

Можете ли вы обнаружить, что я мог бы сделать в этом 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 (дубликат присоединиться в [Т7])

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 
+0

Что является дополнительным ПРИСОЕДИНЕНИЕМ? –

+0

INNER JOIN [dbo]. [PersonPhoneNumber] AS [t5] ON [t5]. [PersonID] = [t4]. [PersonID] и INNER JOIN [dbo]. [PersonPhoneNumber] AS [t7] ON [t7]. [PersonID] = [t4]. [PersonID], поэтому [t7] является дубликатом. –

ответ

0

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

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 существует. Он делает это, выполняя INNER JOIN на этой таблице.

0

Мое шестое чувство, что .distinct(). COUNT() обрабатывается отдельно с помощью перевода linq на sql.

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

0

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

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

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

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

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

Смежные вопросы