简体   繁体   English

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

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

This works:这有效:

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

How do I do the same in the method syntax?我如何在方法语法中做同样的事情?

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

The above code throws an error:上面的代码抛出一个错误:

Cannot implicitly convert type<anonymous // type string Role>[] to 'string[]'不能隐式转换 type<anonymous // type string Role>[] 到 'string[]'

Better to stay with LINQ query syntax which is closer to the SQL and you can easily modify your query.最好使用更接近 SQL 的 LINQ 查询语法,您可以轻松修改查询。 Anyway here is your translation:无论如何,这是您的翻译:

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

So you have Users and UserRoles .所以你有UsersUserRoles There is a one-to-many relation between Users and UserRoles: every User has zero or more UserRoles; Users 和 UserRoles 之间是一对多的关系:每个 User 有零个或多个 UserRoles; every UseRole belongs to exactly one User, namely the User that the foreign key UserId refers to.每个 UserRole 只属于一个 User,即外键 UserId 所指的 User。

You also have a UserName, and you want all Users that have this name, each User with its UserRoles.您还有一个用户名,并且您希望所有具有此名称的用户,每个用户都有其用户角色。

Note: you didn't say that UserName is unique, so It can be, that after the Where you still have several Users with userName "Will Smith".注意:您没有说 UserName 是唯一的,因此在Where您仍然有几个用户名为“Will Smith”。

Short answer简答

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

Or the other way round: start at UserRoles and keep only those UserRoles that have aUser with userName:或者反过来:从 UserRoles 开始,只保留那些具有 userName 的用户的 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() );

There's room for improvement有改进的余地

If user [10] has 20 UserRoles, then every UserRole of User [10] will have a foreign key with a value 10. You will be transferring this value 20 times.如果用户 [10] 有 20 个用户角色,则用户 [10] 的每个用户角色都将有一个值为 10 的外键。您将传输该值 20 次。

If there are several "Will Smith", you will have one big sequence with all the UserRoles of all "Will Smiths" randomly mixed.如果有多个“Will Smith”,您将拥有一个大序列,其中所有“Will Smith”的所有 UserRoles 随机混合。

Your solution will result in:您的解决方案将导致:

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

Wouldn't it be more efficient to group the User, so you have something like:对用户进行分组不是更有效吗,所以你有类似的东西:

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

Note: the result is slightly different: you also get the Users that have no role yet.注意:结果略有不同:您还获得了还没有角色的用户。

Whenever you have items with their zero or more subitems, like Schools with their Students, Customers with their Orders, or Users with their UserRoles, consider to use one of the overloads of Queryable.GroupJoin .每当您有零个或多个子项目的项目时,例如学校有学生、客户有订单或用户有用户角色,请考虑使用Queryable.GroupJoin的重载之一。

Most of the times I use the overload with a parameter resultSelector.大多数情况下,我使用带有参数 resultSelector 的重载。 This way you can specify exactly which properties you want, and in what format:通过这种方式,您可以准确指定所需的属性以及格式:

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

Advantages:好处:

  • You also get the Users that have no UserRoles yet (in your original requirement not a problem)您还可以获得还没有 UserRoles 的用户(在您的原始要求中不是问题)
  • Efficiency: Every property of a User is sent only once.效率:用户的每个属性只发送一次。 An inner join, or left outer join would send the same properties of the User over and over again内连接或左外连接会一遍又一遍地发送用户的相同属性
  • Efficiency: You transfer only the properties that you really need效率:您只传输您真正需要的属性
  • You can deviate from your original tables.您可以偏离原始表格。 If you want to leave out UserRoles, or calculate some properties, like UserRoleCount you can just do it.如果你想省略 UserRoles,或者计算一些属性,比如UserRoleCount你可以这样做。 This makes it easier to change your database tables in the future, without changing this query这使得将来更容易更改数据库表,而无需更改此查询

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM