linq 查询获取好友列表

问题描述 投票:0回答:1

我无法创建请求来获取姓名如“param”的朋友列表。主要要求是请求必须接受所有带有名字或姓氏参数的朋友,而不是全部,然后做

where
。 异常返回到使用
'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
,但它确实在我的
where
之前请求,这是个坏主意,因为如果有很多朋友,那么这是一个很大的负载。

FriendshipRepository 中的方法

    public IQueryable<User> GetAllFriends(int id)
    {
        var friends = _socialNetworkDbContext.Friends
            .Include(f => f.FriendUser.Profile)
            .Where(f => f.UserId == id || f.FriendId == id)
            .Select(f => f.UserId == id ? f.FriendUser : f.User)
            .AsQueryable();
        
        return friends;
    }

然后在通过名字或姓氏查找朋友的服务方法中有这个请求

            string name = parts[0].ToLower();
            matchingUsers = _friendshipRepository.GetAllFriends(userDb.Id)
                .Where(user => EF.Functions.Like( user.Profile.Name.ToLower(), "%"+name+"%")
                    || EF.Functions.Like( user.Profile.Surname.ToLower(), "%"+name+"%"))
                .ToList();

还有一部分

 .Where(user => EF.Functions.Like( user.Profile.Name.ToLower(), "%"+name+"%")
                    || EF.Functions.Like( user.Profile.Surname.ToLower(), "%"+name+"%"))

调用异常

could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

所以我需要做的请求不是向所有人发出请求,而是通过我的“where”参数进行请求。

'AsEnumerable', 'AsAsyncEnumerable', 'ToList' after calling GetAllFriends(userDb.Id)
是个坏主意,因为如果有很多朋友,那么这是一个很大的负担。

所以这样做可能是正常的,我不知道,可能是执行此请求的唯一方法?

linq entity-framework-core
1个回答
0
投票

我不确定 EF 是否可以正确处理这个问题:

.Select(f => f.UserId == id ? f.FriendUser : f.User)

并且仍然将其视为可扩展的

IQueryable
,但是 EF 可以使用
LIKE %term%
构建
string.Contains
查询。

你可以尝试:

public IQueryable<User> GetAllFriendUsers(int id)
{
    var query = _socialNetworkDbContext.Friends
        .Where(f => f.UserId == id || f.FriendId == id)
        .Select(f => f.UserId == id ? f.FriendUser : f.User);
    
    return query;
}

然后:

string name = parts[0].ToLower();
matchingUsers = _friendshipRepository.GetAllFriendUsers(userDb.Id)
.Where(u => u.Profile.Name.Contains(name)
    || u.Profile.Surname.Contains(name))
.ToList();

值得注意的是:如果返回

IQueryable
并使用投影 /w
Select
,我们不需要
Include
语句。调用者可以自由地投影或急切加载他们特别需要的相关数据。我们也不需要将其转换为
AsQueryable
,因为它会返回
IQueryable

此处需要注意的是,您的数据库针对姓名和姓氏设置了不区分大小写的排序规则(即 CI* 排序规则)。如果排序规则区分大小写 (CS*),则在

.ToLower()
之前添加
.Contains(...)

如果查询仍然不起作用,那么您可能需要调整存储库以返回好友,然后构建子查询来检查两个用户引用:

public IQueryable<Friend> GetAllFriends(int id)
{
    var query = _socialNetworkDbContext.Friends
        .Where(f => f.UserId == id || f.FriendId == id);
    
    return query;
}

string name = parts[0].ToLower();
matchingUsers = _friendshipRepository.GetAllFriends(userDb.Id)
.Where(f => (f.UserId == userDb.Id 
        && (f.User.Profile.Name.Contains(name)
            || f.User.Profile.Surname.Contains(name)))
    || (f.FriendId == userDb.Id 
        && (f.FriendUser.Profile.Name.Contains(name)
            || f.FriendUser.Profile.Name.Contains(name))))
.Select(f => f.FriendId == userDb.Id ? f.FriendUser : f.User)
.ToList();

这里的区别在于我们返回 Friends,然后构建查询表达式来检查 User name 或 FriendUser name,具体取决于哪个 Id 匹配。

请注意,因为您想要有条件地加载 Friend.User 或 Friend.FriendUser,如果您想要立即加载相关详细信息(例如适用用户的个人资料),这将使事情变得复杂。例如,您可以尝试以下操作:

.Include(f => f.FriendId == userDb.Id ? f.FriendUser.UserProfile : f.User.UserProfile)

但是我不相信

Include
中的那种条件有效。

如果读取数据并且您需要用户和用户配置文件详细信息,我建议使用

Select
投影视图模型,以便您可以从适用的用户和用户配置文件中选择详细信息。否则,我建议将存储库调用和业务逻辑设计为明确说明所使用的 ID 是 FriendId 还是 UserId,而不是尝试在单个方法中进行有条件的选择。如果您的代码知道它正在根据朋友 ID 或用户 ID 加载用户,那么您可以确定要预先加载的实体和相关实体。作为一般规则,应尽可能避免类似的条件逻辑,因为它会使代码更难以一眼理解,并为隐藏的小错误敞开大门。

© www.soinside.com 2019 - 2024. All rights reserved.