EFCore 分组嵌套列表

huangapple go评论136阅读模式
英文:

EFCore GroupBy nested List

问题

我有以下的实体:

public class CounterOwner
{
    public int Id { get; set; }
    public string Name { get; set; } = null!;
    public ICollection<CounterEntry> CounterEntries { get; set; } = new List<CounterEntry>();
}

public class CounterEntry
{
    public int Id { get; set; }
    public DateTime DateTime { get; set; } = DateTime.Now;
    public double Heating { get; set; }
    public double WaterCounter1 { get; set; }
    public double WaterCounter2 { get; set; }
    public double WaterCounter3 { get; set; }
    public double WaterCounter4 { get; set; }
    public CounterOwner CounterOwner { get; set; } = null!;
    public int CounterOwnerId { get; set; }
}

还有在我的ApplicationDbContext中:

...
 public DbSet<CounterOwner> CounterOwners => Set<CounterOwner>();
...

我想要通过CounterOwner.Name进行过滤,然后按天对CounterEntry进行分组,并计算组中最后一项和第一项之间的差异以获得每日金额。我可以将所有内容加载到内存中,但我想让数据库处理。在SQL中可以实现这一点。

基本上我想要一些代码,最终可能会得到一个匿名对象,其等效的SQL将是GroupBy和类似MAX()的聚合的组合。

如何使用EFCore实现这个?

英文:

I have the following Entities:

public class CounterOwner
{
    public int Id { get; set; }
    public string Name { get; set; } = null!;
    public ICollection<CounterEntry> CounterEntries { get; set; } = new List<CounterEntry>();
}

public class CounterEntry
{
    public int Id { get; set; }
    public DateTime DateTime { get; set; } = DateTime.Now;
    public double Heating { get; set; }
    public double WaterCounter1 { get; set; }
    public double WaterCounter2 { get; set; }
    public double WaterCounter3 { get; set; }
    public double WaterCounter4 { get; set; }
    public CounterOwner CounterOwner { get; set; } = null!;
    public int CounterOwnerId { get; set; }
}

And the following in my ApplicationDbContext

...
 public DbSet<CounterOwner> CounterOwners => Set<CounterOwner>();
...

I want to filter by CounterOwner.Name and then group CounterEntry by day and calculate the difference between the last and first entry in the group to get the 'daily' amount. I could just load everything into memory, but I want the database to do the work. In SQL this is achievable.

Basically I want some code that results possibly in an anonymous object where the equivalent SQL would be a combination of GroupBy and an aggregate like MAX()

How do I do it with EFCore?

答案1

得分: 2

你可以使用 SelectMany 来展平一对多的关系:

var result = context.CounterOwners
    .Where(o => o.Name == "Doe")
    .SelectMany(o => o.CounterEntries)
    .GroupBy(e => e.DateTime.Date)
    .Select(g => new {
        Day = g.Key,
        Amount1 = g.Max(e => e.WaterCounter1) - g.Min(e => e.WaterCounter1),
        Amount2 = g.Max(e => e.WaterCounter2) - g.Min(e => e.WaterCounter2),
        Amount3 = g.Max(e => e.WaterCounter3) - g.Min(e => e.WaterCounter3),
        Amount4 = g.Max(e => e.WaterCounter4) - g.Min(e => e.WaterCounter4)
    });
英文:

You can use SelectMany to flatten the one to many relationship:

var result = context.CounterOwners
    .Where(o => o.Name == "Doe")
    .SelectMany(o => o.CounterEntries)
    .GroupBy(e => e.DateTime.Date)
    .Select(g => new {
        Day = g.Key,
        Amount1 = g.Max(e => e.WaterCounter1) - g.Min(e.WaterCounter1),
        Amount2 = g.Max(e => e.WaterCounter2) - g.Min(e.WaterCounter2),
        Amount3 = g.Max(e => e.WaterCounter3) - g.Min(e.WaterCounter3),
        Amount4 = g.Max(e => e.WaterCounter4) - g.Min(e.WaterCounter4)
    });

答案2

得分: -1

这是模拟你的实体数据库。

英文:

This is a simulatation of you entity database

<!-- begin snippet: js hide: false console: true babel: false -->

namespace ConsoleApplication52
{
    class Program
    {
        static void Main(string[] args)
        {
            Context db = new Context();

            var results = db.CounterOwner
                .Select(x =&gt; new {id = x.Id, name = x.Name, first = x.CounterEntries.OrderBy(y =&gt; y.DateTime).First(), last = x.CounterEntries.OrderBy(y =&gt; y.DateTime).Last()})
                .Select(x =&gt; new {
                    id = x.id, 
                    name = x.name,
                    heating = x.last.Heating - x.first.Heating,
                    waterCount1 = x.last.WaterCounter1 = x.first.WaterCounter1,
                    waterCount2 = x.last.WaterCounter2 = x.first.WaterCounter2,
                    waterCount3 = x.last.WaterCounter3 = x.first.WaterCounter3,
                    waterCount4 = x.last.WaterCounter4 = x.first.WaterCounter4,
                    }).ToList();

 
        }
    }
    public class Context
    {
        public List&lt;CounterOwner&gt; CounterOwner { get;set;} 
        public List&lt;CounterEntry&gt; CounterEntry { get;set;} 
    }

    public class CounterOwner
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public ICollection&lt;CounterEntry&gt; CounterEntries { get; set; } = new List&lt;CounterEntry&gt;();
    }

    public class CounterEntry
    {
        public int Id { get; set; }
        public DateTime DateTime { get; set; }
        public double Heating { get; set; }
        public double WaterCounter1 { get; set; }
        public double WaterCounter2 { get; set; }
        public double WaterCounter3 { get; set; }
        public double WaterCounter4 { get; set; }
        public CounterOwner CounterOwner { get; set;}
        public int CounterOwnerId { get; set; }
    }

}

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年3月20日 23:08:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75792007.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定