[英]LINQ double INNER JOIN on query translation when using selectMany
我有以下 LINQ 声明:
var repoActivityRowsTest = appManager.GetRepository<ActivityRow>();
var activityRowsTest = await repoActivityRowsTest.Search(f => f.ExcelReport.uploadPhase == RPToolConstants.Phase_Planning, includeProperties: "PlanningInfo")
.Where(f => iso3Alpha3List.Contains(f.ExcelReport.countryOfficeIso3Alpha3))
.SelectMany(sm => sm.PlanningInfo).Select(s => new { s.Year, s.Count, s.ActivityRow.UnitCost })
.GroupBy(g=>new { g.Year }).Select(sg=>new { sg.Key.Year, Total = sg.Sum(sum => sum.UnitCost * sum.Count) })
.ToListAsync();
它使用存储库模式。 搜索 function 是下面这个:
public IQueryable<TEntity> Search(Expression<Func<TEntity, bool>> filter = null,
string includeProperties = "", bool trackChanges = false)
{
IQueryable<TEntity> query = context.Set<TEntity>();
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty.Trim());
}
if (!trackChanges)
{
query = query.AsNoTracking();
}
return query;
}
当我检查到达 SQL 服务器的命令时,我看到查询在以下 SQL 中翻译:
SELECT [a0].[Year], SUM([a1].[UnitCost] * CAST([a0].[Count] AS decimal(18,2))) AS [Total]
FROM [ActivityRows] AS [a]
INNER JOIN [ExcelReports] AS [e] ON [a].[ExcelReportId] = [e].[Id]
INNER JOIN [ActivityRowPlanningInfo] AS [a0] ON [a].[Id] = [a0].[ActivityRowId]
INNER JOIN [ActivityRows] AS [a1] ON [a0].[ActivityRowId] = [a1].[Id]
WHERE ([e].[uploadPhase] = N'planning')
AND [e].[countryOfficeIso3Alpha3] IN (N'AFG', N'DZA', N'AGO', N'ARM', N'BGD')
GROUP BY [a0].[Year]
它工作得很好,但为什么有一个重复的内部连接:
INNER JOIN [ActivityRows] AS [a1] ON [a0].[ActivityRowId] = [a1].[Id]
对我来说是无意义的!
如果我从 SQL 中删除它,它会像以前一样工作。 我的 LINQ 查询中是否有任何问题导致这个奇怪的 SQL?
这是实体的定义:
public class ActivityRow : Entity<int>
{
public string Description { get; set; }
public int ExcelReportId { get; set; }
[ForeignKey("ExcelReportId")]
public virtual ExcelReport ExcelReport { get; set; }
public int ActivitySubTypeId { get; set; }
[ForeignKey("ActivitySubTypeId")]
public virtual ActivitySubType ActivitySubType { get; set; }
public int? ActivityCategoryId { get; set; }
[ForeignKey("ActivityCategoryId")]
public virtual ActivityCategory ActivityCategory { get; set; }
public string ResponsibleEntity { get; set; }
[Column(TypeName = "decimal(18,2)")]
public decimal UnitCost { get; set; }
public string Notes { get; set; }
public virtual ICollection<ActivityRowReportingInfo> ReportingInfo { get; set; }
public virtual ICollection<ActivityRowPlanningInfo> PlanningInfo { get; set; }
}
public class ActivityRowPlanningInfo : Entity<int>
{
public int ActivityRowId { get; set; }
[ForeignKey("ActivityRowId")]
public virtual ActivityRow ActivityRow { get; set; }
public int Year { get; set; }
public int Quarter { get; set; }
public int Count { get; set; }
}
这里定义了与 fluent API 的关系:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//activities
modelBuilder.Entity<ActivityRow>()
.HasMany(b => b.ReportingInfo)
.WithOne(t => t.ActivityRow)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ActivityRow>()
.HasMany(b => b.PlanningInfo)
.WithOne(t => t.ActivityRow)
.OnDelete(DeleteBehavior.Cascade);
...etc.
}
通过 LINQ 查询语法重写查询,您可以轻松简化查询。 以下查询不会创建不需要的联接:
var repoActivityRowsTest = appManager.GetRepository<ActivityRow>();
var activityRows = repoActivityRowsTest
.Search(f => true);
var resultQuery =
from ar in activityRows
where
ar.ExcelReport.uploadPhase == RPToolConstants.Phase_Planning
&& iso3Alpha3List.Contains(ar.ExcelReport.countryOfficeIso3Alpha3)
from pi in ar.PlanningInfo
group new { ar, pi } by new { pi.Year } into g
select new
{
g.Key.Year,
Total = g.Sum(x => x.ar.UnitCost * x.pi.Count)
};
var result = await resultQuery.ToListAsync();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.