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
                            }
                        )
                    )
                );
Другие вопросы по тегам