使用 Lambda 表达式在 LINQ 中执行 1 对 1 左外连接
Performing 1-to-1 Left Outer Join in LINQ using Lambda expression
我有以下 LINQ 查询:
dbContext.NAVSummaries
.Join(dbContext.NAVSummaries.DefaultIfEmpty(),
current => new
{
current.Portfolio,
PD = SqlFunctions.DatePart("dw", current.ValueDate) == 2 ? DbFunctions.AddDays(current.ValueDate, -3).Value :
SqlFunctions.DatePart("dw", current.ValueDate) == 1 ? DbFunctions.AddDays(current.ValueDate, -2).Value :
DbFunctions.AddDays(current.ValueDate, -1).Value
},
previous => previous == null ? null : new { previous.Portfolio, PD = previous.ValueDate },
(outer, inner) => new { outer, inner }
)
.Where(n => !dateStart.HasValue || n.outer.ValueDate.CompareTo(dateStart.Value) >= 0)
.Where(n => !dateEnd.HasValue || n.outer.ValueDate.CompareTo(dateEnd.Value) <= 0)
给定的 ValueDate 有 x 条记录,在其上一个营业日期有 x-1 条记录。 NAVSummaries DbSet 在 ValueDate 列上自联接,ValueDate 项目与其先前的业务日期相匹配。但是,输出结果的计数仅为 x-1。我希望执行左外连接,以便返回左侧 table/collection 的所有 x 记录。
编辑: 只有一个 record/item 与上一个营业日期匹配。所以它必须是一种一对一映射。
NavSummary 实体:
public class NAVSummary
{
[Key, Column(Order = 0)]
public string Portfolio { get; set; }
[Key, Column(Order = 2)]
public DateTime ValueDate { get; set; }
public decimal BackOfficeNAV { get; set; }
public decimal FrontOfficeNAV { get; set; }
public decimal DifferencePercent { get; set; }
public decimal Threshold { get; set; }
public int ExtractId { get; set; }
public string ExtractStatus { get; set; }
public string PortfolioOwner { get; set; }
public DateTime DateTimeModified { get; set; }
public int MostCorrectNAV { get; set; }
public virtual IList<NAVComment> Comments { get; set; }
public virtual IList<NAVStatus> Statuses { get; set; }
public virtual IList<NAVExtract> Extracts { get; set; }
[JsonIgnore]
[NotMapped]
public bool IsChange { get; set; }
[NotMapped]
public decimal DayOverDayChange { get; set; }
[JsonIgnore]
[NotMapped]
public DateTime PreviousValueDate { get; set; }
[JsonIgnore]
[NotMapped]
public decimal PreviousDP { get; set; }
}
在处理包括联接、分组依据等复杂查询时,我建议您对大部分部分使用 LINQ 查询语法,因为透明标识符和 let
表达式使它更自然、更易读.此处描述了不同类型的连接 join clause (C# Reference).
这是您使用查询语法进行的查询:
var query =
from current in db.NAVSummaries
let currentWD = SqlFunctions.DatePart("dw", current.ValueDate)
let currentPD = DbFunctions.AddDays(current.ValueDate, currentWD == 2 ? -3 : currentWD == 1 ? -2 : -1).Value
join previous in db.NAVSummaries
on new { current.Portfolio, PD = currentPD }
equals new { previous.Portfolio, PD = previous.ValueDate }
into previousGroup
from previous in previousGroup.DefaultIfEmpty() // LEFT OUTER JOIN
select new { outer = current, inner = previous };
if (dateStart.HasValue)
query = query.Where(e => e.outer.ValueDate >= dateStart.Value);
if (dateEnd.HasValue)
query = query.Where(e => e.outer.ValueDate <= dateEnd.Value);
我有以下 LINQ 查询:
dbContext.NAVSummaries
.Join(dbContext.NAVSummaries.DefaultIfEmpty(),
current => new
{
current.Portfolio,
PD = SqlFunctions.DatePart("dw", current.ValueDate) == 2 ? DbFunctions.AddDays(current.ValueDate, -3).Value :
SqlFunctions.DatePart("dw", current.ValueDate) == 1 ? DbFunctions.AddDays(current.ValueDate, -2).Value :
DbFunctions.AddDays(current.ValueDate, -1).Value
},
previous => previous == null ? null : new { previous.Portfolio, PD = previous.ValueDate },
(outer, inner) => new { outer, inner }
)
.Where(n => !dateStart.HasValue || n.outer.ValueDate.CompareTo(dateStart.Value) >= 0)
.Where(n => !dateEnd.HasValue || n.outer.ValueDate.CompareTo(dateEnd.Value) <= 0)
给定的 ValueDate 有 x 条记录,在其上一个营业日期有 x-1 条记录。 NAVSummaries DbSet 在 ValueDate 列上自联接,ValueDate 项目与其先前的业务日期相匹配。但是,输出结果的计数仅为 x-1。我希望执行左外连接,以便返回左侧 table/collection 的所有 x 记录。
编辑: 只有一个 record/item 与上一个营业日期匹配。所以它必须是一种一对一映射。
NavSummary 实体:
public class NAVSummary
{
[Key, Column(Order = 0)]
public string Portfolio { get; set; }
[Key, Column(Order = 2)]
public DateTime ValueDate { get; set; }
public decimal BackOfficeNAV { get; set; }
public decimal FrontOfficeNAV { get; set; }
public decimal DifferencePercent { get; set; }
public decimal Threshold { get; set; }
public int ExtractId { get; set; }
public string ExtractStatus { get; set; }
public string PortfolioOwner { get; set; }
public DateTime DateTimeModified { get; set; }
public int MostCorrectNAV { get; set; }
public virtual IList<NAVComment> Comments { get; set; }
public virtual IList<NAVStatus> Statuses { get; set; }
public virtual IList<NAVExtract> Extracts { get; set; }
[JsonIgnore]
[NotMapped]
public bool IsChange { get; set; }
[NotMapped]
public decimal DayOverDayChange { get; set; }
[JsonIgnore]
[NotMapped]
public DateTime PreviousValueDate { get; set; }
[JsonIgnore]
[NotMapped]
public decimal PreviousDP { get; set; }
}
在处理包括联接、分组依据等复杂查询时,我建议您对大部分部分使用 LINQ 查询语法,因为透明标识符和 let
表达式使它更自然、更易读.此处描述了不同类型的连接 join clause (C# Reference).
这是您使用查询语法进行的查询:
var query =
from current in db.NAVSummaries
let currentWD = SqlFunctions.DatePart("dw", current.ValueDate)
let currentPD = DbFunctions.AddDays(current.ValueDate, currentWD == 2 ? -3 : currentWD == 1 ? -2 : -1).Value
join previous in db.NAVSummaries
on new { current.Portfolio, PD = currentPD }
equals new { previous.Portfolio, PD = previous.ValueDate }
into previousGroup
from previous in previousGroup.DefaultIfEmpty() // LEFT OUTER JOIN
select new { outer = current, inner = previous };
if (dateStart.HasValue)
query = query.Where(e => e.outer.ValueDate >= dateStart.Value);
if (dateEnd.HasValue)
query = query.Where(e => e.outer.ValueDate <= dateEnd.Value);