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方法进行检查,正如你们中的许多人所说的那样。

IQueryable在调用Count c#时返回null

我的猜测是您的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一开始的查询是错误的,但以上几点仍然有效。