使用EF在连接表中获取与其订单的多对多关系的记录?

时间:2017-10-17 11:25:14

标签: c# entity-framework linq

我有一个与T1有多对多关系的表T2,加入表为T12,我希望从T2获取相关记录, Id中记录的T1,使用EF和LINQ,我这样做:

var listIds = oContext.T12.Where(x => x.T1Id == id).Select(x => x.T2Id).ToList(); 
//then 
var theList = oContext.T2.In(x => x.Id, listIds).ToList(); 

In的实施。

我不认为这是从m-t-m关系查询数据的最佳方式。 但真正的问题是来自T2的记录不是出现在SQL中的顺序(应用程序中的顺序问题):

enter image description here

但他们的订单是T2Id:58478,58479,58480,58481

修改

我使用OrderBy按顺序获取listIds,但列表仍未按顺序排列,我访问了SSMS,并进行了查询:

SELECT* FROM T2 WHERE Id IN(58481, 58478, 58479, 58480)

这就是结果:

enter image description here

1 个答案:

答案 0 :(得分:2)

你的直觉是正确的,这不是最好的方式。如果您正确地在Entity Framework中设置多对多关系,则不必提及联接表T12

请参阅Configure Many To Many

调整到您的班级:

class T1
{
    public int Id {get; set;}

    // every T1 has zero or more T2
    public virtual ICollection<T2> T2s {get; set;}

    // other properties
    public int A {get; set;}
    public string B {get; set;}
}

class T2
{
    public int Id {get; set;}

    // every T2 has zero or more T1
    public virtual ICollection<T1> T1s {get; set;}

    // other properties
    public int C {get; set;}
    public string D {get; set;}
}

public MyDbContext : DbContext
{
    public DbSet<T1> T1s {get; set;}
    public DbSet<T2> T2s {get; set;}
}

就是这样!实体框架将认识到您正在建模T1和T2之间的多对多关系,并为您创建额外的数据库表。

在你的linq查询中,你不需要这个额外的表。当您访问集合时,Linq将创建连接。

“给我所有的T1,其中属性X == ......所有的T2属性Y == ......”

using (var myDbContext = new MyDbContext)
{
    var result = myDbContext.T1s
        .Where(t1 => t1.X == ...)
        .Select(t1 = new
        {
            // select the T1 properties you want
            A = t1.A,
            B = t1.B,
            // a T1 has zero or more T2s
            // select the T2s you want:
            T2s = t1.T2s
                .Where(t2 => t2.Y == ....)
                .Select(t2 => new
                {   // Take the T2 properties you want
                    C = t2.C,
                    D = T2.D,
                }),
        });
}

你也可以从T2开始:

var result = myDbContext.T2s
        .Where(t2 => t2.Y == ...)
        .Select(t1 = new
        {
            // select the T1 properties you want
            C = t2.C,
            D = t2.C,
            // a T2 has zero or more T1s
            // select the T1s you want:
            T1s = t2.T1s
                .Where(t1 => t1.Y == ....)
                .Select(t1 => new
                {   // Take the T1 properties you want
                    A = t1.A,
                    B = T2.B,
                }),
        });

因为您访问多对多中的集合属性,所以Entity Framework知道必须执行与额外创建的多对多表的连接。

结果类似于GroupJoin。如果您想要它未分组,更像是真正的联接,您需要SelectMany

var result = MyDbContext.T1s.SelectMany(t1 => t1.T2s
    .Select(t2 => new
    {
        A = t1.A,
        B = t1.B,
        C = t2.C,
        D = t2.D,
    });

根据我的经验,无论何时正确定义一对多和多对多关系,您都很少需要考虑加入。您只需访问属性,实体框架将自动知道要加入哪些表。