在瞬态错误上重试LINQ到SQL查询

本文关键字:LINQ SQL 查询 重试 错误 | 更新日期: 2023-09-27 18:06:18

重写System.Data.Linq.DataContext很方便。SubmitChanges(ConflictMode failureMode)方法,以便在插入、更新或删除记录时发生瞬态错误(如死锁或超时)时重试。

我的问题是,是否有一个类似的函数,可以被覆盖,以处理这样的错误时,执行LINQ到SQL查询?我猜/希望在DataContext类中会有一个方法,它对数据库进行实际调用,并且可以被重写以执行重试。

我看到的示例(如下所示)通常将LINQ表达式和在重试块中枚举它的方法调用包装起来:

try
{
    e.Result = retry.ExecuteAction(() =>
        {
            Deadlock(); // Artificially create a deadlock condition
            CustomerOrdersDataContext ctx = new CustomerOrdersDataContext();
            ctx.Connection.ConnectionString = builder.ConnectionString;
            ctx.CommandTimeout = 3;
            var results = from c in ctx.customers
                            from o in c.orders
                            from i in o.order_items
                            select new { c.lname, c.fname, i.product.product_name, i.quantity };
            return results.ToList();
        });
}
catch (SqlException ex)
{
    MessageBox.Show(ex.Message, "SqlException");
}

}

(http://social.technet.microsoft.com/wiki/contents/articles/retry-logic-for-transient-failures-in-sql-azure.aspx)

我希望避免每次枚举LINQ表达式时都必须这样做。此外,由于延迟加载,对数据库的实际调用可能在时间和代码上与LINQ表达式完全分离,因此,如果重试可以在较低级别处理,会更安全。

在瞬态错误上重试LINQ到SQL查询

您可以通过创建一个为您执行重试的扩展方法来完成:

public static List<T> ToList_DeadlockRetry<T>(this IEnumerable<T> source, int retryAttempts = 5)
{
    while (retryAttempts > 0)
    {
        try
        {
            return source.ToList();
        }
        catch (SqlException ex)
        {
            retryAttempts--;
            if (retryAttempts == 0)
            {
                throw ex;
            }
        }
    }
}

那么你可以这样使用:

var results = from c in ctx.customers
              from o in c.orders
              from i in o.order_items
              select new { c.lname, c.fname, i.product.product_name, i.quantity };
 return results.ToList_DeadlockRetry();