Простой перевод LINQ to Entities - PullRequest
3 голосов
/ 25 марта 2019

Прежде чем кто-либо прыгнет на отметку как дубликат, я посмотрел, и все делают что-то немного более сложное, чем я пытаюсь.

Итак, я работаю с базой данных, где нужно проверить много данных, и расширение LINQ Any (), переведенное в SQL, не так быстро, как SQL Count (1)> 0, поэтому везде я пишу:

var someBool = Ctx.SomeEntities.Count(x => x.RelatedEntity.Count(y => y.SomeProperty == SomeValue) > 0) > 0;

В Pseudo: Имеет ли какая-либо из моих сущностей отношения с какой-либо другой сущностью, у которой есть свойство со значением SomeValue.

Это отлично работает и работает быстро. Тем не менее, он не совсем читабелен (и у меня их много, более встроенных, чем в случаях), поэтому я хотел бы заменить его на:

var someBool = Ctx.SomeEntities.AnyX(x => x.RelatedEntity.AnyX(y => y.SomeProperty == SomeValue));

с:

public static bool AnyX<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) => source.Count(predicate) > 0;

Итак, вы видите, что я не делаю ничего, что LINQ не может перевести на SQL, я не делаю ничего, что LINQ уже не переводит на SQL, а просто создаю дополнительное расширение, которое я получаю:

LINQ to Entities не распознает метод Boolean AnyX и т. Д. *

Должен быть какой-то способ написания моего расширения или какой-то способ сказать LINQ, просто чтобы взглянуть на код, и вы увидите, что вы можете это сделать.

1 Ответ

0 голосов
/ 29 марта 2019

Не ответ на ваш конкретный вопрос, но я предлагаю вам переосмыслить, как вы подходите к запросу.

Давайте используем некоторые описательные имена, которые облегчат понимание: есть ли в домохозяйствах резидент с именем «Бобби»?

// your way
Ctx.Households.Count( hh => hh.Residents.Count( r => r.FirstName == "Bobby" ) > 0 ) > 0

Тьфу, это задом наперед. Начните с резидентов:

Ctx.Residents.Count( r => 
    r.FirstName == "Bobby"
    && r.Household != null ) // if needed
    > 0;

Теперь, будет ли это генерировать SQL значительно отличным от приведенного ниже?

Ctx.Residents.Any( r => r.FirstName == "Bobby" && r.Household != null)

редактирование:

Вот истинный MCVE, который приводит к противоположному вашему выводу:

/*
create table TestDatum
(
    TestValue nchar(36) not null
)
*/

/*
set nocount on
declare @count int
declare @start datetime
declare @end datetime
set @count = 0

set @start = GETDATE()

while @count < 14000000
begin
    insert TestDatum values( CONVERT(nchar(36), NEWID()) )

    set @count = @count + 1

    if (@count % 100000) = 0
    begin
        print convert(nvarchar, @count)
    end
end

set @end = GETDATE()

select CONVERT(nvarchar, DATEDIFF(ms, @start, @end))
*/

/*
-- "Any" test
declare @startdt datetime, @enddt datetime
set @startdt = GETDATE()
DECLARE @p0 NVarChar(1000) = '%abcdef%'

SELECT 
    (CASE 
        WHEN EXISTS(
            SELECT NULL AS [EMPTY]
            FROM TestDatum AS [t0]
            WHERE [t0].TestValue LIKE @p0
            ) THEN 1
        ELSE 0
     END) AS [value]
set @enddt = GETDATE()
select DATEDIFF(ms, @startdt, @enddt) -- ~7000ms
*/
/*
-- "Count" test
declare @startdt datetime, @enddt datetime
set @startdt = GETDATE()
-- Region Parameters
DECLARE @p0 NVarChar(1000) = '%abcdef%'
-- EndRegion
SELECT COUNT(*) AS [value]
FROM TestDatum AS [t0]
WHERE [t0].TestValue LIKE @p0
set @enddt = GETDATE()
select DATEDIFF(ms, @startdt, @enddt) -- > 48000ms
*/
...