LINQ-EF Core-返回嵌套列表中包含两个对象(由属性引用)的对象



我知道有一百万个LINQ问题,很抱歉问你。我环顾四周,找不到正确的答案。我怀疑这很容易,但我是LINQ和EF核心的新手。

我有以下类型的房间列表,它是从DB查询返回的(为了简洁起见,我只包括一个(:

[
{
"roomId": 2,
"roomName": "test",
"users": [
{
"userId": 2,
"username": "seconduser",
"password": "demo",
"token": null,
"refreshToken": null,
"alias": "test",
"friends": null
},
{
"userId": 3,
"username": "thirduser",
"password": "demo",
"token": null,
"refreshToken": null,
"alias": "test",
"friends": null
}
]
}
]

太好了。我想要一个LINQ查询(最好是流利的语法,但我感谢任何帮助(,它将用更多的Room查询这个列表,并且只返回一个(我知道只有一个(,满足以下标准:

房间中只有两个用户,并且两个用户都由传递到方法中的userId标识。

因此,如果该方法接收到以下对象:

{
"friendId": 1,
"requestUserId": 3
}

上述房间将被退回,其他房间不予退还。

我希望这是清楚的。

提前感谢!

编辑-公平地说,我现在包括了一些让我更接近的尝试

我试着填充两个用户,这样我就可以询问是否有房间。Users.Contains((如此:

var requestingUser = UserService.GetSingleUser(request.RequestUserId);

var friendUser = UserService.GetSingleUser(srequest.FriendId);
var test = allRooms.FirstOrDefault(room => room.Users.Count == 2 && room.Users.Contains(friendUser) && room.Users.Contains(requestingUser);

但是用户的比较没有通过。这只是我如何填充用户的问题吗?不管怎样,我知道我不应该那样做。

然后,我尝试了一种在方向上似乎是正确的方法,只是比较ID:

var test = allRooms.First(room => room.Users.Any(user =>
user.userId == request.FriendId && user.userId == request.RequestUserId));

但这返回null,但我已经确认有一个房间满足我指定的条件。

给我带来麻烦的是,EF核心生成了一个我不熟悉的数据库模式。在SQL中,我会让ROOM、USER、ROOMUSER和inner表加入到两个USER.id都存在的ROOMUSER中。。。和独特的,或者类似的东西。

进一步编辑:

我在下面列出了我用来构建DB的模型。最初我没有这样做,因为我包含的JSON是查询所有房间并包括其用户(房间内的ICollection(的结果。

public class User
{
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Token { get; set; }
public string RefreshToken { get; set; }
public string Alias { get; set; }

public ICollection<User> Friends { get; set; }
}
public class Room
{
public int RoomId { get; set; }
public string RoomName { get; set; }

public ICollection<User> Users { get; set; }
}

因此,正如我所描述的,如果我手工制作的话,这些表会是什么样子,其想法是User和Room是不同的实体(主要实体(,并且会有一个连接表来表明它们的关系。从概念上讲,用户在房间中。

更清楚的是,最初的JSON由以下LINQ返回:

var allRooms = db.Rooms.Include(x => x.Users).ToList();

因此,要求一间具备上述条件的房间应该不会太困难。

诚然,正如我所说,我从未与英孚核心合作过,也几乎从未与LINQ合作过。我可能犯了一个愚蠢的错误。。。

这个是接近的

room => room.Users.Any(user =>
user.userId == request.FriendId && user.userId == request.RequestUserId)

但需要一些调整

  • And(&&(运算符不合适-id不能同时等于两个传递的id。它应该是一个或另一个,即您需要的是or(||(运算符,而不是

    user.userId==请求。FriendId||user.userId==请求。请求用户ID

  • Any也不合适。它将返回一个只有一个通过的用户的房间,或者同时有两个用户,但其中有其他用户。您需要的是All

    room.Users.All(user=>user.userId==请求。FriendId||user.userId==请求。请求用户ID(

然而,All也为空集返回true(即,当room.Users为空时(,因此它必须与另一个调用组合以消除这种情况下的

room.Users.Any() && room.Users.All(user =>
user.userId == request.FriendId || user.userId == request.RequestUserId)

这将产生期望的结果,但由于涉及两个子查询而不是一个子查询,因此效率低下。

因此,最好使用我所说的";条件计数";并将所得计数与二(2(进行比较:

room.Users.Count(user =>
user.userId == request.FriendId || user.userId == request.RequestUserId) == 2

它也可以用类似的输入更通用地表达(因为它支持2个以上(

// could contain more than two ids and doesn't need to be array
var userIds = new [] { request.FriendId, request.RequestUserId }.AsEnumerable();

以及类似的查询条件

room.Users.Count(user => userIds.Contains(user.userId)) == userIds.Count()

最新更新