Linq 将多个包含iQueryTables添加到基础iQueryTable会更改以前的每个iQueryTable

Linq 将多个包含iQueryTables添加到基础iQueryTable会更改以前的每个iQueryTable,linq,linq-to-sql,Linq,Linq To Sql,我花了大量的时间试图弄清楚为什么Linq2SQL正在更改我的SQL查询。这很难解释,我也找不到发生这种情况的任何原因。问题的症结在于,在IQueryable周围添加多个包含似乎会覆盖前面的每个IQueryable表达式。让我试着解释一下: 假设您有一个Linq2SQL查询,它为您提供了查询的基本框架。这是所有查询的基础 我正在动态添加where查询的部分,在下面的示例中显示为partQuery。where查询生成的表达式是正确的,当我将其添加到finalQuery时,它仍然是正确的。当我向最终查

我花了大量的时间试图弄清楚为什么Linq2SQL正在更改我的SQL查询。这很难解释,我也找不到发生这种情况的任何原因。问题的症结在于,在IQueryable周围添加多个包含似乎会覆盖前面的每个IQueryable表达式。让我试着解释一下:

假设您有一个Linq2SQL查询,它为您提供了查询的基本框架。这是所有查询的基础

我正在动态添加where查询的部分,在下面的示例中显示为partQuery。where查询生成的表达式是正确的,当我将其添加到finalQuery时,它仍然是正确的。当我向最终查询添加另一个partQuery时,问题出现了,它似乎覆盖了最终查询中的第一个查询,但向其中添加了第二个查询。或者如下所示,当添加第三个查询时,将覆盖前两个查询

以下是一些源代码示例:

foreach (var partQuery in whereStatements)
    {
        finalQuery = finalQuery.Where(
            dataEvent => partQuery.Contains(dataEvent.DataEventID)
            );
    }
partQuery的类型为IQueryable finalQuery是最终将在SQL server上执行的查询

        // the list of the wheres that are sent
        var whereStatements = new List<IQueryable<long>>();

        var query1 = DataEvent.GetQueryBase(context);
        query1 = query1.Where(
            dataEvent =>
            dataEvent.DataEventKeyID == (short)DataEventTypesEnum.TotalDollarAmount && dataEvent.ValueDouble < -50);

        whereStatements.Add(query1.Select(x => x.DataEventID));


        var query2 = DataEvent.GetQueryBase(context);
        query2 = query2.Where(
            dataEvent =>
            dataEvent.DataEventKeyID == (short)DataEventTypesEnum.ObjectNumber && dataEvent.ValueDouble == 6);

        whereStatements.Add(query2.Select(x => x.DataEventID));
当添加到最终查询时。。您将注意到第一个查询不再正确。。。。还有更多的事情要做

 {SELECT [t0].[DataEventID], [t0].[DataOwnerID], [t0].[DataTimeStamp]
 FROM [dbo].[DataEvents] AS [t0]
 WHERE (EXISTS(
  SELECT NULL AS [EMPTY]
  FROM [dbo].[DataEvents] AS [t1]
  INNER JOIN [dbo].[DataEventAttributes] AS [t2] ON [t1].[DataEventID] = [t2].[DataEventID]
  WHERE ([t1].[DataEventID] = [t0].[DataEventID]) AND ([t2].[DataEventKeyID] = @p0) AND ([t2].[ValueDouble] = @p1)
  )) AND (EXISTS(
  SELECT NULL AS [EMPTY]
  FROM [dbo].[DataEvents] AS [t3]
  INNER JOIN [dbo].[DataEventAttributes] AS [t4] ON [t3].[DataEventID] = [t4].[DataEventID]
  WHERE ([t3].[DataEventID] = [t0].[DataEventID]) AND ([t4].[DataEventKeyID] = @p2) AND ([t4].[ValueDouble] = @p3)
  )) AND ([t0].[DataOwnerID] = @p4)
 }
还有一个额外的好处。。。通过SQL探查器查看后,它似乎完全删除了第一个查询,并且最终SQL中的两个Exists子句实际上是同一个查询查询2。对于第一个查询,没有任何参数实际传递给SQl server

因此,在我对此的研究中,它似乎向SQl中添加了查询,但它用添加的最后一个子句替换了任何现有的where exists子句。再次确认这一点。。与上面的代码完全相同,但我添加了第三个查询。。。。看看它是怎么变化的

        var query3 = DataEvent.GetQueryBase(context);
        query3 = query3.Where(
            dataEvent =>
            dataEvent.DataEventKeyID != (short)DataEventTypesEnum.Quantity && dataEvent.ValueDouble != 5);

        whereStatements.Add(query3.Select(x => x.DataEventID));
