出现暂时性错误时重试 LINQ to SQL 查询

And*_*rew 5 c# linq-to-sql

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

\n\n

我的问题是,是否有一个类似的函数可以在执行 LINQ to SQL 查询时被重写来处理此类错误?我\xe2\x80\x99m 猜测/希望 DataContext 类中有一个方法可以对数据库进行实际调用,并且可以覆盖该方法以执行重试。

\n\n

我见过的示例\xe2\x80\x99(如下所示)通常将 LINQ 表达式和枚举它的方法调用包装在重试块中:

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

}

\n\n

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

\n\n

I\xe2\x80\x99m 希望避免每次枚举 LINQ 表达式时都必须执行此操作。此外,通过延迟加载,对数据库的实际调用可能在时间和代码上与 LINQ 表达式很好地分离,因此如果可以在较低级别处理重试会更安全。

\n

Rya*_*yan 0

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

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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

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();
Run Code Online (Sandbox Code Playgroud)