投影条件评估错误

时间:2014-07-03 10:15:13

标签: c# linq linq-to-sql

我一定是在失去理智......请看下面的内容 enter image description here

现在看看我正在查询的值: enter image description here enter image description here

你可以看到ETouchesEvent是null而Event不是......那么为什么Linq to SQL认为ETouchesEvent不为null?在我的第一张照片中,每个结果应为1。

[更新] 下面是生成的T-SQL,您可以清楚地看到它使用entityID来检查null

{SELECT 
    (CASE 
        WHEN ([t5].[EntityID]) IS NULL THEN @p1
        WHEN ([t5].[EntityID]) IS NULL THEN @p2
        ELSE @p3
     END) AS [value]
FROM (
    SELECT [t4].[ParticipationItemID], [t4].[EntityID]
    FROM (
        SELECT [t0].[ParticipationItemID], [t0].[IsLocalEvent], [t0].[IsProject], [t0].[IsOther], [t0].[EntityID], [t0].[IsEtouchesEvent]
        FROM [ParticipationItem] AS [t0]
        INNER JOIN [dbo].[Event] AS [t1] ON [t0].[EntityID] = ([t1].[Id])
        WHERE [t0].[IsLocalEvent] = 1
        UNION
        SELECT [t2].[ParticipationItemID], [t2].[IsLocalEvent], [t2].[IsProject], [t2].[IsOther], [t2].[EntityID], [t2].[IsEtouchesEvent]
        FROM [ParticipationItem] AS [t2]
        INNER JOIN [ETouchesEvent] AS [t3] ON [t2].[EntityID] = ([t3].[ETouchesEventID])
        WHERE [t2].[IsEtouchesEvent] = 1
        ) AS [t4]
    ) AS [t5]
WHERE ((([t5].[EntityID]) IS NOT NULL) OR (([t5].[EntityID]) IS NOT NULL)) AND (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [OrganisationParticipation] AS [t6]
    WHERE (([t6].[OrganisationID]) = @p0) AND ([t6].[ParticipationitemID] = ([t5].[ParticipationItemID]))
    ))
}

这就是所有代码:

    public List<int> GetParticipationYears(int? organisationID)
    {
        var result = (from p in GetParticipation(organisationID, null)
               where p.ETouchesEvent != null || p.Event != null
                select p.ETouchesEvent == null ? 1 : (p.Event == null ? 5 : 0));
               //select p.IsEtouchesEvent ? p.ETouchesEvent.StartDate.Year : (p.IsLocalEvent ? p.Event.StartDate.Year : 0)); //<== this does work!
        return result.Distinct().ToList();
    }

    public IQueryable<ParticipationItem> GetParticipation(int? organisationID, List<int> filterByYears)
    {
        var result = (from pi in DB.ParticipationItems
                      join e in DB.Events on pi.EntityID equals e.Id
                      where pi.IsLocalEvent
                      select pi)
                    .Union(
                      from pi in DB.ParticipationItems
                      join e in DB.ETouchesEvents on pi.EntityID equals e.ETouchesEventID
                      where pi.IsEtouchesEvent
                      select pi);

        if (filterByYears != null)
            result = result.Where(pi => (pi.IsEtouchesEvent && pi.ETouchesEvent != null && filterByYears.Contains(pi.ETouchesEvent.StartDate.Year)) ||
                                        (pi.IsLocalEvent && pi.Event != null && filterByYears.Contains(pi.Event.StartDate.Year)));

        if (organisationID.HasValue)
            return result.Where(pi => pi.OrganisationParticipations.Any(x => x.OrganisationID == organisationID));
        else
            return result;
    }

2 个答案:

答案 0 :(得分:0)

确定。

所以问题可能来自你的联盟。

联盟的所有部分必须共享相同数量的字段(具有相同类型)。

在您的情况下,联盟起作用是因为EventsETouchesEvents必须从同一个类继承,或实现相同的接口,或者只是相同。

但是这个联合生成的sql不能区分这两种类型(生成的CASE WHEN不能做你需要的,这是“连贯的”)。

因此,您必须检查sql可以区分的内容,这似乎只是IsLocalEventIsEtouchesEvent

所以(如果我错了就改变逻辑)

var result = (from p in GetParticipation(organisationID, null)
               // don't need a where clause, you're doing a join in your union, so any returned part will have an event (which might be a EtouchesEvent or an Event
                select !p.IsEtouchesEvent  
                       ? 1 
                       : !p.IsLocalEvent 
                             ? 5 
                             : 0);

我同意这根本不直观,但有时你必须考虑“SQL”,而不仅仅是“Orm”。

如果你使用扁平化物体,而不是那种情况下的实体,那可能会更清楚。

点点滴滴。 在你的联合之后,pi.ETouchesEvent上的任何测试都将生成与pi.Event完全相同的sql(并且它们不能为空)。

所以我认为你也可以将年份测试更改为

if (filterByYears != null)
            result = result.Where(pi =>  filterByYears.Contains(pi.ETouchesEvent.StartDate.Year);

答案 1 :(得分:0)

我没有找到关于此行为的任何文档,但似乎Linq to SQL转换正在查看关系背后的外键列(在本例中为EntityID),以查看它是否为空而不是链接记录。生成的SQL清楚地显示了这一点。