我投了一些!=转到查询的最后一部分

 {SELECT [t0].[DataEventID], [t0].[DataOwnerID], [t0].[DataTimeStamp]
 FROM [dbo].[DataEvents] AS [t0]
 WHERE (EXISTS(
  SELECT NULL AS [EMPTY]
  FROM [dbo].[DataEvents] AS [t1]
  INNER JOIN [dbo].[DataEventAttributes] AS [t2] ON [t1].[DataEventID] = [t2].[DataEventID]
  WHERE ([t1].[DataEventID] = [t0].[DataEventID]) AND ([t2].[DataEventKeyID] <> @p0) AND ([t2].[ValueDouble] <> @p1)
  )) AND (EXISTS(
  SELECT NULL AS [EMPTY]
  FROM [dbo].[DataEvents] AS [t3]
  INNER JOIN [dbo].[DataEventAttributes] AS [t4] ON [t3].[DataEventID] = [t4].[DataEventID]
  WHERE ([t3].[DataEventID] = [t0].[DataEventID]) AND ([t4].[DataEventKeyID] <> @p2) AND ([t4].[ValueDouble] <> @p3)
  )) AND (EXISTS(
  SELECT NULL AS [EMPTY]
  FROM [dbo].[DataEvents] AS [t5]
  INNER JOIN [dbo].[DataEventAttributes] AS [t6] ON [t5].[DataEventID] = [t6].[DataEventID]
  WHERE ([t5].[DataEventID] = [t0].[DataEventID]) AND ([t6].[DataEventKeyID] <> @p4) AND ([t6].[ValueDouble] <> @p5)
  )) AND ([t0].[DataOwnerID] = @p6)
 }
请注意,现在所有三个内部查询都是在上面的查询不是这样的情况下进行的

我是不是完全疯了?当你告诉我我要拔指甲的时候,我是不是错过了一些简单的事情?我真的希望你告诉我,我们知道有时候会发生这种情况,而不是告诉我它看起来像MS框架中的一个bug


非常感谢您的帮助。也许我应该以另一种方式将动态查询部分发送到基本查询。我对想法持开放态度。

在没有充分评估您的示例的情况下,最突出的一点是:

foreach (var partQuery in whereStatements)
{
    finalQuery = finalQuery.Where(
        dataEvent => partQuery.Contains(dataEvent.DataEventID)
        );
}
由于该循环的结构方式,在每次迭代中生成的每个表达式最终将使用partQuery的最终值,即循环终止时出现的值。您可能希望这样:

foreach (var partQuery in whereStatements)
{
    var part = partQuery;
    finalQuery = finalQuery.Where(
        dataEvent => part.Contains(dataEvent.DataEventID)
        );
}
现在,part是捕获的变量,每次迭代都是唯一的,因此每个表达式都是唯一的。这种奇怪的行为最初是出于设计:参见


编辑:看起来这正是造成你问题的原因;最后一个查询中的子查询都是x-y形式,这是添加到whereStatements集合中的最后一个查询的形式。

该死,我再也不会忽略我的警告了。它在VS中有下划线,但我忽略了它。。我想范围应该是一样的。非常感谢。。第二双眼睛似乎解决了我的问题:
 {SELECT [t0].[DataEventID], [t0].[DataOwnerID], [t0].[DataTimeStamp]
 FROM [dbo].[DataEvents] AS [t0]
 WHERE (EXISTS(
  SELECT NULL AS [EMPTY]
  FROM [dbo].[DataEvents] AS [t1]
  INNER JOIN [dbo].[DataEventAttributes] AS [t2] ON [t1].[DataEventID] = [t2].[DataEventID]
  WHERE ([t1].[DataEventID] = [t0].[DataEventID]) AND ([t2].[DataEventKeyID] <> @p0) AND ([t2].[ValueDouble] <> @p1)
  )) AND (EXISTS(
  SELECT NULL AS [EMPTY]
  FROM [dbo].[DataEvents] AS [t3]
  INNER JOIN [dbo].[DataEventAttributes] AS [t4] ON [t3].[DataEventID] = [t4].[DataEventID]
  WHERE ([t3].[DataEventID] = [t0].[DataEventID]) AND ([t4].[DataEventKeyID] <> @p2) AND ([t4].[ValueDouble] <> @p3)
  )) AND (EXISTS(
  SELECT NULL AS [EMPTY]
  FROM [dbo].[DataEvents] AS [t5]
  INNER JOIN [dbo].[DataEventAttributes] AS [t6] ON [t5].[DataEventID] = [t6].[DataEventID]
  WHERE ([t5].[DataEventID] = [t0].[DataEventID]) AND ([t6].[DataEventKeyID] <> @p4) AND ([t6].[ValueDouble] <> @p5)
  )) AND ([t0].[DataOwnerID] = @p6)
 }
foreach (var partQuery in whereStatements)
{
    finalQuery = finalQuery.Where(
        dataEvent => partQuery.Contains(dataEvent.DataEventID)
        );
}
foreach (var partQuery in whereStatements)
{
    var part = partQuery;
    finalQuery = finalQuery.Where(
        dataEvent => part.Contains(dataEvent.DataEventID)
        );
}