计算按属性分组的相关和不相关实体

问题描述 投票:0回答:1

本质上,我想获取具有相关实体 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("");
        }
    }
}
}
c# entity-framework-core
1个回答
1
投票

尝试以下查询:

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

© www.soinside.com 2019 - 2024. All rights reserved.