我有 3 个表:Person
、PersonFriend
、PersonGroup
。
使用LINQ,我想联接 3 个表,使用动态生成的 where 子句进行筛选,并选择具有平展行的自定义列(平展的一对多关系表列)。
伪SQL设计:
CREATE TABLE Person (int id, varchar socialclass, date createddate);
CREATE TABLE Person_Friend (int id, id personid references person.id, id friendpersonid references person.id, varchar friendtype);
CREATE TABLE Person_Group (int id, int memberid references person.id, varchar membershiplevel);
实体:
public class Person
{
public int Id { get; set; }
public string SocialClass { get; set; }
public DateTime? CreatedDate { get; set; }
public ICollection<PersonFriend> Friend { get; set; }
public ICollection<PersonGroup> Group { get; set; }
}
public class PersonFriend
{
public int Id { get; set; }
public int PersonId { get; set; }
public int FriendPersonId { get; set; }
public string FriendType { get; set; }
}
public class PersonGroup
{
public int Id { get; set; }
public int MemberId { get; set; }
public string MembershipLevel { get; set; }
}
查询语法 LINQ:
var queryResult = from person in _context.Person
join friend in _context.PersonFriend on person.Id equals friend.FriendPersonId
join group in _context.PersonGroup on person.Id equals group.MemberId
where (friend.PersonId == 1 && friend.FriendType == "type1") || (friend.PersonId == 3 && friend.FriendType == "type2") || ...
select new { person.Id, person.SocialClass, person.CreatedDate, friend.FriendPersonId, friend.FriendType, group.Id, group.MembershipLevel };
请注意 where 子句;给定{ PersonId, FriendType }
对象的列表,我想像上面一样构建 where 子句。
由于我无法为query syntax LINQ
构建动态 where 子句, 我尝试将其转换为Method syntax LINQ
语句,以便我可以利用PredicateBuilder
(http://www.albahari.com/nutshell/predicatebuilder.aspx),但在将一对多事物选择为平展对象时遇到了问题。
var methodResult = _context.Person
.Include(x => x.Friend)
.Include(x => x.Group)
.Select(person => new { person.Id, person.SocialClass, person.CreatedDate, person.friend.FriendPersonId, person.friend.FriendType, person.group.Id, person.group.MembershipLevel });
请注意,上述选择是不可能的,因为friend
是 ICollection。
我还尝试使用上面不带 where 子句的query syntax LINQ
语句,使其返回对象而不是匿名对象,然后使用谓词生成器调用方法.Where()
。但是构建的表达式会LINQ => Entity Framework SQL conversion error
并在应用程序中执行where
,而不是在数据库中执行。
var queryResultWithoutWhere = from person in _context.Person
join friend in _context.PersonFriend on person.Id equals friend.FriendPersonId
join group in _context.PersonGroup on person.Id equals group.MemberId
select new SelectedObject { PersonId = person.Id, SocialClass = person.SocialClass, CreatedDate = person.CreatedDate, FriendId = friend.FriendPersonId, FriendType = friend.FriendType, GroupId = group.Id, MembershipLevel = group.MembershipLevel };
var predicate = PredicateBuilder.New<SelectedObject>(false);
foreach (var searchObject in searchRequestObjects)
{
predicate.Or(p => p.FriendPersonId == searchObject.FriendPersonId && p.FriendType == searchObject.FriendType);
}
var result = queryResultWithoutWhere.Where(predicate).ToList();
我觉得我尽我所能,但我似乎无法生成这个 SQL。最后的手段是编写一个原始的SQL字符串,然后执行它,但我真的很想让它与实体框架一起工作。
我将如何完成创建动态 where 子句,选择到自定义平展对象中,并让实体框架生成 SQL?
您可以使用SelectMany
来展平集合:
var methodResult = Persons
.Include(x => x.Friend)
.Include(x => x.Group)
.SelectMany(person =>
person.Friend.SelectMany(friend =>
person.Group.Select(group =>
new {
person.Id,
person.SocialClass,
person.CreatedDate,
friend.FriendPersonId,
friend.FriendType,
GroupId = group.Id,
group.MembershipLevel
}
)
)
);