简单的LINQ到实体翻译

时间:2019-03-25 12:02:35

标签: c# linq entity-framework-6 extension-methods

在有人跳到重复标记之前,我已经看过了,每个人都在做比我尝试的要复杂的事情。

因此,我正在处理一个要检查大量数据的数据库,而将LINQ的Any()扩展转换为SQL的速度不如SQL的Count(1)> 0快,所以我在写的所有地方:< / p>

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无法识别方法布尔型AnyX等...

一定有某种编写扩展程序的方式或某种告诉LINQ的方式,只是为了看一下代码,您就会发现可以做到这一点。

1 个答案:

答案 0 :(得分:0)

不是您的特定问题的答案,但我建议您重新考虑如何处理查询。

让我们使用一些易于理解的描述性名称:是否有任何家庭的居民姓“ Bobby”?

// 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
*/