繁体   English   中英

了解延迟执行:是否重新执行Linq查询每次引用其匿名对象集合时?

[英]Understanding Deferred Execution: Is a Linq Query Re-executed Everytime its collection of anonymous objects is referred to?

我目前正在尝试编写一些代码,这些代码将在两个单独的数据库上运行查询,并将结果返回给匿名对象。 一旦我有两个匿名对象集合,我需要对两个集合进行比较。 比较是我需要检索webOrders中的所有记录,但不需要检索foamOrders中的所有记录。 目前,我正在使用Linq进行比较。 我的主要问题是两个原始查询都返回了大约30,000条记录,而现在我的代码需要花费太长时间才能完成。 我是新手使用Linq,所以我试图理解是否使用Linq比较两个匿名对象集合实际上会导致数据库查询反复运行 - 由于延迟执行。 这可能是一个明显的答案,但我还没有非常明确地理解Linq和匿名对象如何使用延迟执行。 我希望有人能够启发我。 以下是我的代码......

private DataTable GetData()
{
    using (var foam = Databases.Foam(false))
    {
        using (MySqlConnection web = new MySqlConnection(Databases.ConnectionStrings.Web(true)
        {
            var foamOrders = foam.DataTableEnumerable(@"
                    SELECT order_id
                    FROM   Orders
                    WHERE  order_id NOT LIKE 'R35%'
                    AND originpartner_code = 'VN000011'
                    AND orderDate > Getdate() - 7 ")
                .Select(o => new
                {
                    order = o[0].ToString().Trim()
                }).ToList();

            var webOrders = web.DataTableEnumerable(@"
                    SELECT ORDER_NUMBER FROM TRANSACTIONS AS T WHERE
                    (Str_to_date(T.ORDER_DATE, '%Y%m%d %k:%i:%s') >= DATE_SUB(Now(),  INTERVAL 7 DAY))
                    AND (STR_TO_DATE(T.ORDER_DATE, '%Y%m%d %k:%i:%s') <= DATE_SUB(NOW(),  INTERVAL 1 HOUR))")
                .Select(o => new
                {
                    order = o[0].ToString().Trim()
                }).ToList();
            return (from w in webOrders
                    where !(from f in foamOrders
                            select f.order).Contains(w.order)
                    select w
                ).ToDataTable();
        }
    }
}

当你这样做时,你的linq不再被推迟

ToDataTable();

在那时,它被拍摄为已完成并永远拂去灰尘。

转换它时,foamOrders和webOrders也是如此

ToList();

你可以把它做成一个查询。 我没有mySQL来检查它。

关于延期执行:

方法.ToList()迭代IEnumerable检索所有值并用该值填充新的List<T>对象。 所以在这一点上绝对不是延迟执行。

它最有可能与.ToDataTable();相同.ToDataTable();

PS但我建议:

  1. 使用自定义类型而不是匿名类型。
  2. 不要使用LINQ比较对象,因为它不是真正有效(linq正在做额外的工作)
  3. 您可以创建自定义MyComparer类(可能实现IComparer接口)和比较两个实体的Compare<T1, T2>类的方法。 然后你可以创建另一个方法来比较两组实体,例如T1[] CompareRange<T1,T2>(T1[] entities1, T2[] entities2)在循环中重用你的Compare方法并返回操作的结果

PS一些其他资源密集型操作可能会导致重大性能损失(如果您需要执行数千次操作):

  1. 枚举器对象的使用( foreach循环或一些LINQ方法)

可能的解决方案:如果可能,尝试使用for循环。

  1. 广泛使用匿名方法(编译器需要大量时间来编译lambda表达式/运算符);

可能的解决方案:将lambda存储在委托中(如Func<T1, T2>

如果它将来帮助任何人,我的新代码将粘贴在下面。 现在快得多运行。 感谢大家的帮助,我了解到即使我的数据库查询的延迟执行被切断,结果在我使用.ToList()后变为静态,使用Linq来比较结果集合的效率非常低。 我转而使用for循环。

private DataTable GetData()
    {
        //Needed to have both connections open in order to preserve the scope of var foamOrders and var webOrders, which are both needed in order to perform the comparison.
        using (var foam = Databases.Foam(isDebug))
        {
            using (MySqlConnection web = new MySqlConnection(Databases.ConnectionStrings.Web(isDebug)))
            {
                var foamOrders = foam.DataTableEnumerable(@"
            SELECT foreignID
            FROM   Orders
            WHERE  order_id NOT LIKE 'R35%'
            AND originpartner_code = 'VN000011'
            AND orderDate > Getdate() - 7 ")
                                     .Select(o => new
                                     {
                                         order = o[0].ToString()
                                                     .Trim()
                                     }).ToList();


                var webOrders = web.DataTableEnumerable(@"
            SELECT ORDER_NUMBER FROM transactions AS T WHERE
                                                (Str_to_date(T.ORDER_DATE, '%Y%m%d %k:%i:%s') >= DATE_SUB(Now(),  INTERVAL 7 DAY))
                                                AND (STR_TO_DATE(T.ORDER_DATE, '%Y%m%d %k:%i:%s') <= DATE_SUB(NOW(),  INTERVAL 1 HOUR))
                                                 ", 300)
                            .Select(o => new
                            {
                                order = o[0].ToString()
                                            .Trim()

                            }).ToList();


                List<OrderNumber> on = new List<OrderNumber>();

                foreach (var w in webOrders)
                {
                    if (!foamOrders.Contains(w))
                    {
                        OrderNumber o = new OrderNumber();
                        o.orderNumber = w.order;
                        on.Add(o);
                    }
                }

                return on.ToDataTable();

            }
        }


    }


    public class OrderNumber
    {
        public string orderNumber { get; set; }
    }


 }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM