2014-07-03 34 views
3

我一定要失去我的心......请看看下面的 enter image description here投影条件判断错误

现在看的价值观,我正在上查询: enter image description here enter image description here

你可以看到ETouchesEvent为空,事件不是......那么为什么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; 
    } 
+0

我怀疑这是因为这两个属性都是使用相同ID字段的关联。例如它们都使用“EntityID”链接。我怀疑Linq-to-sql将其转换为ISNULL(EntityID),而不是检查是否有可用的记录 – Peter

+0

这可能是一个调试器工件。尝试移动'.ToList()'上面的一行。当你调试时,跳过第一行(现在用'。ToList()'),只有当你到达第二行时(现在只是'return result;'),才将鼠标悬停在鼠标上。 –

+0

@BrankoDimitrijevic非常感谢您的建议。我只是试过了,但它给了我相同的结果......我现在正在考虑这是Linq to SQL中的一个错误。 – Peter

回答

0

我没有找到关于这种行为的任何文件,但它似乎LINQ到SQL翻译看外键列的背后关系(在这种情况下是EntityID)来查看它是否为空而不是链接的记录。生成的SQL清楚地显示了这一点。

0

好的。

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

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

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

但是,由该联合生成的SQL不能使这两种类型之间的区别(CASE当生成不会做你所需要的,这是“一致的”)。

所以你必须检查一些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”,不仅是“奥姆”。

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

稍微多点。 联合后,pi.ETouchesEvent上的任何测试都会生成与pi.Event完全相同的sql(并且它们不能为空)。

所以,我想你也可以改变一年测试

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