如何使用实体框架和Linq创建此查询

本文关键字:创建 查询 Linq 何使用 实体 框架 | 更新日期: 2023-09-27 18:09:17

在使用LinqKit的LinqPad中,我正在做以下操作:

var topPredicate = PredicateBuilder.True<LandRecord>();
topPredicate = topPredicate.And(a=>a.InstrumentType == "DEED");
topPredicate = topPredicate.And(a=>a.BookType == "OFFICIAL RECORD");
var subPredicate = PredicateBuilder.True<LandRecord>();
subPredicate = subPredicate.And(a=>a.Parties.Any(b=>b.LastName == "SMITH"));
subPredicate = subPredicate.And(a=>a.Parties.Any(b=>b.FirstName == "John"));
LandRecords.AsExpandable().Include(a=>a.Parties).Where(topPredicate).Where(subPredicate).ToList();

这是它正在创建的SQL:

SELECT 
    [Extent1].[LandRecordID] AS [LandRecordID], 
    [Extent1].[DocumentID] AS [DocumentID], 
    [Extent1].[InstrumentNo] AS [InstrumentNo], 
    [Extent1].[BookType] AS [BookType], 
    [Extent1].[BookNo] AS [BookNo], 
    [Extent1].[PageNo] AS [PageNo], 
    [Extent1].[DateFiled] AS [DateFiled], 
    [Extent1].[DateInstrument] AS [DateInstrument], 
    [Extent1].[InstrumentType] AS [InstrumentType], 
    [Extent1].[MortgageAmount] AS [MortgageAmount]
    FROM [LAND].[LandRecord] AS [Extent1]
    WHERE (N'DEED' = [Extent1].[InstrumentType]) AND (N'OFFICIAL RECORD' = [Extent1].[BookType]) AND ( EXISTS (SELECT 
        1 AS [C1]
        FROM [LAND].[Party] AS [Extent2]
        WHERE ([Extent1].[LandRecordID] = [Extent2].[LandRecordID]) AND (N'SMITH' = [Extent2].[LastName])
    )) AND ( EXISTS (SELECT 
        1 AS [C1]
        FROM [LAND].[Party] AS [Extent3]
        WHERE ([Extent1].[LandRecordID] = [Extent3].[LandRecordID]) AND (N'John' = [Extent3].[FirstName])
    ))

我想让它创建的SQL将如下所示,其中LastName和FirstName将在同一个exists语句中组合/连接。

在生产环境中,该子查询可以包含1个或多个条件,每个条件都是start with、end with、contains或精确匹配。所以我需要能够手动构建子查询1块在一个时间。

SELECT 
    [Extent1].[LandRecordID] AS [LandRecordID], 
    [Extent1].[DocumentID] AS [DocumentID], 
    [Extent1].[InstrumentNo] AS [InstrumentNo], 
    [Extent1].[BookType] AS [BookType], 
    [Extent1].[BookNo] AS [BookNo], 
    [Extent1].[PageNo] AS [PageNo], 
    [Extent1].[DateFiled] AS [DateFiled], 
    [Extent1].[DateInstrument] AS [DateInstrument], 
    [Extent1].[InstrumentType] AS [InstrumentType], 
    [Extent1].[MortgageAmount] AS [MortgageAmount]
    FROM [LAND].[LandRecord] AS [Extent1]
    WHERE (N'DEED' = [Extent1].[InstrumentType]) AND (N'OFFICIAL RECORD' = [Extent1].[BookType]) AND ( EXISTS (SELECT 
        1 AS [C1]
        FROM [LAND].[Party] AS [Extent2]
        WHERE ([Extent1].[LandRecordID] = [Extent2].[LandRecordID]) AND (N'SMITH' = [Extent2].[LastName] AND (N'John' = [Extent2].[FirstName])
    ))

如何使用实体框架和Linq创建此查询

您可以单独构建子谓词,如果它包含任何内容,则将其添加到顶部谓词:

var topPredicate = PredicateBuilder.True<LandRecord>();
topPredicate = topPredicate.And(a=>a.InstrumentType == "DEED");
topPredicate = topPredicate.And(a=>a.BookType == "OFFICIAL RECORD");
var subPredicate = PredicateBuilder.True<Party>();
if (!string.IsNullOrWhiteSpace(firstName)
{
    subPredicate = subPredicate.And(b => b.FirstName == firstName);
}
if (!string.IsNullOrWhiteSpace(lastName)
{
    subPredicate = subPredicate.And(b => b.LastName == lastName);
}
// If the subPredicate's body is still just PredicateBuilder.True<Party>(), ignore it.
if (!(subPredicate.Body is ConstantExpression))
{
    topPredicate = topPredicate.And(lr => lr.Parties.AsQueryable().Any(subPredicate));
}

这里使用lr.Parties.AsQueryable(),因为Parties可能是ICollection,即IEnumerable。由于IEnumerable.Any接受Func,而不是Expression,如果没有AsQueryable(),代码将无法编译。

顺便说一下,我的代码不包含AsExpandable(),因为我使用通用谓词生成器。