【问题标题】:EF Core 1.0: How to query a whole tree?EF Core 1.0:如何查询整棵树?
【发布时间】:2016-04-08 07:09:05
【问题描述】:

我正在使用 EF 7.0.0.0-rc1-final。

我有一个树结构,其中包含从 GrandGrandParent 到 GrandParent 到 Parent 到 Child 的一对多关系:

public class GrandGrandParent
{
    public int ID { get; set; }
    public string Name { get; set; }

    public virtual List<GrandParent> GrandParents { get; set; }

    public GrandGrandParent()
    {
        this.GrandParents = new List<GrandParent>();
    }
}

public class GrandParent
{
    public int ID { get; set; }
    public string Name { get; set; }

    public virtual GrandGrandParent GrandGrandParent { get; set; }
    public virtual List<Parent> Parents { get; set; }

    public GrandParent()
    {
        this.Parents = new List<Parent>();
    }
}

public class Parent
{
    public int ID { get; set; }
    public string Name { get; set; }

    public virtual GrandParent GrandParent { get; set; }
    public virtual List<Child> Children { get; set; }

    public Parent()
    {
        this.Children = new List<Child>();
    }
}

public class Child
{
    public int ID { get; set; }
    public string Name { get; set; }

    public virtual Parent Parent { get; set; }
}

使用 EF Core 1.0 (EF 7),我如何创建一个 LINQ 查询(或带有子查询),给我整个树,给定一个特定的祖祖父母 ID?

我可以 .Include() 向上或向下一级,也许我对显而易见的事情视而不见?这给了我 GrandGrandParent 和 GrandParents 列表:

var ggparent1 = from ggp in myDbContext.GrandGrandParent
                .Include(ggp => ggp.GrandParents)
                where ggp.ID == 2
                select ggp;

我想得到整棵树,一直到孩子的列表。我必须求助于编写 foreach() 循环并手动构建树吗?

【问题讨论】:

  • 您的数据库是如何设计的?你有4张桌子,2张还是1张?尽管您的层次结构很奇怪,但表的数量可以指导我们为您提供帮助(尤其是包含和连接)
  • 有4张桌子,每个班级一张。选择层次结构以通用方式显示我的问题,因此读者也不必费心学习业务逻辑。我尝试了以下 LINQ 的变体: var gparents = from gp in myDbContext.GrandParent .Include(gparent => gparent.GrandGrandParent) .Include(gparent => gparent.Parents) .ThenInclude(children => children.Select(child = > child.ID)) 其中 gp.GrandGrandParent.ID == 2 选择 gp;但是 .ThenInclude 总是抛出异常。
  • 有什么异常?
  • System.ArgumentException:属性表达式 'children => {from Parent child in children select [child].ID}' 无效。该表达式应表示属性访问:'t => t.MyProperty'。指定多个属性时使用匿名类型:'t => new { t.MyProperty1, t.MyProperty2 }'。
  • 我的测试应用程序:http://pastebin.com/b2tWS7LC 和上面的 EF 类。

标签: c# linq tree entity-framework-core


【解决方案1】:

我只会使用 Linq 表单:

private static void Test0(ApplicationDbContext myDbContext)
{
    var ggparent = myDbContext.GrandGrandParents
        .Include(ggp => ggp.GrandParents)
        .ThenInclude(gp => gp.Parents)
        .ThenInclude(p => p.Children)
        .FirstOrDefault(ggp => ggp.ID == 3);

    if (ggparent == null)
    {
        DebugPrint("GrandGrandParent not found");
        return;
    }

    DebugPrint("GrandGrandParent:");
    DebugPrint(ggparent);


    if (ggparent.GrandParents == null)
    {
        DebugPrint("GrandParents null");
        return;
    }

    foreach (var gparent in ggparent.GrandParents)
    {
        DebugPrint(gparent);
        if (gparent.Parents == null) continue;
        foreach (var parent in gparent.Parents)
        {
            DebugPrint(parent);
            if (parent.Children == null) continue;
            foreach (var child in parent.Children)
            {
                DebugPrint(child);
            }
        }
    }

    int changeCount = myDbContext.SaveChanges();
    DebugPrint(string.Format("ChangeCount={0}", changeCount));
}

那么您不必自己进行子查询。但您可以添加日志记录以查看 EF 实际创建的 SQL 查询。

如果您需要完整的树,则不需要select。您可以使用 select 提取结果树的一部分或从层次结构中构建一个新的(平面)对象。

我将一个只有两个级别(多对多)的层次结构展平以获取分组 SelectList 的项目的示例:

var result =
    (from c in dbContext.EventTypes
    join j in dbContext.EventType2EventTypes on c.Id equals j.ChildEventTypeId
    join p in dbContext.EventTypes on j.ParentEventTypeId equals p.Id
    where p.EventTypeLevel == EventTypeLevel.First && c.EventTypeLevel == EventTypeLevel.Second
    orderby p.SortOrder, p.Id, c.SortOrder, c.Id
    select new SelectListItem
    {
        Text = c.NameDe,
        Value = c.Id.ToString(),
        Group = GetParentEventTypeSelectListGroup(p.NameDe)
    }).AsNoTracking();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 2022-01-14
    • 1970-01-01
    • 2020-03-29
    • 2020-05-08
    • 2017-03-28
    相关资源
    最近更新 更多