在强类型 DataSet TableAdapter 中使用的 CommandTimeout 如何设置?

7

前言:

在过去的五年里,我们公司编写了许多应用程序和工具。不幸的是,许多开发这些应用程序的人使用了强类型数据集,我正在考虑禁止在我们的店内使用它们...

现在,一个使用强类型数据集的较大进程超时了... 我打算在接下来的几个月内使用nHibernate重新编写整个过程,但目前我需要更改超时时间,以便我们的用户可以使用该过程,尽管速度较慢... 不幸的是,Microsoft使命令超时方法私有化,因此我无法直接访问它们。

到目前为止,我找到的唯一解决方案是为每个TableAdapter创建一个局部类,并在其中包含超时方法...

这相当笨拙,因为这意味着要为相当多的TableAdapters添加局部类...

有没有人知道更有效的处理方法?

7个回答

4

我使用反射来“解决”这个问题。(虽然VS2010模型允许公开Adapter属性,但例如在GetData之前,SelectCommand等将为null。)

我目前正在使用的“丑陋但功能性”的代码:

void SetAllCommandTimeouts(object adapter, int timeout)
{
    var commands = adapter.GetType().InvokeMember(
            "CommandCollection",
            BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
            null, adapter, new object[0]);
    var sqlCommand = (SqlCommand[])commands;
    foreach (var cmd in sqlCommand)
    {
        cmd.CommandTimeout = timeout;
    }
}

// unfortunately this still requires work after a TableAdapter is obtained...
var ta = new MyTableAdapter();
SetAllCommandTimeouts(ta, 120);
var t = ta.GetData();

由于缺乏共同的基础/接口,实际上不可能更好地键入适配器(尽管可能对Component),请注意格式。祝编码愉快。


非常有帮助,解决了我的问题。 :) - Waqas Ali

2

您没有说明使用的是哪种语言。以下示例使用VB.NET,因为我首先找到了这样的示例:

Namespace AdventureWorksPurchasingDSTableAdapters
    Partial Public Class SalesOrderHeaderTableAdapter
    Public Property SelectCommandTimeout() As Integer
        Get
        Return Adapter.SelectCommand.CommandTimeout
        End Get
        Set(ByVal value As Integer)
        Adapter.SelectCommand.CommandTimeout = value
        End Set
    End Property
    End Class
End Namespace

没错,但这正是我试图避免做的事情...单独做很容易...但如果你有几百个数据集的几百个表适配器,那么这真的不太可行。 - Gary
我想不出还能做什么。没有全局的CommandTimeout属性。如果有的话,它仍然必须设置单独的SqlCommand.CommandTimeout属性。 - John Saunders
为什么无法在数据集设计器中调整CommandTimeout属性?当我将连接超时更改为300秒时,为什么它仍然是30秒?顺便问一下,这些之间有什么区别?谢谢。 - Tim Schmelter
Tim,如果你有问题,请提出单独的问题。这不是一个讨论小组,评论也不是线程。 - John Saunders
这种方法对我不起作用。直到在像GetData这样的函数中填充SelectCommand之前,它都是null - user166390

2

目前来看,我认为这种情况下没有捷径或解决方法。感谢约翰的尝试。

我的最佳建议是不要在快速原型制作之外使用MS数据集... 当您的应用程序增长并需要扩展时,您只剩下了脏乱的代码 :)


这是一个相对狭窄的基础来谴责类型化的数据集。然而,这是一个关于 Connect(http://connect.microsoft.com/visualstudio/)功能建议的绝佳基础。当你发布了这个建议后,请编辑此答案并添加建议的URL,以便他人可以投票表达我们认为该建议有多重要。 - John Saunders
好的,这个问题并不是那个声明的唯一依据... 我对数据集最大的问题是缺乏智能默认值... 如果配置文件中没有正确的连接字符串,则会默认为创建时的任何连接字符串... 我对这个问题的直觉感觉是,在任何存在歧义的情况下,唯一正确的响应就是抛出异常并退出... - Gary
我晚些时候会在 Connect 上提出你的建议,我没有忽视你的建议 :) - Gary
我发现强类型的数据集在报表中运作良好...这也是我唯一使用它们的地方... - user166390

0

我决定在DataSet.cs文件中创建一个新的类,该类派生自TableAdapter类,并在构造函数中检查App.config文件中的commandtimeouts。我还添加了为特定的table adapter指定命令超时的功能,如果不存在,则检查全局值。

public class ImprovedMyTableAdapter : MyTableAdapter
{
    public ImprovedMyTableAdapter()
        : base()
    {
        int parsedInt = int.MinValue;
        string appSettingValue = System.Configuration.ConfigurationManager.AppSettings["MyTableAdapter_CommandTimeout"];
        if (string.IsNullOrEmpty(appSettingValue))
            appSettingValue = System.Configuration.ConfigurationManager.AppSettings["CommandTimeout"];
        if (!string.IsNullOrEmpty(appSettingValue) && int.TryParse(appSettingValue, out parsedInt))
        {
            foreach (var command in this.CommandCollection)
                command.CommandTimeout = parsedInt;
        }
    }
}

