简体   繁体   English

Linq lambda表达式中的布尔短路评估

[英]Boolean shortcircuit evaluation in Linq lambda expression

I have the following Linq lambda expression: 我有以下Linq lambda表达式:

private IEnumerable<SubjectSelectorSubjectGroup> GetSubjectList()
{
    User user = db.Users.Find(WebSecurity.CurrentUserId);
    return db.RequiredSubjects.Where(r => !r.Subject.Name.Contains("Home"))
                              .GroupBy(r => r.Subject)
                              .OrderByDescending(r => r.Count())
                              .Select(r => new SubjectSelectorSubjectGroup()
                              {
                                  SubjectId = r.Key.SubjectId,
                                  SubjectName = r.Key.Name,
                                  IsInFavourites = HttpContext.Current.Request.IsAuthenticated &&
                                                  (user.Elective1 != null && user.Elective1.SubjectId == r.Key.SubjectId ||
                                                   user.Elective2 != null && user.Elective2.SubjectId == r.Key.SubjectId ||
                                                   user.Elective3 != null && user.Elective3.SubjectId == r.Key.SubjectId),
                                  Occurrences = r.Count()
                              });
}

When the user is not logged in then the user variable in this function is null. 当用户未登录时,此函数中的user变量为null。 This should not be a problem becuase short-circuit boolean evaluation should deal with this. 这不应该是一个问题,因为短路布尔评估应该处理这个问题。 The problem is, it doesn't! 问题是,它没有! Instead, a System.NullReferenceException is thrown. 而是抛出System.NullReferenceException

When the user is null HttpContext.Current.Request.IsAuthenticated returns false. 当用户为null时, HttpContext.Current.Request.IsAuthenticated返回false。 I have checked this by commenting out the bracketed section that references the user variable, and then expression evaluates correctly. 我通过注释引用user变量的括号部分来检查这一点,然后表达式正确评估。

Does anyone know why Linq to Sql tries to dereference the user variable in this situation when it shouldn't actually be necessary? 有谁知道为什么Linq to Sql在这种情况下试图取消引用user变量时它实际上不应该是必要的? Does anyone have a work around for this issue? 有没有人解决这个问题?

The entire expression is translated to and evaluated as SQL, which means that the && operator is not short circuited as expected. 整个表达式被转换为SQL并进行评估,这意味着&&运算符不会按预期短路。

You can solve the problem by building a list or array of the ElectiveX.SubjectId that you want to search for and then use tmpList.Contains(r.Key.SubjectId) in the query. 您可以通过构建要搜索的ElectiveX.SubjectId的列表或数组来解决问题,然后在查询中使用tmpList.Contains(r.Key.SubjectId) That will be translated into a WHERE IN (...) SQL expression. 这将被转换为WHERE IN (...) SQL表达式。

Here is how I resolved this using the suggestion given by Anders Abel . 以下是我使用Anders Abel给出的建议解决这个问题的方法。

private IEnumerable<SubjectSelectorSubjectGroup> GetSubjectList()
{
    List<string> userSubjects = new List<string>();
    if (HttpContext.Current.Request.IsAuthenticated)
    {
        User user = db.Users.Find(WebSecurity.CurrentUserId);
        if (user.Elective1 != null) { userSubjects.Add(user.Elective1.SubjectId); }
        if (user.Elective2 != null) { userSubjects.Add(user.Elective2.SubjectId); }
        if (user.Elective3 != null) { userSubjects.Add(user.Elective3.SubjectId); }
    }

    return db.RequiredSubjects.Where(r => !r.Subject.Name.Contains("Home"))
                              .GroupBy(r => r.Subject)
                              .OrderByDescending(r => r.Count())
                              .Select(r => new SubjectSelectorSubjectGroup()
                              {
                                   SubjectId = r.Key.SubjectId,
                                   SubjectName = r.Key.Name,
                                   IsInFavourites = userSubjects.Contains(r.Key.SubjectId),
                                   Occurrences = r.Count()
                              });
}

The only reason I can think of such behaviour is that your query is getting translated to SQL (since its LINQ to SQL) , and for user.Elective it is trying to generate a CASE statement. 我能想到这种行为的唯一原因是你的查询被转换为SQL (因为它的LINQ to SQL) ,而对于user.Elective它试图生成一个CASE语句。 That is why you are getting the error. 这就是你得到错误的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM