如何在 C# 中使用 Linq 方法语法检索具有相同外键 ID 的多个列值?

How to retrieve multiple column values with same foreign key id using Linq method Syntax in C#?

这个有效:

var query = (from user in _context.Users
             join role in _context.UserRoles on user.UserID equals role.UserId
             where user.Username == username
             select role.Role).ToArray();

如何在方法语法中执行相同的操作?

//here role.Role has multiple values

var query2 = _context.Users.Join(_context.UserRoles, u=>u.UserID,ur=>ur.UserId,
                 (u,ur)=> new { ur.Role }).ToArray();

以上代码抛出错误:

Cannot implicitly convert type<anonymous // type string Role>[] to 'string[]'

最好使用更接近 SQL 的 LINQ 查询语法,您可以轻松修改查询。不管怎样,这是你的翻译:

 var query2 = _context.Users
    .Where(u => u.Username == username)
    .Join(_context.UserRoles, u => u.UserID, ur => ur.UserId, (u,ur) => ur.Role)
    .ToArray();

所以你有 UsersUserRoles。 Users 和 UserRoles 之间存在 one-to-many 关系:每个 User 都有零个或多个 UserRoles;每个UseRole恰好属于一个User,即外键UserId所指的User。

您还有一个用户名,并且您希望所有用户都具有此名称,每个用户都有其用户角色。

注意:您没有说 UserName 是唯一的,所以在 Where 之后您仍然有几个用户名为“Will Smith”的用户。

简答

string userName = "Will Smith";
var result = dbContext.Users
    .Where(user => user.UserName == userName)
    .Join(dbContext.UserRoles,

        user => user.Id,               // from each User take the Id
        userRole => userRole.UserId,   // from each UserRole take the foreign key

        (user, userRole) => userRole);

或者反过来:从 UserRoles 开始,只保留那些具有用户名的用户角色:

dbContext.UserRoles.Where (userRole => 
    dbContext.Users
        .Where(user => user.Id == userRole.UserId  // get the User of this Role
                    && user.UserName == userName)  // check the name of this User
        .Any() );

还有改进的余地

如果用户 [10] 有 20 个 UserRoles,那么用户 [10] 的每个 UserRole 都有一个值为 10 的外键。您将传输此值 20 次。

如果有多个“Will Smith”,您将得到一个大序列,所有“Will Smiths”的所有 UserRoles 随机混合。

您的解决方案将导致:

UserId UserRole
10     Administator,
10     User
25     Backup
10     Backup
18     User
25     User

将用户分组不是更有效,所以你有这样的东西:

UserId    UserRoles
10        { Administator, User, Backup }
18        { User }
25        { User, Backup }
22        <no UserRoles yet>

注意:结果略有不同:您还得到了还没有角色的用户。

只要你有零个或多个子项的项目,比如学校有他们的学生,客户有他们的订单,或者用户有他们的用户角色,请考虑使用 Queryable.GroupJoin.[=20 的重载之一=]

大多数时候我使用带有参数 resultSelector 的重载。这样您就可以准确指定您想要的属性以及格式:

var usersWithTheirUserRoles = dbContext.Users

    // keep only the users with a specific UserName
    .Where(user => user.UserName == userName)

    // fetch some properties of the remaining users and their UserRoles
    .GroupJoin(dbContext.UserRoles,

        user => user.Id,               // from each User take the Id
        userRole => userRole.UserId,   // from each UserRole take the foreign key

        // parameter resultSelector: take each user, with its zero or more userRoles
        // to make one new:
        (user, userRolesOfThisUser) => new
        {
            // Select only the user parameters that you plan to use:
            Id = user.Id,
            Address = user.Address,
            ...

            // select the zero or more user roles of this user
            UserRoles = userRolesOfThisUser.Select(userRole => new
            {
                // Select only the properties that you plan to use
                Id = userRole.Id,
                Description = userRole.Description,
                ...

                // not needed, you've already got the value:
                // UserId = userRole.UserId,
            })
            .ToList(),
        });

优点:

  • 您还会获得还没有 UserRoles 的用户(在您的原始要求中不是问题)
  • 效率:用户的每个 属性 只发送一次。内部联接或左外部联接会一遍又一遍地发送用户的相同属性
  • 效率:您只传输真正需要的属性
  • 您可以偏离原始表格。如果您想省略 UserRoles,或计算一些属性,例如 UserRoleCount,您可以这样做。这使得将来更改数据库表更容易,而无需更改此查询