本质上,我想获取具有相关实体 B 的所有 A 的计数。以及按实体 A 的属性分组的所有不具有相关实体 B 的实体 A 的计数。
当我查询所有 A 包括相关的 B 时,我设法得到了我需要的东西。
但是如果这可以在数据库上完成,那就太好了,因为我不想查询这么多不需要的数据。
这是我的工作疑问:
var groupedMappings = await _spContext.MappingTargets.AsNoTracking()
.Include(x => x.PrinterMappings)
.GroupBy(target => target.Type)
.Select(group => new
{
Type = group.Key,
Targets = group.ToList()
})
.ToListAsync(ct);
var counts = groupedMappings.Select(group =>
new DashboardMappingTargetDto(
group.Type,
group.Targets.Count,
group.Targets.Count(target => target.PrinterMappings.Any()),
group.Targets.Count(target => !target.PrinterMappings.Any())
)).ToList();
结果应该是模型:
public record DashboardMappingTargetDto(int Type, int TotalCount, int CountWithMapping, int CountWithoutMapping);
我尝试了很多方法来组合它们,但没有成功:
var counts2 = await _spContext.MappingTargets.AsNoTracking()
.GroupBy(target => target.Type)
.Select(group => new DashboardMappingTargetDto(
group.Key,
group.Count(),
group.Sum(target => target.PrinterMappings.Any() ? 1 : 0),
group.Sum(target => !target.PrinterMappings.Any() ? 1 : 0)
))
.ToListAsync(ct);
无法对包含聚合或子查询的表达式执行聚合函数。
如果这不能在 ef 中完成,我也会对原始 sql 查询感兴趣,它可以作为最后的手段来完成工作。
控制台示例:
namespace ConsoleApp3
{
public class MappingTarget
{
public int Id { get; set; }
public string Name { get; set; }
public int Type { get; set; }
public List<PrinterMapping> PrinterMappings { get; set; } = new List<PrinterMapping>();
}
public record DashboardMappingTargetDto(int Type, int TotalCount, int CountWithMapping, int CountWithoutMapping);
public class PrinterMapping
{
public int Id { get; set; }
public int MappingTargetId { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
//Setup
var MappingTargets = new List<MappingTarget>
{
new MappingTarget
{
Id = 1, Name = "I have 2 pm", Type = 1, PrinterMappings = new List<PrinterMapping>
{
new PrinterMapping {Id = 1, MappingTargetId = 1},
new PrinterMapping {Id = 2, MappingTargetId = 1}
}
},
new MappingTarget {Id = 2, Name = "I have 0 pm", Type = 1},
new MappingTarget
{
Id = 3, Name = "I have 1 pm", Type = 2, PrinterMappings = new List<PrinterMapping>
{
new PrinterMapping {Id = 3, MappingTargetId = 3}
}
},
new MappingTarget
{
Id = 4, Name = "I have 1 pm", Type = 2, PrinterMappings = new List<PrinterMapping>
{
new PrinterMapping {Id = 4, MappingTargetId = 4}
}
},
new MappingTarget {Id = 5, Name = "I have 0 pm", Type = 3},
};
//New Query
var groupedMappings =
from mt in MappingTargets
from pm in mt.PrinterMappings
group mt by new { mt.Id, mt.Type } into g
select new
{
g.Key.Type,
MappingsCount = g.Count()
} into s
group s by new { s.Type } into g
select new DashboardMappingTargetDto
(
g.Key.Type,
g.Sum(x => x.MappingsCount),
g.Sum(x => x.MappingsCount > 0 ? 1 : 0),
g.Sum(x => x.MappingsCount == 0 ? 1 : 0)
);
foreach (var g in groupedMappings)
{
Console.Write($"total:{g.TotalCount} ");
Console.Write($"WithPm:{g.CountWithMapping} ");
Console.Write($"NoPm:{g.CountWithoutMapping} ");
Console.Write($"Type:{g.Type} ");
Console.WriteLine("");
}
//OldQuery
var groupedMappingsOld = MappingTargets
.GroupBy(target => target.Type)
.Select(group => new
{
Type = group.Key,
Targets = group.ToList()
})
.ToList();
var counts = groupedMappingsOld.Select(group =>
new DashboardMappingTargetDto(
group.Type,
group.Targets.Count,
group.Targets.Count(target => target.PrinterMappings.Any()),
group.Targets.Count(target => !target.PrinterMappings.Any())
)).ToList();
Console.WriteLine("Before");
foreach (var g in counts)
{
Console.Write($"total:{g.TotalCount} ");
Console.Write($"WithPm:{g.CountWithMapping} ");
Console.Write($"NoPm:{g.CountWithoutMapping} ");
Console.Write($"Type:{g.Type} ");
Console.WriteLine("");
}
}
}
}
尝试以下查询:
var byTebnat =
from mt in _spContext.MappingTargets
from pm in mt.PrinterMappings
group mt by new { mt.Id, mt.Type } into g
select new
{
g.Key.Type,
MappingsCount = g.Count()
};
var groupedMappings =
from mt in _spContext.MappingTargets
from bt in byTebnat
.Where(bt => bt.Id == mt.Id)
.DefaultIFMepty()
group new { MappingsCount = (int?)bt.MappingsCount ?? 0 } by new { mt.Type } into g
select new DashboardMappingTargetDto
(
g.Key.Type,
g.Sum(x => x.MappingsCount),
g.Sum(x => x.MappingsCount > 0 ? 1 : 0),
g.Sum(x => x.MappingsCount == 0 ? 1 : 0)
);
旁注。如果末尾有
AsNoTracking
,请勿使用 Include
、Select
。