0

我不会直接修改DataSet设计器的代码,因为如果您在设计器中更新任何内容,它将被更改。相反,为表适配器创建一个部分类,并为其提供一个构造函数,该构造函数接受命令超时参数并调用无参数构造函数。

然后循环遍历CommandCollection并将超时设置为传入的超时参数。


0

我轻松地解决了这个问题。我进入了我的数据集的设计师代码(dataset1.designer.vb),找到了以下命令:Me._commandCollection(0)Me._commandCollection(1)Me._commandCollection(5),因为我总共有五个命令针对我的 SQL Server 2008 数据库执行。在每个(0 到 5)这些命令中,我写了 Me._commandCollection(0).CommandTimeout = 60,其中我将 0 更改为其他四个命令的下一个数字。这五个命令中的每一个都有一段代码块,其中两个块如下所示,以提供给您一个示例。

Me._commandCollection = New Global.System.Data.SqlClient.SqlCommand(5) {}

Me._commandCollection(0) = New Global.System.Data.SqlClient.SqlCommand()

Me._commandCollection(0).Connection = Me.Connection

Me._commandCollection(0).CommandTimeout = 60

Me._commandCollection(0).CommandText = "SELECT MK_QR_SUB_AND_DETAIL.*" & _ "Global.Microsoft.VisualBasic.ChrW(13) & Global.Microsoft.VisualBasic.ChrW(10)" & _ "FROM MK_QR_SUB_AND_DETAIL"

Me._commandCollection(0).CommandType = Global.System.Data.CommandType.Text    

Me._commandCollection(1) = New Global.System.Data.SqlClient.SqlCommand()

Me._commandCollection(1).Connection = Me.Connection

Me._commandCollection(1).CommandTimeout = 60

Me._commandCollection(1).CommandText = "dbo.spQtrRptTesting_RunInserts_Step1of4"

Me._commandCollection(1).CommandType = Global.System.Data.CommandType.StoredProcedure

Me._commandCollection(1).Parameters.Add(New Global.System.Data.SqlClient.SqlParameter("@RETURN_VALUE", Global.System.Data.SqlDbType.Int, 4, Global.System.Data.ParameterDirection.ReturnValue, 10, 0, Nothing, Global.System.Data.DataRowVersion.Current, False, Nothing, "", "", ""))

Me._commandCollection(1).Parameters.Add(New Global.System.Data.SqlClient.SqlParameter("@pStartADate", Global.System.Data.SqlDbType.[Date], 3, Global.System.Data.ParameterDirection.Input, 10, 0, Nothing, Global.System.Data.DataRowVersion.Current, False, Nothing, "", "", ""))

Me._commandCollection(1).Parameters.Add(New Global.System.Data.SqlClient.SqlParameter("@pEndADate", Global.System.Data.SqlDbType.[Date], 3, Global.System.Data.ParameterDirection.Input, 10, 0, Nothing, Global.System.Data.DataRowVersion.Current, False, Nothing, "", "", ""))

Me._commandCollection(1).Parameters.Add(New Global.System.Data.SqlClient.SqlParameter("@pStartBDate", Global.System.Data.SqlDbType.[Date], 3, Global.System.Data.ParameterDirection.Input, 10, 0, Nothing, Global.System.Data.DataRowVersion.Current, False, Nothing, "", "", ""))

Me._commandCollection(1).Parameters.Add(New Global.System.Data.SqlClient.SqlParameter("@pEndBDate", Global.System.Data.SqlDbType.[Date], 3, Global.System.Data.ParameterDirection.Input, 10, 0, Nothing, Global.System.Data.DataRowVersion.Current, False, Nothing, "", "", ""))

警告:永远不要手动编辑“设计师”文件。这是自动生成的代码,您在其中编写的所有内容都可能在 Visual Studio 重新生成代码时被覆盖。 - Julien N

0

虽然有点老,但有时候你会用到旧的解决方案...

首先,创建这个基类:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;

namespace PhotoReport.Data
{
    public class DataAdapterCustomBase : global::System.ComponentModel.Component
    {
        public void SetTimeout(int value)
        {
            SqlCommand[] innerCommands = this.GetType().InvokeMember(
                "CommandCollection",
                BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                null, this, null) as SqlCommand[];

            if (!ReferenceEquals(innerCommands, null))
            {
                foreach (SqlCommand cmd in innerCommands)
                {
                    cmd.CommandTimeout = value;
                }
            }
        }
    }
}

接下来,在 DataSet 设计器中,选择您的 Table Adapter 并将 BaseClass 属性更改为您的自定义基类(在我的情况下,是 PhotoReport.Data.DataAdapterCustomBase)。

最后,您可以使用:

using (svcServiceAppointmentsTableAdapter tableAdapter = new svcServiceAppointmentsTableAdapter()) 
{
    tableAdapter.SetTimeout(60);

    // do your stuff
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接