0

这有效:

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();

上面的代码抛出一个错误:

无法将 type<anonymous // 类型字符串 Role>[] 隐式转换为 'string[]'

4

2 回答 2

1

最好使用更接近 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();
于 2020-11-01T07:20:42.397 回答
1

所以你有UsersUserRoles。Users 和 UserRoles 之间存在一对多的关系:每个 User 都有零个或多个 UserRoles;每个 UserRole 只属于一个 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 个用户角色,那么用户 [10] 的每个用户角色都将有一个值为 10 的外键。您将传输此值 20 次。

如果有多个“Will Smith”,您将拥有一个大序列,其中所有“Will Smith”的所有 UserRole 随机混合。

您的解决方案将导致:

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>

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

每当您有带有零个或多个子项的项目时,例如带有学生的学校、带有订单的客户或带有 UserRoles 的用户,请考虑使用Queryable.GroupJoin的重载之一。

大多数时候,我使用带有参数 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你可以这样做。这使得将来更改数据库表变得更容易,而无需更改此查询
于 2020-11-02T09:14:27.510 回答