Linq гуру - фильтрация связанных лиц - PullRequest
4 голосов
/ 27 апреля 2010

Моя структура таблицы выглядит следующим образом:

Person 1-M PesonAddress
Person 1-M PesonPhone
Person 1-M PesonEmail
Person 1-M Contract 
Contract M-M Program
Contract M-1 Organization

В конце этого запроса мне нужен заполненный граф объектов, где у каждого человека есть свои:

  • PesonAddress в
  • PesonPhone в
  • PesonEmail в
  • PesonPhone в
  • Контракт - и это имеет свои
    • программа

Теперь у меня был следующий запрос, и я подумал, что он отлично работает, но у него есть пара проблем:

from people in ctx.People.Include("PersonAddress")
                        .Include("PersonLandline")
                        .Include("PersonMobile")
                        .Include("PersonEmail")
                        .Include("Contract")
                        .Include("Contract.Program")
where people.Contract.Any(
    contract => (param.OrganizationId == contract.OrganizationId)
        && contract.Program.Any(
            contractProgram => (param.ProgramId == contractProgram.ProgramId)))
select people;

Проблема в том, что он фильтрует человека по критериям, но не по Контрактам или Программам Контракта. Он возвращает все Контракты, что у каждого человека есть не только те, которые имеют OrganId x, и то же самое относится к каждой из этих Программ Контракта соответственно.

Мне нужны только те люди, у которых есть хотя бы один контракт с OrgId, равным x, и где этот контракт имеет Программу с идентификатором y ... и для возвращаемого графа объектов, который имеет только контракты. эти совпадения и соответствующие программы в этом договоре.

Я вроде понимаю, почему он не работает, но я не знаю, как его изменить, чтобы он работал ...

Пока это моя попытка:

from people in ctx.People.Include("PersonAddress")
                        .Include("PersonLandline")
                        .Include("PersonMobile")
                        .Include("PersonEmail")
                        .Include("Contract")
                        .Include("Contract.Program")
let currentContracts = from contract in people.Contract
                where (param.OrganizationId == contract.OrganizationId)
                select contract 
let currentContractPrograms = from contractProgram in currentContracts 
                    let temp = from x in contractProgram.Program
                        where (param.ProgramId == contractProgram.ProgramId)
                        select x
                    where temp.Any()
                    select temp
where currentContracts.Any() && currentContractPrograms.Any()
select new Person { PersonId = people.PersonId, FirstName = people.FirstName, ..., ...., 
                    MiddleName = people.MiddleName, Surname = people.Surname, ..., ...., 
                    Gender = people.Gender, DateOfBirth = people.DateOfBirth, ..., ...., 
                    Contract = currentContracts, ... };  //This doesn't work

Но у этого есть несколько проблем (где тип Person является объектом EF):

  • Мне оставлено самостоятельно составлять карту, которой в этом случае достаточно много для отображения
  • Когда я пытаюсь сопоставить список со свойством (например, Scholarship = currentScholarships), он говорит, что не может, потому что IEnumerable пытается привести к EntityCollection
  • Включить не работает

Следовательно, как мне заставить это работать. Помня о том, что я пытаюсь сделать это как скомпилированный запрос, я думаю, что это означает, что анонимные типы отсутствуют.

Ответы [ 3 ]

2 голосов
/ 03 мая 2010

Только не используйте Включить, фильтруйте вручную. Сначала вы можете отфильтровать Контракты, связанные с требуемыми ProgramId и OrganizationId. После этого вы можете выбрать лиц, связанных с выбранными контрактами. Я приложил образец кода. Вам нужно будет изменить его, чтобы правильно использовать отношения M-M. Но в любом случае логика должна быть правильной.

public class PersonDetails
{
    public Person person;
    public List<Contract> contracts;
}

var selected_program = (from pr in ctx.Programs where pr.Id == param.ProgramId select pr).Single();

//select contracts by OrganizationId and ProgramId
var selected_contracts = from c in ctx.Contracts
                where c.OrganizationId == param.OrganizationId
                from p in ctx.Programs
                where p.Id == param.ProgramId
                where p.ContractId == c.Id
                select c;

//select persons and contracts
var people =
    from p in ctx.People
    select new PersonDetails()
    {
        person = p,
        contracts = (from c in selected_contracts
                     where c.PersonId == p.Id
                     select c).ToList()
    };

//select people associated with selected contracts
var selected_people = from p in people where p.contracts.Count > 0 select p;
1 голос
/ 30 апреля 2010

Включение в Entity Framework всегда возвращает все в отношениях, нет способа сделать частичное включение или эквивалент AssociateWith, который есть в Linq to SQL.

Вместо этого, если вы хотите вернуть только некоторые Контракты, вам нужно разделить их на два запроса и воспользоваться преимуществами автоматического подключения, выполняемого структурой сущностей.

Как только оба запроса будут выполнены, ваши объекты Person будут содержать только Контракты, возвращенные запросом Контрактов в их коллекции Контрактов.

0 голосов
/ 03 мая 2010

Как говорит Mant101, вы не можете фильтровать часть .Include в Linq для сущностей. Посмотрите на объект Person как на представление всей информации об этом человеке, хранящейся в базе данных, включая все contracts. Все настройки должны быть сделаны отдельно.

Эти вопросы, похоже, появляются здесь регулярно. По крайней мере, я думаю, что видел некоторые, но не могу найти много. Вот еще один вопрос, касающийся этой темы: условное включение в linq для сущностей? .

Там также есть работающий ансер: просто верните свой (весь) объект person и любую дополнительную (отфильтрованную) информацию о нем в новом анонимном типе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...