首页 > 解决方案 > 实体框架 - 检查是否有孙记录

问题描述

我正在使用 asp net core 2.0 和实体框架来访问 MySQL 数据库。我的模型结构看起来像

public class Parent 
{
   [Key]
   public int Id { get; set; }
   public virtual ICollection<Child> Child { get; set; }
   [NotMapped]
   public virtual bool HasGrandchild  { get; set; }
}

public class Child
{
   [Key]
   public int Id { get; set; }
   public int ParentId { get; set; }
   public virtual ICollection<Grandchild> Grandchild { get; set; }
}

public class Grandchild
{
   [Key]
   public int Id { get; set; }
   public int ChildId { get; set; }
}

我想查一下班上有没有孙子的记录Parent。我知道我可以使用IncludeThenInclude检索子孙。不过,Grandchild真的很大。我不想退货。或者,我可以使用for循环来计算数字Grandchild。例如,

List<Parent> p_list = _context.Parent.ToList();
foreach(Parent p in p_list) 
{
    List<Child> c_list = _context.Child
        .Where(c => c.ParentId == p.Id)
        .ToList();
    int NumberOfGrandchild = 0;
    foreach (Child c in c_list) 
    {
        List<Grandchild> gc_list = _context.Grandchild
           .Where(gc =>gc.ChildId == c.Id)
           .ToList();
        NumberOfGrandchild  += gc_list.Count();
    }
    p.HasGrandchild = false;
    if (NumberOfGrandchild > 0) {
        p.HasGrandchild = true;
    }
}

这种方法的性能很慢,尤其是对于大表。

有没有更好的方法来检查是否有孙子记录。

标签: entity-frameworkasp.net-core

解决方案


var parents = _context.Parents
                      .Where(p => p.Children.SelectMany(c => c.Grandchildren).Any());

应该给你你正在寻找的东西。您希望尽可能避免Include,因为它会将整个表的列添加到查询中。(至少 <= EF5 是这样。)

这里发生的事情是您正在生成子查询,其中最低的将获得所有Childrenparent并查看是否Child有任何Grandchild

如果你想确定 aParent是否有,Grandhildren那么你可以移动Where子句的那部分,或者只是true在一个匿名对象中。

var parents = _context.Parents
                      .Select(p => new { // Can be other DTO if you have one
                          Parent = p,
                          HasGrandchildren = p.Children
                                              .SelectMany(c => c.Grandchildren)
                                              .Any()
                      });

或者

var parents = _context.Parents
                      .Where(p => p.Children.SelectMany(c => c.Grandchildren).Any())
                      .Select(p => new {
                          Parent = p,
                          HasGrandchildren = true
                      });

第二个可能性能更高一些,因为它能够在单个查询中执行。第一个查询可能会稍微慢一些,但它也可以让您获取所有内容。

GroupBy如果您想将他们分成有孙子孙女的人和没有孙子孙女的人,还有其他方法可以做到这一点。


推荐阅读