昨天我在进行代码重构时遇到了一个异常,但我很难找到关于它的更多信息。以下是情况简述。
我们有一对EF实体通过关系表之间具有多对多的关系。涉及的对象看起来像这样,省略了不必要的部分。
public partial class MasterCode
{
public int MasterCodeId { get; set; }
...
public virtual ICollection<MasterCodeToSubCode> MasterCodeToSubCodes { get; set; }
}
public partial class MasterCodeToSubCodes
{
public int MasterCodeToSubCodeId { get; set; }
public int MasterCodeId { get; set; }
public int SubCodeId { get; set; }
...
}
现在,我尝试对这些实体运行一个LINQ查询。我们使用很多LINQ投影到DTOs中。以下是DTO和查询。masterCodeId是传递的参数。
public class MasterCodeDto
{
public int MasterCodeId { get; set; }
...
public ICollection<int> SubCodeIds { get; set; }
}
(from m in MasterCodes
where m.MasterCodeId == masterCodeId
select new MasterCodeDto
{
...
SubCodeIds = (from s in m.MasterCodeToSubCodes
select s.SubCodeId).ToList(),
...
}).SingleOrDefaultAsync();
内部查询抛出以下异常Expression of type 'System.Data.Entity.Infrastructure.ObjectReferenceEqualityComparer' cannot be used for constructor parameter of type 'System.Collections.Generic.IEqualityComparer`1[System.Int32]'
我们之前在代码的其他地方做过这样的嵌套查询,并且没有遇到任何问题。不同之处在于,这次我们不是新建一个对象并将其投影到其中,而是返回了一组我们想要放入列表中的整数。
我通过将MasterCodeDto上的ICollection更改为IEnumerable并删除ToList()来找到了一种解决方法,但我从未能够找出为什么不能只选择id并将其作为列表返回。
有人对这个问题有任何见解吗?通常,当它不是内部查询的一部分时,只返回一个id字段并调用ToList()是可以正常工作的。我是否忽略了防止发生这种操作的内部查询限制?
谢谢。
编辑:为了举例说明这个模式在哪里起作用,我将展示一个可以工作的查询的例子。
(from p in Persons
where p.PersonId == personId
select new PersonDto
{
...
ContactInformation = (from pc in p.PersonContacts
select new ContactInformationDto
{
ContactInformationId = pc.PatientContactId,
...
}).ToList(),
...
}).SingleOrDefaultAsync();
在这个例子中,我们选择一个新的Dto而不仅仅是选择单个值,它可以正常工作。问题似乎源于只选择一个单一的值。
编辑2:另一个有趣的变化是,如果我选择匿名类型而不是选择MasterCodeDto,那么在使用ToList()时也不会抛出异常。
ToList()
导致了错误吗? - flindeberg