I have the following Linq lambda expression:
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. 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.
When the user is null HttpContext.Current.Request.IsAuthenticated returns false. I have checked this by commenting out the bracketed section that references the user variable, and then expression evaluates correctly.
Does anyone know why Linq to Sql tries to dereference the user variable in this situation when it shouldn’t actually be necessary? 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.You can solve the problem by building a list or array of the
ElectiveX.SubjectIdthat you want to search for and then usetmpList.Contains(r.Key.SubjectId)in the query. That will be translated into aWHERE IN (...)SQL expression.