IQueryable在调用Count c#时返回null
本文关键字:返回 null Count 调用 IQueryable | 更新日期: 2023-09-27 18:02:32
我在尝试从以下查询中获取计数时遇到问题:
var usersView = PopulateUsersView(); //usersView is an IQueryable object
var foo = usersView.Where(fields => fields.ConferenceRole.ToLower().Contains("role"));
其中UsersView是一个由称为users的EF实体填充的类(参考上面代码中的第一行(
这是UsersView类的类定义:
public class UsersView
{
public int UserId { get; set; }
public string Title { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string PostCode { get; set; }
public string CountryName { get; set; }
public string WorkPlaceName { get; set; }
public string Gender { get; set; }
public string EMail { get; set; }
public string Company { get; set; }
public string RoleName { get; set; }
public string ConferenceRole { get; set; }
}
正如我所说的试图执行foo行。Count((返回Null Exception,这可能是因为ConferenceRole列在数据库中允许Null。
现在我不能理解的是,当我直接在ObjectQuery上调用同一个查询时,记录的计数(即调用foo2.Count(((会毫无例外地返回。
var foo2 = entities.users.Where(fields => fields.ConferenceRole.ToLower().Contains("role"));
是否可以使用上面的相同查询,但使用IQueryable usersView对象?
(对我来说,使用usersView对象而不是直接查询实体是至关重要的。users实体(
编辑
以下是PopulateUsersView方法的代码
private IQueryable<UsersView> PopulateUsersView()
{
using (EBCPRegEntities entities = new EBCPRegEntities())
{
var users = entities.users.ToList();
List<UsersView> userViews = new List<UsersView>();
foreach (user u in users)
{
userViews.Add(new UsersView()
{
UserId = u.UserId,
Title = u.Title,
Name = u.Name,
Surname = u.Surname,
Street1 = u.Street1,
Street2 = u.Street2,
City = u.City,
PostCode = u.Post_Code,
CountryName = u.country.Name,
WorkPlaceName = u.workplace.Name,
Gender = u.Gender,
EMail = u.E_Mail,
Company = u.Company,
RoleName = u.roles.FirstOrDefault().Name,
ConferenceRole = u.ConferenceRole
});
}
return userViews.AsQueryable();
}
}
感谢
更新。。。
感谢各位,我终于找到了IQueryable和ObjectQuery对象之间区别的好答案。
作为一个解决方案,我正在检查ConferenceRole是否为null,然后使用contains方法进行检查,正如你们中的许多人所说的那样。
我的猜测是您的PopulateUsersView()
方法实际上正在执行一个查询并返回一个IQueryable Linq to Objects对象,而foo2
行仅在SQL层中执行查询。如果是这种情况,显然PopulateUsersView()
将是执行Count
的一种非常低效的方式
调试:
- 你能发布一些
PopulateUsersView()
的代码吗 - 你能试着通过EF跟踪提供程序运行这两组代码,看看SQL中执行了什么吗?(参见http://code.msdn.microsoft.com/EFProviderWrappers)
更新
@Ryan-感谢您将代码发布到PopulateUsersView
看起来我的猜测是对的——您正在执行一个查询,将整个表返回到List
中——然后使用Linq2Objects进一步查询该列表。
@ntziolis为您的问题提供了一个解决方案——在执行ToLower()
之前测试null。然而,如果您的唯一要求是Count
非空项目列表,那么我建议您考虑更改PopulateUsersView
方法或更改您的整体设计。如果您只需要一个Count
,那么确保数据库完成这项工作而不是C#代码将更加高效。如果表有很多行,情况尤其如此——例如,您肯定不想从数据库中将1000行拉回到内存中。
更新2
请考虑对此进行优化,而不仅仅是进行简单的!= null
修复。
查看您的代码,有几行代码会导致多次sql调用:
CountryName = u.country.Name
WorkPlaceName = u.workplace.Name
RoleName = u.roles.FirstOrDefault().Name
由于这些都是在foreach循环中调用的,那么要计算大约500个用户的计数,那么你可能会进行大约1501次SQL调用(尽管一些角色和国家/地区可能会被缓存(,总共返回一兆字节的数据?所有这些只是为了计算一个单一的整数Count
?
在调用方法之前,请尝试检查ConferenceRole
是否为null:
var foo = usersView.Where(fields => fields.ConferenceRole != null
&& fields.ConferenceRole.ToLower().Contains("role"));
这将使您能够在用户视图上调用count方法。
那么,为什么它对ObjectQuery
有效呢?
当对ObjectQuery执行查询时,LinqToSql将您的查询转换为正确的sql,该sql不会出现空值问题,类似于以下内容(它是示例标记sql,只有实际查询看起来大不相同,而且使用了"="而不是检查包含(:
SELECT COUNT(*) from USERS U WHERE TOLOWER(U.CONFERENCEROLE) = 'role'
与:NET代码的区别在于:它不会在对象上调用方法,而只是调用方法并传递值,因此在这种情况下不会出现NullReference。
为了确认这一点,您可以尝试在调用where方法之前强制.NET运行时执行SQL,只需在.Where()
之前添加一个ToList()
var foo2 = entities.users.ToList()
.Where(fields => fields.ConferenceRole.ToLower().Contains("role"));
这将导致与您在UserView
中看到的错误完全相同的错误。
是的,这将首先返回整个用户表,所以不要在实时代码中使用它;(
更新
我不得不更新答案,因为我;p一开始的查询是错误的,但以上几点仍然有效。