Entity framework 即使在得到 false 后评估子句

Entity framework evaluating clause even after getting false

var exercises = _repository.Exercises.Where(a =>
    userPrincipal.User != null && // false 
    (
        userPrincipal.Activated && a.PrivacyString == Privacy.PUBLIC_TO_REGISTERED_USERS.ToString() ||
        userPrincipal.User.Id == a.User.Id && a.PrivacyString == Privacy.PRIVATE.ToString()
    )
).ToList();

这是我的代码,这永远不会超出 false,但它也是 运行 底部子句。 基本上有空检查,但现在 EF 给我空指针错误

{"Non-static method requires a target."}

当我从查询中删除 userPrincipal.User.Id 时,我没有得到异常,所以我知道 userPrincipal.User 为空。

编辑:

_存储库定义。

public DbSet<Exercise> Exercises { get; set; }
IQueryable<Exercise> IRepository.Exercises {
        get { return Exercises; }
}

编辑:EF 生成的查询。

SELECT 
1 AS [C1], 
CAST(NULL AS int) AS [C2], 
CAST(NULL AS varchar(1)) AS [C3], 
CAST(NULL AS varchar(1)) AS [C4], 
CAST(NULL AS varchar(1)) AS [C5], 
CAST(NULL AS varchar(1)) AS [C6], 
CAST(NULL AS varchar(1)) AS [C7], 
CAST(NULL AS int) AS [C8]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
WHERE 1 = 0

空指针错误是检索 userPrincipal 变量 属性 值的结果,该变量是空引用。

EF 将查询转换为 SQL,并将所有使用的内存值转换为 sql 参数。例如,当您在查询中使用 userPrincipal.Activated 时,EF 会从表达式树中检索 PropertyInfo(或 FieldInfo 或 MethodInfo),并使用它从对象中检索值。为此,您需要引用包含该值的对象。如果该对象是空引用,则会出现您看到的异常。

简而言之:抛出异常是因为如果您使用的对象是空引用,EF 无法检索属性的值。

另请参阅:

有效的最终解决方案,在查询外部进行空检查:

var exercises = _repository.Exercises;

if (userPrincipal.User == null) {
    exercises = exercises.Where(a => a.PrivacyString == Privacy.PUBLIC.ToString());
} else {
    exercises = exercises.Where(a => 
        a.PrivacyString == Privacy.PUBLIC.ToString() ||
        userPrincipal.Activated && a.PrivacyString == Privacy.PUBLIC_TO_REGISTERED_USERS.ToString() ||
        userPrincipal.User.Id == a.User.Id && a.PrivacyString == Privacy.PRIVATE.ToString());
}