c# – 调用ToList()时内部LINQ查询的异常

昨天我正在研究一个代码重构,遇到一个异常,我真的找不到太多的信息.情况就是这样.

我们有一对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查询.我们在DTO中使用了很多LINQ投影. 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:在另一个有趣的转折中,如果不选择进入MasterCodeD,而是选择匿名类型,也不会在ToList()就位时抛出异常.

解决方法

我认为你偶然发现了Entity Framework中的一个错误. EF有一些逻辑可以选择适当的具体类型来实现集合.的HashSet< T>是它的最爱之一.显然(我不能完全遵循EF的源代码),它为ICollections选择HashSet,为IEnumerable选择List.

看起来EF试图通过使用接受IEqualityComparer< T>的constructor来创建HashSet. (这发生在EF’sDelegateFactory类,方法GetNewExpressionForCollectionType.)错误是它使用自己的ObjectReferenceEqualityComparer.但这是一个IEqualityComparer< object>,它无法转换为IEqualityComparer< int>.

一般来说,我认为最好不要在LINQ查询中使用ToList,并在DTO类型的集合中使用IEnumerable.因此,EF将有完全的自由选择合适的混凝土类型.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...