我如何使用.ThenInclude()c从.Include()获得价值

时间:2019-05-02 12:07:08

标签: c# entity-framework linq lambda

我的项目中有一些用户过滤器,我想在这里显示每个用户的朋友。 UserFrom-发送友谊请求,UserTo-接受友谊请求。因此,我需要知道下面代码中的ID以选择相反的位置,因为它将是他的朋友。

var users = await _context.User
            .Where(u => userFilter.Gender != null ?
                u.Gender == userFilter.Gender : true)
            .Where(u => (userFilter.Languages != null &&
                         userFilter.Languages.Count() != 0) ?
                userFilter.Languages.Any(fl => u.Languages.Any(
                    ul => ul.LanguageCode == fl &&
                        LevelInRange(ul, userFilter.MinLevel))) : true)
            .Where(u => (userFilter.MaxDistance != null) ?
                LocationHelper.GetDistanceBetween((double)u.Longitude, (double)u.Latitude,
                longtitude, latitude) <= userFilter.MaxDistance : true)
            .Where(u => (userFilter.MaxAge != null) ?
                GetAge(u.Birthdate) <= userFilter.MaxAge : true)
            .Where(u => (userFilter.MinAge != null) ?
                GetAge(u.Birthdate) >= userFilter.MinAge : true)
            .Include(u => u.Languages)
            .ThenInclude(ul => ul.Language)
            .Include(u => u.CreatedEvents)
            .Include(u => u.Friends)
            .ThenInclude(f => f.UserTo) //The problem is here. How can I get u.Id there
            .Include(u => u.Credentials)
            .Include(u => u.Hobbies)
                .ThenInclude(h => h.Hobby)
            .ToListAsync();

2 个答案:

答案 0 :(得分:2)

数据库管理系统已针对选择数据进行了优化。较慢的部分之一是将所选数据传输到您的流程。因此,明智的做法是仅传输您实际打算使用的数据。

如果您具有一对多关系,例如Schools和他们的Students,并且School 10有1000 Students,则每个Student School中的一个将具有值为10的外键SchoolId

因此,如果您获取“学校[10]及其学生”,您已经知道学校[10]的每个Student都会有一个属性SchoolId,其值为10。您已经知道)将被运输1000次(如果您还算学校的主键,则为1001)。多么浪费处理能力!

  

如果您使用实体框架查询数据,请始终使用Select。仅在要更新提取的数据(更改,删除)时才使用Include

使用“选择”可以使您仅选择所需格式的所需属性。

回到您的问题

A,您忘记给我们上课了。因此,我们将不得不猜测。似乎User具有零个或多个LanguagesCreatedEventsFriendsHobbies等。其中一些将是一对多的关系,可能大多数将是多对多关系:用户知道零种或多种语言。每种语言都由零个或多个用户说。

如果您遵循entity framework code first conventions,则可能有类似的课程:

class User
{
    public int Id {get; set;}
    public string Name {get; set;}

    // every User has zero or more Hobbies (many-to-many)
    public virtual ICollection<Hobby> Hobbies {get; set;}

    // every Student has created zero or more events (one-to-many)
    public virtual ICollection<CreatedEvent> CreatedEvents {get; set;}

    ...
}

class Hobby
{
    public int Id {get; set;}
    public string Name {get; set;}
    ...

    // every Hobby is practised by zero or more Users (many-to-many)
    public virtual ICollection<User> Users {get; set;}
}

class CreatedEvent
{
    public int Id {get; set;}
    public string Name {get; set;}
    public DateTime Date {get; set;}

    // every event is created by exactly one User (one-to-many, using foreign key)
    public int UserId {get; set;}
    public virtual User User {get; set;}
}

  

在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系(一对多,多对多,...)

因此,外键是非虚拟的。外键指向的项目是虚拟的。如果两个类有一个指向彼此的virtual ICollection<...>,则实体框架会知道存在多对多关系;如果两个类之一具有virtual ICollection<...>而另一个具有virtual ...,则实体框架知道您打算设计一对多关系。

如果您已经正确地创建了类,尤其是virtual ICollections,则使用Select进行查询非常简单。您几乎不必再进行(group-)join。因为使用了虚拟属性,所以实体框架知道需要(组)连接。

var queryUsers = dbContext.User.Where(...).Where(...) ...
    .Select(user => new
    {
        // select only the user properties you really plan to use
        Id = user.Id,
        BirthDay = user.BirthDay,

        // Select the data in the format that you want, for example:
        FullName = user.FirstName + user.MiddleName + user.LastName,

        // SubCollections:
        Languages = user.Hobbies
           .Where(hobby => ...) // only if you don't want all this user's hobbies
           .Select(hobby => new
           {
                // again, select only the hobby properties that you plan to use
                Id = hobby.Id,
                ...

                // not needed, you already know the value:
                // I know, it is probably a many-to-many, but let's suppose it is one-to-many
                // UserId = hobby.UserId,
           })
           .ToList(),

           ...
    });

现在问题出在属性Friends中,您可以将其添加到“选择”中,就像选择Hobbies

    Friends = user.Friends
        .Where(friend => ...)  // only if you don't want all Friends
        .Select(friend => new
        {
            // select the Friend properties you actually plan to use:
            Id = friend.Id,
            Name = friend.Name,
            ...
        })
        .ToList(),

   // continue the select

答案 1 :(得分:0)

IIRC,您可以使用.Include()对具有Linq表达式的孩子进行Select(),对于孩子来说,就像这样。

return _context.User
 .Include(a => a.Friends.Select(c => c.UserTo));