2010-04-27 5 views
4

Моей структура таблицы выглядит следующим образом:Linq гуру - фильтрация связанные с ней структуры

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; 

Проблема заключается в том, что он фильтрует человека по критериям, а не по контрактам или программам контракта. Он возвращает все Контракты, что каждый человек имеет не только те, которые имеют Организацию 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 объект):

  • Я остался сделать отображение на себя, в данном случае существует довольно много, чтобы отобразить
  • Когда я пытаюсь сопоставить список с собственностью (т. Стипендия = currentScholarships) он говорит, что я не могу, потому что IEnumerable пытается быть отлиты в EntityCollection
  • Include не работает

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

+0

Вы уверены, что контракт-программа M-M? Итак, для этого есть таблица перекрестных ссылок? – Fedor

+0

Да ... В базе данных есть таблица между Контрактом и Программой, которая облегчает ММ, но структура Entity абстрагировала эту «сущность» ... –

ответ

2

Просто не используйте Включить, отфильтруйте вручную. Вы можете сначала фильтровать Контракты, связанные с требуемыми 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; 
+0

@Fedor: Я попытался реализовать этот подход в своей ситуации, и я получаю следующее исключение ... LINQ to Entities не распознает метод «System.Collections.Generic.List'1 [Contract] (System.Collections.Generic .IEnumerable'1 [Contract]) ', и этот метод не может быть переведен в выражение хранилища. –

+0

Так что это необходимо исправить. К сожалению, я не могу создать свой код, чтобы рассказать, в чем проблема. Вы можете использовать IEnumerable вместо List в PersonDetails. Или даже используйте анонимный класс вместо PersonDetails. – Fedor

+0

Хотя это не точный ответ, я повел меня по дорожке, чтобы найти его ... Спасибо за вашу помощь. –

1

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

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

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

+0

Прошу прощения, но я действительно не нашел это все что полезно ... не могли бы вы предоставить образец того, о чем вы говорите ... –

+2

Вот ссылка на статью с примерами, которая на самом деле была написана в ответ на вопрос о переполнении стека: http: // blogs. msdn.com/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx – Mant101

0

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

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

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

+0

Проблема с этим подходом, как я уже упоминал выше, я оставил делать все сопоставление я ... что в этом случае есть тонна отображения, которую я должен был бы сделать в инструкции select. Также некоторые из этих сопоставлений невозможно сделать с использованием анонимных типов из-за скомпилированного характера запроса ... Наконец, в запросе, который был принят как ответ в вашей ссылке, он эффективно выполняет только левое соединение, а не внутреннее соединение. .. Мне нужно, чтобы это были только те дилеры, у которых есть части, соответствующие критериям, а затем только те части, которые также соответствуют критериям ... –

+0

Напишите один запрос, который возвращает только те части, которые вы хотите, и извлекайте результаты в память (ToList) Напишите один запрос, который возвращает на дилерские центры, которые вы хотите, и поместите результаты в память. Напишите запрос, который возвращает объект Person, который вы хотите. Когда вы повторяете это, каждый человек будет иметь только дилерские центры, возвращенные во втором запросе, и у каждого Дилерства будут только части, возвращенные первым запросом. Нет необходимости в каких-либо анонимных типах или сопоставлении, структура автоматически свяжет отношения. Вы также можете предварительно скомпилировать все три запроса. – Mant101

 Смежные вопросы

  • Нет связанных вопросов^_^