вложенный выбор linq в метод Contains

#c# #sql #linq #select #nested

#c# #sql #linq #выберите #вложенный

Вопрос:

Можно ли преобразовать это в один оператор LINQ?

 SELECT COUNT(*) 
FROM Abstract_Dedications_Lookup 
WHERE PlatEntryNumber = 10383772 
AND CommonArea = 0 
AND ((OuterType <> '' AND OuterValue <> '') OR (InnerType <> '' AND InnerValue <> '')) 
AND ParcelNumber IN 
(SELECT ParentParcelNumber 
FROM Parcel_Title_History 
WHERE EntryNumber <> 10383772 
AND ParentParcelNumber <> '0' 
AND ChildParcelNumber <> ParentParcelNumber) 
  

Я перепробовал много вариантов и не могу получить правильный синтаксис в методе «.Contains». Можно ли использовать «SELECT» внутри «Contains»?

 var query2 = from d in context.RTV_ParcelDedicationLocations
from p in context.RTV_ParcelTitleHistory
where d.PlatEntryNumber == PlatEntryNum
where d.CommonArea == false
where (d.OuterType != "" amp;amp; d.OuterValue != "") || (d.InnerType != "" amp;amp; d.InnerValue != "")
where d.ParcelNumber.Contains(p.ChildParcelNumber != p.ParentParcelNumber)
select d;                      
var results2 = query2.ToList();
  

Ответ №1:

Вы можете создавать отдельные операторы linq, которые будут выполняться базой данных в виде 1 запроса. Оператор linq, который фактически выполняется, выполняется до тех пор, пока вы не начнете перебирать его.

Способ, которым я думал об этой проблеме, заключался в том, чтобы определить запрос, который получает действительный ParentParcelNumber из Parcel_Title_History . Затем создайте другой запрос, который проверяет, есть ли элементы в Abstract_Dedications_Lookup в первом запросе. Попробуйте что-то вроде этого:

 var query1 =  from p in context.RTV_ParcelTitleHistory
                where p.EntryNumber != 10383772 amp; p.ParentParcelNumber != "0" amp; p.ChildParcelNumber != p.ParentParcelNumber
                select p.ParentParcelNumber;

var query2 = from d in context.RTV_ParcelDedicationLocations
                where d.PlatEntryNumber == 10383772
                amp; d.CommonArea == 0
                amp; ((d.OuterType != "" amp;amp; d.OuterValue != "") || (d.InnerType != "" amp;amp; d.InnerValue != ""))
                amp; query1.Contains(d.ParcelNumber)
                select d;

var results2 = query2.ToList();
  

Комментарии:

1. Логика правильная, и она работает так, что я на правильном пути. У меня есть исключение out_of_memory, вероятно, потому, что количество результатов из запроса ParcelTitleHistory содержит около 300 000 записей, а содержимое этого большого результирующего набора занимает много памяти.

2. query1 фактически не вернул бы 300 000 строк, он создал бы запрос типа WHERE IN (SELECT …), как в вашем OP. Какое количество вы получаете от query2. Count()? РЕДАКТИРОВАТЬ: на самом деле я предположил, что вы используете Entity Framework, если это не так, то да, query1 возвращает 300 000 строк.

3. Количество запросов из query2 равно 43 909. Верно, что приведенный выше код не возвращает количество. Я добавил его, чтобы получить представление о том, сколько записей возвращалось из query1, а затем удалил его. По сравнению с SQL из OP, количество запросов из query2 должно быть 185. Да, я использую EF.

4. Я забыл упомянуть, что исключение «out_of_memory» было вызвано дополнительным предложением «from», которое я случайно добавил из предыдущей попытки запроса. Я удалил это и больше не исключение из памяти, но счетчик из query2 по-прежнему неверен.

5. Хм, это далеко не так. Можете ли вы выписать query2. ToTraceString() и сравнить с запросом в OP?

Ответ №2:

Сгенерированный LINQ оператор SQL, приведенный ниже, возвращает 44 092 записи, но должен быть таким же, как SQL в OP, который возвращает 182 записи. Что-то в LINQ query2, по-видимому, неверно:

 SELECT 
[Extent1].[ParcelNumber] AS [ParcelNumber], 
[Extent1].[PlatEntryNumber] AS [PlatEntryNumber], 
[Extent1].[OuterType] AS [OuterType], 
[Extent1].[OuterValue] AS [OuterValue], 
[Extent1].[InnerType] AS [InnerType], 
[Extent1].[InnerValue] AS [InnerValue], 
[Extent1].[CommonArea] AS [CommonArea]
FROM (SELECT 
[RTV_ParcelDedicationLocations].[ParcelNumber] AS [ParcelNumber], 
[RTV_ParcelDedicationLocations].[PlatEntryNumber] AS [PlatEntryNumber], 
[RTV_ParcelDedicationLocations].[OuterType] AS [OuterType], 
[RTV_ParcelDedicationLocations].[OuterValue] AS [OuterValue], 
[RTV_ParcelDedicationLocations].[InnerType] AS [InnerType], 
[RTV_ParcelDedicationLocations].[InnerValue] AS [InnerValue], 
[RTV_ParcelDedicationLocations].[CommonArea] AS [CommonArea]
FROM [dbo].[RTV_ParcelDedicationLocations] AS [RTV_ParcelDedicationLocations]) AS [Extent1]
WHERE (([Extent1].[PlatEntryNumber] = 10383772) AND (10383772 IS NOT NULL) 
AND (0 = [Extent1].[CommonArea]) AND ('''' <> [Extent1].[OuterType]) AND ('''' <> [Extent1].[OuterValue])) 
OR (('''' <> [Extent1].[InnerType]) AND ('''' <> [Extent1].[InnerValue])
AND ( EXISTS (SELECT 1 AS [C1]
FROM (SELECT  [RTV_ParcelTitleHistory].[EntryNumber] AS [EntryNumber], 
[RTV_ParcelTitleHistory].[ParentParcelNumber] AS [ParentParcelNumber], 
[RTV_ParcelTitleHistory].[ChildParcelNumber] AS [ChildParcelNumber], 
[RTV_ParcelTitleHistory].[Book] AS [Book], 
[RTV_ParcelTitleHistory].[Page] AS [Page]
FROM [dbo].[RTV_ParcelTitleHistory] AS [RTV_ParcelTitleHistory]) AS [Extent2]
WHERE ( NOT (([Extent2].[EntryNumber] = 10383772) AND (10383772 IS NOT NULL))) AND ('0' <> [Extent2].[ParentParcelNumber]) AND ([Extent2].[ChildParcelNumber] <> [Extent2].[ParentParcelNumber]) AND ([Extent2].[ParentParcelNumber] = [Extent1].[ParcelNumber])
)))