将 Double Inner Join SQl 查询转换为 LINQ

convert Double Inner Join SQl query to LINQ

我有一个 SQL 查询,想将其转换为 LINQ 语句而且我之前从未使用过 Linq 语句,请帮我解决这个问题谢谢

SELECT c.* , v.*
  FROM UserEnrolleds u
  INNER JOIN Courses c ON u.CourseId = c.id
  INNEr JOIN Videos v ON v.CourseID = c.Id
  WHERE u.UsersID = '8851d572-eaff-4a84-9ec8-aa144fecfea2'

假设变量 db 是您的数据库尝试;

var qdResult = 
    from u in db.UserEnrolleds 
        join c in db.Courses on u.CourseID equals c.id 
        join v in db.Videos on c.Id equals v.CourseID
    where u.UsersID = '8851d572-eaff-4a84-9ec8-aa144fecfea2'
    select c, v

显然您有三个 table:课程、视频和 UserEnrolled。

Courses 和 UserEnrolleds 之间存在关系,可能是一对多的关系:每个 Course 都有零个或多个 UserEnrolleds,每个 UserEnrolled 只属于一个 Course,即具有 Course.Id 的 Course外键 UserEnrolled.CourseId 指向。

同样,视频和课程之间似乎存在一对多关系:每个视频都有其所属课程的外键 Video.CourseId。

在我看来,您想要由 ID 为“8851d572-eaff...”的用户注册的课程和视频

您计划使用 UserEnrolleds - 课程 - 视频的内​​部联接来执行此操作。

如果您使用 Entity Framework,您可以使用两种方法。您可以使用 virtual ICollection 属性,或自己进行连接。

通常我发现 ICollection 的使用更容易,也更有吸引力,但让我们首先关注您的问题。

三个 table 上的完全内部联接

为此,我将使用 Queryable.Join

的重载之一
var result = dbContext.UserEnrolleds          // get table UserEnrolleds

    // keep only the UserEnrolleds with the mentioned UsersId:
    .Where(userEnrolled => userEnrolled.UsersId = "8851...")

    .Join(dbContext.Courses,                  // join with table Courses,
    userEnrolled => userEnrolled.CourseId,    // from every userEnrolled take the CourseId
    course => course.Id,                      // from every course take the Id

    (userEnrolled, Course) => new             // remember the matching items for the next join
    {
        UserEnrolled = userEnrolled,
        Course = Course,
    })

    .Join(dbContext.Videos,              // join with the Videos table
    joinResult => joinResult.Course.Id,  // from the previous Join take the Course Id
    video => video.CourseId,             // from the video take the CourseId

    (joinResult, video) => new           // when they match, make one new object
    {
       UserEnrolled => joinResult.UserEnrolled,
       Course => joinResult.Course,
       Video => video,
    })

加入后,使用 Select 仅查询您实际计划使用的属性。

.Select(joinResult => new
{
    Course = new
    {
        Id = joinResult.Course.Id,
        Name = joinResult.Course.Name,
        ...
    },

    Video = new
    {
        Id = joinResult.Video.Id,
        Name = joinResult.Video.Name,
        ...
    }

    UserEnrolled = ...
});

如果要查询完整的课程和视频:

.Select(joinResult => new
{
     Course = joinResult.Course,
     Video = joinResult.Video,
})

请注意,您将转移几个您可能不会使用的属性,尤其是外键。

当然,您可以在联接的最后一个参数中执行 select(结果Select 或)。我没有这样做,为了更容易理解。

使用虚拟 ICollection

很多时候,如果您有一对多关系,您想要执行 GroupJoin 而不是 Join:您想要所有 "Courses with their Videos".

所以不是 table:

Course 1 - Video 10
Course 1 - Video 11
Course 1 - Video 12
Course 2 - Video 13
Course 2 - Video 14
Course 3 - Video 15

你想要一个 table:

Course 1 with its Videos 10, 11, and 12
Course 2 with its Videos 13, and 14
Course 3 with its one and only Video 15
Course 4 has no Video at all.

如果您更喜欢 "Courses with their Videos"(也许还有一些与 UserEnrolleds 相关的东西),使用 virtual ICollection 比自己进行连接要容易得多。

如果您遵循了 entity framework code first conventions,您将 类 类似于以下内容:

class Course
{
    public int Id {get; set;}
    public string Name {get; set;}
    ...

    // Every Course has zero or more Videos:
    public virtual ICollection<Video> Videos {get; set;}

    // Every Course has zero or more UserEnrolleds:
    public virtual ICollection<UserEnrolled> UserEnrolleds {get; set;}
}

public class Video
{
    public int Id {get; set;}
    public string Name {get; set;}
    ...

    // every Video belongs to exactly one Course, using foreign key:
    public int CourseId {get; set;}
    public virtual Course Course {get; set;}
}

UserEnrolled 与视频相似:

public class UserEnrolled
{
    public int Id {get; set;}
    public string UsersId {get; set;}
    ...

    // every Video belongs to exactly one Course, using foreign key:
    public int CourseId {get; set;}
    public virtual Course Course {get; set;}
}

In entity framework the columns of the tables are represented by the non-virtual properties. The virtual properties represent the relations between the tables (one-to-many, many-to-many, ...)

外键是您 table 中的真实列,因此它们是非虚拟的

为了完整起见,DbContext:

class MyDbContext : DbContext
{
    public DbSet<Course> Courses {get; set;}
    public DbSet<Video> Videos {get; set;}
    public DbSet<UserEnrolled> UserEnrolleds {get; set;}
}

这就是 entity framework 检测您的 table、table 中的列以及它们之间的关系所需知道的全部内容。它还将为您创建和使用主键和外键。

现在获取所有课程,每个课程都有他们的视频,这些课程由 ID 为“8851d572-eaff...”的用户注册(=至少有一个 UserEnrolled 的 UsersId 等于“8851d572-eaff. .."),使用以下查询:

var coursesAndVideosEnrolledByUser = dbContext.Courses

    // keep only the Courses that are enrolled by user with Id "8851..."
    .Where(course => course.UserEnrolleds
                     .Any(userEnrolled => userEnrolled.UsersId = "8851d572-eaff..."))
    .Select(course => new
    {
        Id = course.Id,
        Name = course.Name,
        ...

        Videos = course.Videos,
    });

您是否同意,如果您想获得由特定用户参加的课程,每个课程都有他们的视频,这看起来会更自然吗?

奖励点:如果此用户参加的课程没有视频,您仍然会在结果中找到它们。您不会使用内部联接获取它们!