如果实体框架查询中存在可选的导航属性,我该如何返回?

时间:2010-10-07 14:05:56

标签: linq entity-framework c#-4.0 entity-framework-4

我正在尝试使用以下查询返回布尔值:

var q = from inmate in context.Inmates
        select new
        {
            inmate.Id,
            IsCrazy = inmate.Certified != null
        };
仅当可选的IsCrazy导航属性不为null时,

true才应为Certified。但是,无论IsCrazy之间是否存在链接,Inmate > Certified始终都会返回true。

使用上面的代码和以下数据:

Inmate { 1 } --> { Certified }
Inmate { 2 } --> NULL
Inmate { 3 } --> { Certified }

我期待以下结果:

1, true
2, false
3, true

然而,所有结果都是真实的。我做错了什么?

然后我试图改回可选的导航属性,但这似乎是做一个内连接而只有返回疯狂的囚犯:

Inmate { 1 } --> { Certified }
Inmate { 3 } --> { Certified }
// Inmate 2 is missing

编辑:忘记提及,我使用的是EF 4.0 Code First。

编辑2:

这是SQL输出

SELECT 
[Extent1].[Id] AS [Id], 
CASE WHEN (cast(1 as bit) <> cast(0 as bit)) 
THEN cast(1 as bit) WHEN (1 = 0) THEN cast(0 as bit) END AS [C1]
FROM [dbo].[Inmate] AS [Extent1]

对我来说完全错了;没有提到任何Certified

编辑3:

我在LINQPad中尝试了以下代码(删除了囚犯的事,这是我的实际代码):

from i in Ingredients
join m in Meats 
    on new { i.IngId, i.VersionId } equals new { m.IngId, m.VersionId } into temp
from t in temp.DefaultIfEmpty()
select new
{
    IngId = i.IngId,
    IsMeat = t.MeatTypeId == null ? false : true
};

这将返回具有正确true / false值的所有3000个结果。实体框架中的相同代码将仅返回已实现一对一关系的结果。

这是LINQPad生成的SQL:

-- Region Parameters
DECLARE @p0 Int SET @p0 = 0
DECLARE @p1 Int SET @p1 = 1
-- EndRegion
SELECT [t0].[IngId], 
    (CASE 
        WHEN ([t1].[MeatTypeId]) IS NULL THEN @p0
        ELSE @p1
     END) AS [IsMeat]
FROM [Ingredient] AS [t0]
LEFT OUTER JOIN [MeatIngredient] AS [t1] ON ([t0].[IngId] = [t1].[IngId]) 
    AND ([t0].[VersionId] = [t1].[VersionId])

这是由EF生成的SQL:

SELECT 
[Extent1].[IngId] AS [IngId], 
cast(1 as bit) AS [C1]
FROM  [dbo].[Ingredient] AS [Extent1]
INNER JOIN [dbo].[MeatIngredient] AS [Extent2] 
    ON ([Extent1].[VersionId] = [Extent2].[VersionId]) 
        AND ([Extent1].[IngId] = [Extent2].[IngId])

3 个答案:

答案 0 :(得分:1)

好吧,我已经设法通过向后思考让它按预期工作。即检查可以为空的肉有一个成分(或仍然与最初的例子,检查证书是否有一个有效的囚犯):

var q = from i in context.Ingredients
        let m = i.Meat // AKA Certificate
        select new 
        {
            IngId = i.IngId,
            IsMeat = m.Ingredient != null 
        };

对于这样一个简单的查询,SQL很讨厌。如果我自己编写存储过程,它的大小约为4倍。但是,它运行时间为57毫秒,因此不必担心。

答案 1 :(得分:0)

不知道这是否有帮助。但试试

IsCrazy =!inmate.Certified.Equals(System.DBNull.Value)

答案 2 :(得分:0)

继续尝试做左外连接:

var q = from inmate in context.Inmates
join c in Certified on inmate.cId equals c.Id into temp //replace with whatever you will join on
from temp in temp.DefaultIfEmpty()
select new { inmate.Id, IsCrazy = c.IsCertified != null }; //replace to what it is you want to check

会是这样的。有关更具体的示例,可能有助于在此处了解有关数据库结构的更多信息。希望这会有所帮助。