我的表格结构如下:
Person 1-M PesonAddress
Person 1-M PesonPhone
Person 1-M PesonEmail
Person 1-M Contract
Contract M-M Program
Contract M-1 Organization
在此查询结束时,我需要一个填充的对象图,其中每个人都有:
现在我有了以下查询,我认为它工作得很好,但它有一些问题:
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;
问题在于它会根据标准过滤此人,但不会过滤合同或合同的程序。它带回了所有合同,每个人不仅具有组织ID为x的组合,而且每个合同的程序都分别相同。
我想要的只是那些至少有一份合同,其中包含一个OrgId为x的合同,并且该合同中的合同具有一个具有y的Id的程序......并且返回的对象图只包含合同匹配和该合同中匹配的程序。
我有点理解为什么它不起作用,但我不知道如何更改它以便它正在工作......
这是我迄今为止的尝试:
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对象):
IEnumerable
正在尝试强制转换为EntityCollection
因此,我如何让它工作。请记住,我正在尝试将此作为编译查询,所以我认为这意味着匿名类型已经出局。
答案 0 :(得分:2)
只是不要使用Include,手动过滤。您可以先过滤与所需ProgramId和OrganizationId相关联的合同。之后,您可以选择与所选合同相关的人员。 A附上了示例代码。您需要对其进行修改才能正确使用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 :(得分:1)
包含在实体框架中将始终带回关系中的所有内容,无法执行部分包含或Linq to SQL具有的等效的AssociateWith。
相反,如果您只想恢复一些合同,则需要将其拆分为两个查询,并利用实体框架执行的自动连接。
一旦两个查询都被执行,您的Person对象将仅包含Contracts集合中Contracts查询带回的合同。
答案 2 :(得分:0)
如同Mant101所说,你无法将Linq中的.Include部分过滤为实体。查看Person
对象,作为存储在数据库中的有关此人的所有信息的表示,包括所有contracts
。所有的装备都是分开做的。
这些问题似乎在这里经常出现。至少我觉得我见过一些,但找不到很多。以下是处理此主题的另一个问题:conditional include in linq to entities?。
那里还有一个可行的anser:只需以新的匿名类型返回你的(整个)人物对象,以及任何其他(过滤的)信息。