EF Core如何选择具有多对多关系的实体

Era*_*ara 6 c# linq entity-framework entity-framework-core

我是这样的表结构

  1. 用户
  2. user_profiles
  3. 型材

描述:

user有许多用户配置文件,user_profile表连接用户和配置文件表.(用户和配置文件表之间存在多对多的关系)

用户>一个一对多> user_profiles>一个对一>型材

user> many user_profiles>一个配置文件

问题:

如何使用linq选择具有配置文件的用户.

样品:

var user=cbContext.user.include("user_profiles").include("profiles").Where(predicate).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

Era*_*ara 7

找到了答案

dbContext.Users
  .Include(user => user.UserProfiles)
  .ThenInclude(userProfiles => userProfiles.Profile) 
  .Where(predicate)
  .FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

  • 加上在lambda中使用有意义的名字! (2认同)
  • 但是按“个人资料”过滤的“谓词”是什么样子的呢? (2认同)

Har*_*lse 7

如果您有完整的实体框架,那么多对多的设计类似于:

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

     // every User has zero or more Profiles (many-to-many)
     public virtual ICollection<Profile> Profiles {get; set;}

     ...
}
class Profile
{
     public int Id {get; set;}

     // every Profile belongs to zero or more Users (many-to-many)
     public virtual ICollection<User> Userss {get; set;}

     ...
}
Run Code Online (Sandbox Code Playgroud)

如果您的课程是这样设计的,并且您想要“具有...及其个人资料的用户”,您可以使用这些集合并选择您计划使用的属性:

using (var dbContext = new MyDbContext(...))
{
    var requestedUsers = dbContext.Users
        .Where(user => ...)                      // only if you don't want all Users
        .Select(user => new
        {    // Select only the properties you plan to use:
             Id = user.Id,
             Name = user.Name,
             ...
             Profiles = user.Profiles
                 .Where(profile => ...)         // only if you don't want all profiles
                 .Select(profile => new
                 {
                      Name = profile.Name,
                      ...
                 })
                 .ToList(),
        })
Run Code Online (Sandbox Code Playgroud)

数据库查询较慢的部分之一是将所选数据从数据库管理系统传输到您的进程。因此,明智的做法是将您传输的数据限制为您实际计划使用的数据。

Include将选择包含对象的所有属性,包括主键和外键。Include a Collection将选择完整的集合,即使您只打算使用其中的几个。

建议:仅Include在您计划更改获取的数据时使用。使用Select速度更快。Select仅您实际计划使用的属性

如果不能使用 ICollection,请使用 (Group)Join

我从一些人那里了解到,virtual ICollections当您使用 EF-core 时,您不能使用。在这种情况下,您必须自己执行 GroupJoin

dbContext.Users
    .Where(user => ...)
    .GroupJoin(dbContext.UserProfiles,         // GroupJoin the users with the UserProfiles
        user => user.Id                        // from every user take the Id
        userProfile => userProfile.UserId,     // from every userProfile take the UserId
        (user, userProfiles) =>  new           // when thay match,
        {                                      // take the user and its matching UserProfiles
            UserId = user.Id,                  // again: select only properties you plan to use
            UserName = user.Name,
            ...

            // for the Profiles, do a new Join with the Profiles
            Profiles = userProfiles.Join(dbContext.Profiles, // join with Profiles
               userProfile => userProfile => profileId       // from the userProfile take profileId
               profile => profile.Id,                        // from the Profile take the Id
               (userProfile, profile) => new                 // when they match, make an object
               {   // again: use only properties you plan to use
                   ProfileId = profile.Id,
                   ProfileName = profile.Name,
                   ...
               })
               .ToList(),
        });
Run Code Online (Sandbox Code Playgroud)

小心:您将无法获得没有任何个人资料的用户!
它是一个内连接。

如果您还需要没有个人资料的用户,请使用Stackoverflow 上所述Left-Outer-GroupJoin向下滚动以获得排名最高的答案,这比所选答案要好