Linq查询中的父子关系

时间:2019-02-15 05:18:03

标签: c# entity-framework linq

在实体类中

我在实体类中有两个父表“ TestParent”和“ TestTag”,并且有一个子表 在实体类中未更新的“ TestChild”。所以我可以加入TestParent和TestChild表(两者都是foreinkey主要关系)。

问题:我无法在Linq查询中选择子表TestChild

表:TestTag:

enter image description here

表:TestParent:

enter image description here

Childtable:TestChild

enter image description here

在下面的Entity类中

public DbSet<TestParent> Questions { get; set; }
  public DbSet<TestTag> Tags { get; set; }

1 个答案:

答案 0 :(得分:0)

因此,您有三个表:TestTags表,TestParents表和带有TestChildren的表。

每个TestTag的零个或多个TestChildren;每个TestChild都使用外键恰好属于一个TestTag。直接的一对多关系

每个TestParent也有零个或多个TestChildren;每个TestChild都只有一个TestParent,使用外键。

如果您遵循entity framework code first conventions,则可能会遇到类似

的情况
class TestTag
{
    public int Id {get; set;}
    ...  // other properties

    // every TestTag has zero or more TestChildren (one-to-many)
    public virtual ICollection<TestChild> TestChildren {get; set;}
}
class TestParent
{
    public int Id {get; set;}
    ...  // other properties

    // every TestParent has zero or more TestChildren (one-to-many)
    public virtual ICollection<TestChild> TestChildren {get; set;}
}
class TestChild
{
    public int Id {get; set;}
    ...  // other properties

    // every TestChild has exactly one TestParent using foreign key
    public int TestParentId {get; set;}
    public virtual TestParent TestParent {get; set;}

    // every TestChild has exactly one TestTag using foreign key
    public int TestTagId {get; set;}
    public virtual TestTag TestTag {get; set;}
}
  

在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系(一对多,多对多,...)

这样,TestTag 4和TestParent 5可以有两个子代。如果您不想要,请考虑创建组合的主键[TestTagId,TestParentId]

如果TestChild除了外键之外没有其他属性,那么实际上您将在TestTag和TestParent之间创建多对多关系。在这种情况下,您不必提及TestChild表。

出于完整性考虑,DbContext:

class MyDbContext : DbContext
{
     public DbSet<TestTag> TestTags {get; set;}
     public DbSet<TestParent> TestParents {get; set;}
     public DbSet<TestChild> TestChildren {get; set;}
}

这是实体框架要检测您的关系以及主键和外键所需要知道的全部内容。因为遵循了约定的属性,所以也不需要流利的API,除非是由于非标准的复数形式Children

  

我可以加入TestParent和TestChild表

您可以进行(group-)联接,但是通常更容易使用ICollections

将...的TestParent和所有的TestChildren和TestTag一起给我。

var result = dbContext.TestParents
    .Where(parent => ...)             // if you don't want all testParents
    .Select(parent => new
    {
        // select only the properties you plan to use
        Id = parent.Id,
        Name = parent.Name,

        Children = parent.TestChildren
            .Where(child => child.TestTag.Name = "My Test Tag Name")
            .Select(child => new
            {
                Name = child.TestTag.Name,
                ...
            })
            .ToList(),
    });

有些人更喜欢使用GroupJoin。如果您希望这样做,并且可以说服项目负责人说,与使用ICollections相比,GroupJoin具有更好的可读性/可测试性/可维护性,则可以执行以下操作:

var result = dbContext.TestParents.GroupJoin(dbContext.TestChildren,
    parent => parent.Id,                // from each parent take the Id
    child => child.ParentId,            // from each child take the ParentId

    // resultSelector:
    (parent, children) => new
    {
        // Parent Properties:
        Id = parent.Id,
        ...

        // GroupJoin the collection of child properties with the TestTags:
        children.GroupJoin(dbContext.TestTags,
        child => child.TestTagId,          // from each TestChild take the TestTagId
        tag => tag.Id,                     // from each TestTag take the Id
        (child, tagsOfThisChild) => new
        {
            // desired Child properties
            ...

            TestTags = tagsOfThisChild.Select(tag => new
            {
                 Id = tag.Id,
                 ...
            })
            .ToList(),
        })
        .ToList(),
    });

恕我直言:这看起来太可怕了!