C# LINQ关联数据库与内存列表报错:无法创建指定类型常量值
问题原因
你遇到的这个错误,是因为Entity Framework(EF)无法直接将内存中的List<info.User>和数据库端的IQueryable查询做关联操作。UserDbQry是未执行的数据库查询(IQueryable类型),EF会尝试把整个关联逻辑转换成SQL语句,但内存里的info.User是自定义对象,EF没法将其转换成SQL能识别的常量类型,所以抛出这个错误。
解决方案
有两种可行的处理方式,可根据你的需求选择:
方案1:先把数据库数据拉到内存再做关联
把UserDbQry的结果通过ToList()加载到内存,之后再和studyAccessList做关联,整个操作在客户端内存中完成,不会触发EF的SQL转换逻辑:
List<info.User> studyAccessList = new List<info.User>(); using (var Db = new Entities()) { // 先将数据库数据加载到内存 var UserDbList = (from data in Db.USER where data.System == "something" && data.Active == true select data).ToList(); // 内存中执行左外连接 var joinQry = from s1 in UserDbList join t2 in studyAccessList on new { Study = s1.Study, Email = s1.Email } equals new { Study = t2.Study, Email = t2.Email } into rs from r in rs.DefaultIfEmpty() where r == null // 放开此注释,筛选出不在studyAccessList里的用户 select s1; foreach (var inactiveUser in joinQry) { string xml = String.Format("<User><Study>{0}</Study><Email>{1}</Email><Active>false</Active></User>", inactiveUser.Study, inactiveUser.Email); recordCount = recordCount + ProcessXml(wsu, xml, log.ErrorMsgPrefix); } }
方案2:提取关键字段,在数据库端筛选(更高效)
如果数据量较大,方案1可能性能不佳,你可以先把studyAccessList中的Study和Email提取成匿名类型集合,然后用Contains在数据库端筛选出不在这个集合里的用户,避免把大量数据拉到内存:
List<info.User> studyAccessList = new List<info.User>(); using (var Db = new Entities()) { // 提取内存列表中的关键标识组合 var studyEmailPairs = studyAccessList.Select(u => new { u.Study, u.Email }).ToList(); // 直接在数据库端筛选不在内存列表中的用户 var joinQry = from data in Db.USER where data.System == "something" && data.Active == true && !studyEmailPairs.Any(p => p.Study == data.Study && p.Email == data.Email) select data; foreach (var inactiveUser in joinQry) { string xml = String.Format("<User><Study>{0}</Study><Email>{1}</Email><Active>false</Active></User>", inactiveUser.Study, inactiveUser.Email); recordCount = recordCount + ProcessXml(wsu, xml, log.ErrorMsgPrefix); } }
注意点
- 方案2更适合大数据量场景,筛选逻辑在数据库端完成,能减少内存占用和数据传输。
- 如果你需要完整的左外连接结果(而非仅筛选不存在的记录),方案1更适配。
内容的提问来源于stack exchange,提问作者Adam Mohammed Dabdoub
相关产品推荐
相关产品推荐

