C# 将SQL语句重写为LINQ查询会导致运行时错误

C# 将SQL语句重写为LINQ查询会导致运行时错误,c#,sql,linq,.net-core,entity-framework-core,C#,Sql,Linq,.net Core,Entity Framework Core,作为后续行动,我得到了以下SQL: 选择文档。* 从文件 Documents.ID在哪里 选择关键字。文档ID 来自关键字 哪里 Keywords.Keyword='KeywordA'或 Keywords.Keyword='KeywordB' 按关键字分组。文档ID 有COUNTKeywords.Keyword=2 我曾将查询转换为C,以便与Entity Framework Core 5一起使用: 来自db.Document中的文档 哪里 数据库中的from关键字。关键字 哪里 关键字.Valu

作为后续行动,我得到了以下SQL:

选择文档。* 从文件 Documents.ID在哪里 选择关键字。文档ID 来自关键字 哪里 Keywords.Keyword='KeywordA'或 Keywords.Keyword='KeywordB' 按关键字分组。文档ID 有COUNTKeywords.Keyword=2 我曾将查询转换为C,以便与Entity Framework Core 5一起使用:

来自db.Document中的文档 哪里 数据库中的from关键字。关键字 哪里 关键字.Value==关键字a|| 关键字.Value==关键字B 按新关键字分组{ 关键字.DocumentId }进入g 其中g.Countp=>p.Value!=null==2 选择新的{ g、 Key.DocumentId }.Containsnew{DocumentId=Document.DocumentId} 选择文档 这将成功编译,但在运行查询时,我收到一个错误:

无法翻译LINQ表达式。以可以翻译的形式重写查询,或者通过插入对“AsEnumerable”、“asAsAsAsyncEnumerable”、“ToList”或“ToListSync”的调用显式切换到客户端计算。有关更多信息,请参阅

上述错误消息中的格式化LINQ表达式读取:

数据库集 其中k=>k.Value==KeywordA | | k.Value==KeywordB .群比 keySelector:k=>new{DocumentId=k.DocumentId}, elementSelector:k=>k .其中e=>e .Countp=>p.值!=null==2 .Selecte=>new{DocumentId=e.Key.DocumentId} .Anyp=>p==new{DocumentId=EntityShapeExpression: EntityType:文档 ValueBufferExpression: ProjectionBindingExpression:EmptyProjectionMember IsNullable:False .DocumentId} 我真的不明白这里出了什么问题。我只能想象Linqer太老了,无法生成用于EF Core 5的有效C代码

我的问题 有人能告诉我我做错了什么以及如何解决这个问题吗?例如,如何重写C查询

看起来.Containsnew{DocumentId=Document.DocumentId}部分是您的问题。将其转换为表达式时遇到问题,因为此时尚未对文档求值

如果您有FK设置,可以通过以下方式对其进行重构:

from d in db.Documents
where d.Keywords
       .Where(k => (new[] { "keyword A", "keyword B" }).Contains(k.Keyword))
       .Count() == 2
select d
试试这个:

var result =
    from Document in db.Document
    where
        (from Keyword in db.Keyword
         where
       Keyword.Value == "KeywordA" ||
       Keyword.Value == "KeywordB"
         group Keyword by Keyword.DocumentId
          into g
         where g.Count(p => p.Value != null) == 2
         select g.Key).Any(d => d == Document.DocumentId)
    select Document;

如果有两个单独的查询(一个用于关键字,一个用于文档)不是问题,那么这也应该起作用:

var matchedDocumentId=db.Keywords .Wherekeyword=>keyword.keyword==KeywordA | | keyword.keyword==KeywordB .GroupBykeyword=>keyword.DocumentID .Wheregrp=>grp.Count>2 .Selectgrp=>grp.Key; var filteredDocs=db.Documents.Wheredoc=>matchedDocumentIds.AnymatchedDocId=>matchedDocId==doc.ID;
这假设在两个表之间有一个外键。

EF核心查询转换仍然不支持许多LINQ构造,而且如果没有关于确切支持/不支持的内容的文档,所有这些都会使我们处于试验和错误路径上,因此外部工具无法生成正确的转换也就不足为奇了

在这种特殊情况下,问题是Contains call with complex argument event,尽管它是一个具有单个成员的类。因为它们只支持带有基元参数的Contains

因此,实现这一功能所需的最小变化是替换

select new
{
    g.Key.DocumentId
}).Contains(new { DocumentId = Document.DocumentId })


如果不是选择new{g.Key.DocumentId}.Contains,而是选择new{g.Key.DocumentId}.Contains。。。您尝试选择1。是否确实在我的程序中编译了此项,但它没有?似乎在select k.DocumentId中,k未知。已编辑所选语句。你可以选择汉克斯,伊万,这似乎管用。我现在得到一个错误“数据为空”。无法对空值调用此方法或属性。具体化查询时,例如在结果上调用.ToList时,请在Microsoft.Data.SqlClient.SqlBuffer.ThrowifFull处调用。因为我认为我已经检查了null,所以我不确定为什么现在会出现这种情况。这似乎也适用于这里。是的,这是一个单独的问题。即使只执行db.Document.ToList,您也应该能够获得它。您必须找到哪个文档属性被标记/使用不可为null的类型,并且在数据库中具有null值。实际上,它是一个int,应该是一个int?还有一个应该是DateTime的DateTime?。请参阅.string标记为[Required]或int?映射到int并不重要-EF不期望来自数据库的null。必须更正类类型或atribute或fluent配置,以反映数据库表列的可空性。
select g.Key.DocumentId).Contains(Document.DocumentId)