linq查询获取好友列表

c9qzyr3d  于 2023-06-19  发布在  其他
关注(0)|答案(1)|浏览(102)

我不能创建一个请求,以获得一个朋友的名字或姓氏像“参数”的列表。主要的要求是请求必须接受所有带有名字或姓氏参数的朋友,而不是所有的朋友,然后做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.
所以我需要做的请求,不做所有的请求,但做请求我的'在哪里'参数。'AsEnumerable', 'AsAsyncEnumerable', 'ToList' after calling GetAllFriends(userDb.Id)是个坏主意,因为如果有很多朋友,那么这是一个很大的负载。
所以可能是正常的这样做,我不知道,可能是它唯一的方式来做这个请求?

rkkpypqq

rkkpypqq1#

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

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

并且仍然将其视为可扩展的IQueryable,但是EF可以使用string.Contains构建LIKE %term%查询。
您可以尝试:

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
这里需要注意的是,您的数据库设置为不区分大小写的排序规则(即a CI**排序规则)。如果排序规则区分大小写(CS),则在.Contains(...)之前添加.ToLower()
如果查询仍然不起作用,那么您可能需要调整Repository以返回Friends,然后构建子查询以检查两个用户引用:

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,然后构建查询表达式来检查用户名或FriendUser名,这取决于哪个ID匹配。
请注意,因为您希望有条件地加载Friend.User或Friend.FriendUser,所以如果您希望立即加载相关的详细信息(如适用的用户配置文件),这将使事情变得复杂。例如,您可以尝试以下操作:

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

然而,我不相信Include中的那种条件工作。
如果阅读数据并且您需要User和UserProfile详细信息,我建议使用Select来投影视图模型,以便您可以从适用的用户和用户配置文件中选择详细信息。否则,我会建议将存储库调用和业务逻辑设计为明确使用的ID是FriendId还是UserId,而不是试图在单个方法中有条件地选择/或。如果您的代码知道它正在基于朋友ID或基于用户ID加载用户,那么您可以确定要立即加载的实体和相关实体。作为一般规则,应该尽可能避免这样的条件逻辑,因为它会使代码很难一目了然,并为隐藏的小错误敞开大门。

相关问题