简体   繁体   English

如何仅从导航属性中查询一小部分(不包括该属性中的所有数据)?

[英]How to query only a small part from a navigation property (without including all data in that property)?

I have this small scenario: 我有一个小场景:

var user = await dbContext.Users
        .Include(u => u.Posts)
    .SingleOrDefaultAsync(u => u.Id == userId);

return user
    .SelectMany(u => u.Posts)
    .Skip(someStartIndex)
    .Take(someCount);

The problem with this scenario is that skip and take happen in the memory (after loading a lot of posts from the database into the memory because of issuing Include ). 这个方案的问题是, skiptake的记忆发生(从数据库加载很多帖子进入,因为发出的内存后Include )。 I just want to query small amount of those posts from the database in the first query where I get the user (instead of including the whole posts). 我只想在获取用户的第一个查询中从数据库中查询少量的帖子(而不是包括整个帖子)。 In other words, I want somehow to query small amount of the included data, instead of including them all. 换句话说,我想以某种方式查询少量的包含数据,而不是全部包含它们。

How can I achieve that? 我该如何实现?

PS: In my real code the Posts are not directly under User, but in multiple sub-properties. PS:在我的真实代码中,帖子不是直接位于用户下,而是位于多个子属性中。 I just omitted that to keep the code simple, as the idea of how can I include only a part should still the same. 我只是为了使代码简单而省略了它,因为我如何只包含一部分的想法应该仍然相同。

UPDATE UPDATE

My real code, to have a better understanding of the situation: 我的真实代码是为了对情况有更好的了解:

public async Task<IEnumerable<Post>> GetPostsFromFollowsAsync(Guid userId, int count, int startIndex)
{
    //TODO rewrite this ugly query!!!
    var user = await dbContext.Users
        .Include(u => u.UserFollowing)
            .ThenInclude(uf => uf.FollowingUser)
                .ThenInclude(u => u.Posts)
                    .ThenInclude(p => p.Writer)
                        .ThenInclude(u => u.Profile)
        .Include(u => u.UserFollowing)
            .ThenInclude(uf => uf.FollowingUser)
                .ThenInclude(u => u.Posts)
                    .ThenInclude(p => p.PostLikes)
        .Include(u => u.UserFollowing)
            .ThenInclude(uf => uf.FollowingUser)
                .ThenInclude(u => u.Posts).
                    ThenInclude(p => p.PostCategories)
                        .ThenInclude(pc => pc.Category)
        .Include(u => u.UserFollowing)
            .ThenInclude(uf => uf.FollowingUser)
                .ThenInclude(u => u.Posts)
                    .ThenInclude(p => p.Comments)
        .SingleOrDefaultAsync(u => u.Id == userId);

    return user
        .UserFollowing
        .Select(uf => uf.FollowingUser)
        .SelectMany(u => u.Posts)
        .Skip(startIndex)
        .Take(count);
}

In this specific scenario you can start the query from Posts and use the inverse navigation property for filtering / additional includes: 在这种特定情况下,您可以从“ Posts开始查询,并使用反向导航属性进行过滤/其他包括:

var userPosts = await dbContext.Posts
    .Include(p => p.User)
    // other includes ...
    .Where(p => p.User.Id == userId)
    .Skip(someStartIndex)
    .Take(someCount)
    .ToListAsync();

This way the Skip / Take will happen server side. 这样,“ Skip / Take将发生在服务器端。

Update: The actual structure doesn't change the concept. 更新:实际的结构不会改变概念。 You just need to navigate backwards and change the user Id filter to Any due to many-to-many relationship: 由于多对多关系,您只需要向后导航并将用户ID过滤器更改为Any

return await dbContext.Posts
    .Include(p => p.Writer) // Parent info
        .ThenInclude(u => u.UserFollowers)
            .ThenInclude(uf => uf.FollowerUser)
    .Include(p => p.Writer) // Child info
        .ThenInclude(u => u.Profile)
    .Include(p => p.PostLikes)
    .Include(p => p.PostCategories)
        .ThenInclude(pc => pc.Category)
    .Include(p => p.Comments)
    .Where(p => p.Writer.UserFollowers.Any(uf => uf.FollowerUser.Id == userId))
    .Skip(startIndex)
    .Take(count)
    .ToListAsync();

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

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