我的项目中有一些用户过滤器,我想在这里显示每个用户的朋友。 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();
答案 0 :(得分:2)
数据库管理系统已针对选择数据进行了优化。较慢的部分之一是将所选数据传输到您的流程。因此,明智的做法是仅传输您实际打算使用的数据。
如果您具有一对多关系,例如Schools
和他们的Students
,并且School
10有1000 Students
,则每个Student
School
中的一个将具有值为10的外键SchoolId
。
因此,如果您获取“学校[10]及其学生”,您已经知道学校[10]的每个Student
都会有一个属性SchoolId
,其值为10。您已经知道)将被运输1000次(如果您还算学校的主键,则为1001)。多么浪费处理能力!
如果您使用实体框架查询数据,请始终使用
Select
。仅在要更新提取的数据(更改,删除)时才使用Include
使用“选择”可以使您仅选择所需格式的所需属性。
回到您的问题
A,您忘记给我们上课了。因此,我们将不得不猜测。似乎User
具有零个或多个Languages
,CreatedEvents
,Friends
,Hobbies
等。其中一些将是一对多的关系,可能大多数将是多对多关系:用户知道零种或多种语言。每种语言都由零个或多个用户说。
如果您遵循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));