Entity Framework: генерировать динамическое предложение where и выбирать пользовательские столбцы
У меня есть 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, как указано выше.
Так как я не мог придумать построение динамического предложения where для query syntax LINQ
Я пытался преобразовать его в 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.
Я также пытался использовать выше query syntax LINQ
оператор без предложения where, заставляющий его возвращать объект вместо анонимного объекта, а затем вызывающий метод .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 и затем выполнить ее, но мне бы очень хотелось, чтобы это работало с Entity Framework.
Как бы я завершил создание динамического предложения where, выделил бы в пользовательском плоском объекте, и чтобы структура сущностей генерировала SQL?
1 ответ
Ты можешь использовать 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
}
)
)
);