Visual Studio 2008とC#を使用しています。
.xsdファイルがあり、テーブルアダプターがあります。テーブルアダプタのコマンドタイムアウトを変更したい。
ご協力いただきありがとうございます。
私は今日この問題を少し調査し、いくつかの情報源に基づいて次の解決策を考え出しました。アイデアは、テーブルアダプターの基本クラスを作成し、継承しすぎることです。これにより、既存のコードを書き直さなくても、テーブルアダプター内のすべてのコマンドのタイムアウトが増加します。生成されたテーブルアダプタは有用なものを継承しないため、リフレクションを使用する必要があります。コンストラクターで使用したものを削除して使用する場合は、タイムアウトを変更するパブリック関数を公開します。
using System;
using System.Data.SqlClient;
using System.Reflection;
namespace CSP
{
public class TableAdapterBase : System.ComponentModel.Component
{
public TableAdapterBase()
{
SetCommandTimeout(GetConnection().ConnectionTimeout);
}
public void SetCommandTimeout(int Timeout)
{
foreach (var c in SelectCommand())
c.CommandTimeout = Timeout;
}
private System.Data.SqlClient.SqlConnection GetConnection()
{
return GetProperty("Connection") as System.Data.SqlClient.SqlConnection;
}
private SqlCommand[] SelectCommand()
{
return GetProperty("CommandCollection") as SqlCommand[];
}
private Object GetProperty(String s)
{
return this.GetType().GetProperty(s, BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance).GetValue(this, null);
}
}
}
いくつかの小さな変更を加えると、cslのアイデアはうまく機能します。
partial class FooTableAdapter
{
/**
* <summary>
* Set timeout in seconds for Select statements.
* </summary>
*/
public int SelectCommandTimeout
{
set
{
for (int i = 0; i < this.CommandCollection.Length; i++)
if (this.CommandCollection[i] != null)
this.CommandCollection[i].CommandTimeout = value;
}
}
}
これを使用するには、this.FooTableAdapter.CommandTimeout = 60;を設定するだけです。 this.FooTableAdapter.Fill();の前のどこか
多くのテーブルアダプタでタイムアウトを変更する必要がある場合は、汎用拡張メソッドを作成し、リフレクションを使用してタイムアウトを変更することができます。
/// <summary>
/// Set the Select command timeout for a Table Adapter
/// </summary>
public static void TableAdapterCommandTimeout<T>(this T TableAdapter, int CommandTimeout) where T : global::System.ComponentModel.Component
{
foreach (var c in typeof(T).GetProperty("CommandCollection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance).GetValue(TableAdapter, null) as System.Data.SqlClient.SqlCommand[])
c.CommandTimeout = CommandTimeout;
}
使用法:
this.FooTableAdapter.TableAdapterCommandTimeout(60);
this.FooTableAdapter.Fill(...);
これは少し遅いです。また、間違ったタイプのオブジェクトで使用すると、エラーが発生する可能性があります。 (私が知る限り、制限できる「TableAdapter」クラスはありません。)
Mitchell Gilmanのソリューションの使用に関していくつか問題があり、最終的には回避することができました。
まず、正しい名前空間を使用する必要がありました。 xsdデータセットのDesignerファイルに実際には2つの名前空間が含まれていることを理解するのに少し時間がかかりました。1つは一般的なデータセット用で、もう1つはテーブルアダプター用です。したがって、最初に注意することは、一般的なデータセットではなく、テーブルアダプタの名前空間を使用する必要があるということです。
第2に、timeoutコマンドを初めて使用するときに、commandcollectionが常に初期化されるとは限りません。これを回避するために、この場合はInitCommandCollectionコマンドを呼び出しました。
したがって、私が使用した適応ソリューションは
namespace xxx.xxxTableAdapters
partial class FooTableAdapter
{
/**
* <summary>
* Set timeout in seconds for Select statements.
* </summary>
*/
public int SelectCommandTimeout
{
set
{
if (this.CommandCollection == null)
this.InitCommandCollection();
for (int i = 0; i < this.CommandCollection.Length; i++)
if (this.CommandCollection[i] != null)
this.CommandCollection[i].CommandTimeout = value;
}
}
}
それが人々に役立つことを願っています!
クラスに対してAdapterとして定義されているため、クラス内のAdapterのようなメンバーにアクセスできない場合があります。
幸い、ウィザードは部分的なクラスを生成します。つまり、それらを拡張できます。 [Piebaldによるこのスレッド] [1]で説明されているように、独自のプロパティを記述して、selectコマンドのタイムアウトを設定できます。
通常、これを行います。
partial class FooTableAdapter
{
/**
* <summary>
* Set timeout in seconds for Select statements.
* </summary>
*/
public int SelectCommandTimeout
{
set
{
for ( int n=0; n < _commandCollection.Length; ++n )
if ( _commandCollection[n] != null )
((System.Data.SqlClient.SqlCommand)_commandCollection[n])
.commandTimeout = value;
}
}
}
私は実際にこれを自分で試したことがないことに注意してください、しかしそれは実行可能な解決策のようです。
TableAdapterと時間を秒単位で指定してChangeTimeout関数を呼び出します。
this.ChangeTimeout(this.taTest, 500);
関数 :
private void ChangeTimeout(Component component, int timeout)
{
if (!component.GetType().FullName.Contains("TableAdapter")) {
return;
}
PropertyInfo adapterProp = component.GetType().GetProperty("CommandCollection", BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance);
if (adapterProp == null) {
return;
}
SqlCommand[] command = adapterProp.GetValue(component, null) as SqlCommand[];
if (command == null) {
return;
}
Interaction.command(0).CommandTimeout = timeout;
}
データセットがMySETと呼ばれているとします。
MyTableというテーブルが1つあります
MySETTableAdapters.MyTableTableAdapter fAdapter =
new MySETTableAdapters.MyTableTableAdapter();
fAdapter.Adapter.SelectCommand.CommandTimeout = <fill inyour value here>;
VB.NETを使用した [〜#〜] msdn [〜#〜] のサンプルコードを次に示します。
Imports System.Data.SqlClient
Namespace MyDataSetTableAdapters
Partial Class CustomersTableAdapter
Public Sub SetCommandTimeOut(ByVal timeOut As Integer)
For Each command As SqlCommand In Me.CommandCollection
command.CommandTimeout = timeOut
Next
End Sub
End Class
End Namespace
長いクエリを呼び出すときは、クエリの前にSetCommandTimeOutメソッドを呼び出すだけです。
Dim ds As New MyDataSet
Dim customersTA As New MyDataSetTableAdapters.CustomersTableAdapter
' Increase time-out to 60 seconds
customersTA.SetCommandTimeOut(60000)
' Do the slow query
customersTA.FillSlowQuery(ds.Customers)
一日中頭をかいた後、私はついにこれに対する解決策を得ました。 .xsdファイルを設計した後、必要なのは、自動生成されたページであるdataset.designer.csページに移動し、コードを以下のように変更することだけです。それは実際に動作します。試してみる。
protected global::System.Data.SqlClient.SqlCommand[] CommandCollection
{
get
{
if ((this._commandCollection == null))
{
this.InitCommandCollection();
_commandCollection[0].CommandTimeout = 0;
}
_commandCollection[0].CommandTimeout = 0;
return this._commandCollection;
}
}
プロパティフォルダを開き、Settings.settingsを開いて、接続文字列のTimeoutプロパティを変更できます。
ソリューションのデータセットファイルの下に追加されたファイルである[DataSetの名前] .Designer.csに移動し、次を検索する場合:
private void InitCommandCollection();
これは、テーブルアダプタで定義されている関数のプロパティを設定できるはずの関数です。
その関数の最初の行は
this._commandCollection = new global::System.Data.IDbCommand[<number of function defined in a table adapater>];
次に、これらの各関数の次の行で、
((global::System.Data.SqlClient.SqlCommand)(this._commandCollection[<index>])).CommandTimeout = 0;
この0は制限がなく、タイムアウトによって機能が停止しないことを示します。また、10、20、30、または1000などに設定できます。
私はこれが好きです; Fill()
またはGetX()
関数を右クリックし、メニューから_Goto Defination
_をクリックします。
DATATABLEのソースコードが表示されます。見つけて ;
_private global::System.Data.SqlClient.SqlCommand[] _commandCollection;
_
dataadapterクラスのコマンドライン。そして、プライベートをパブリックに変更します。
これで、_commandCollectionにアクセスして、すべての属性を変更できます。
ただし、Filed form DESIGNERを追加または変更する場合は注意してください。自動生成システムにより、パブリックは再びプライベートになります。
また、FillまたはGet関数の呼び出しが終了したら、この関数を呼び出して__commandColleciton
_をリセットする必要があります(InitCommandCollection()
)
_ public void InitCommandCollection() {}
_
この関数もautogenによってプライベートになっているので、パブリックにも変更する必要があります。
例:
_dsIslemlerTableAdapters.tblIslemlerTableAdapter _t = new dsIslemlerTableAdapters.tblIslemlerTableAdapter();
dsIslemler.tblIslemlerDataTable _m = new dsIslemler.tblIslemlerDataTable();
_t._commandCollection[0].CommandText = "Select * From tblIslemler Where IslemTarihi>='' And IslemTarihi<=''";
_m = _t.GetData();
_t.InitCommandCollection();
_
部分クラスを使用する場合は、適切な名前空間を使用してください。おそらく[データセットの名前] + "TableAdapters '。例:
名前空間MyProject.DataSet1TableAdapters
私を大いに助けてくれたtableadaptersのすでに非常に有用な答えを拡張して、実際のタイムアウト値を読み取る必要もありました。したがって:
namespace XTrans.XferTableAdapters
{
public partial class FooTableAdapter
{
int? _timeout = null;
///<summary>
///Get or set the current timeout in seconds for Select statements.
///</summary>
public int CurrentCommandTimeout
{
get
{
int timeout = 0;
if (_timeout != null)
{
timeout = (int)_timeout;
}
else
{
for (int i = 0; i < this.CommandCollection.Length; i++)
if (this.CommandCollection[i] != null)
timeout = this.CommandCollection[i].CommandTimeout;
}
return timeout;
}
set
{
if (this.CommandCollection == null)
this.InitCommandCollection();
for (int i = 0; i < this.CommandCollection.Length; i++)
if (this.CommandCollection[i] != null)
{
this.CommandCollection[i].CommandTimeout = value;
_timeout = value;
}
}
}
}
}
これは少し古く、このソリューションはすべての人に関係があるとは思われませんが、次のようにObjectDataSourceコントロールをオーバーライドするために AniPol's ソリューションを使用することになりました。
public class MyObjectDataSource : ObjectDataSource
{
public MyObjectDataSource()
{
this.ObjectCreated += this.MyObjectDataSource_ObjectCreated;
}
private void MyObjectDataSource_ObjectCreated(object sender, ObjectDataSourceEventArgs e)
{
var objectDataSourceView = sender as ObjectDataSourceView;
if (objectDataSourceView != null && objectDataSourceView.TypeName.EndsWith("TableAdapter"))
{
var adapter = e.ObjectInstance;
PropertyInfo adapterProp = adapter.GetType()
.GetProperty(
"CommandCollection",
BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance);
if (adapterProp == null)
{
return;
}
SqlCommand[] commandCollection = adapterProp.GetValue(adapter, null) as SqlCommand[];
if (commandCollection == null)
{
return;
}
foreach (System.Data.SqlClient.SqlCommand cmd in commandCollection)
{
cmd.CommandTimeout = 120;
}
}
}
}
これを行うにはもっと便利な方法があるようです。これが私が見つけたものの簡単な要約です。
MyDBという(クラスライブラリ)プロジェクトをソリューションに追加するとします。そのプロジェクトに「Data」というDataSetを追加します。そして、そのデータセットに「X」というテーブルをドラッグします。
デザイン面に表示されるのは、「XTableAdapter」というオブジェクトがあることを示すオブジェクトです。
生成されたコードData.Designer.csを開き、XTableAdapterを探します。それを見つけると、名前空間MyDB.DataTableAdaptersに含まれていることに気付きます。これは、プロジェクトの名前「MyDB」、DataSetの名前、「Data」、および「TableAdapters」を連結したものにすぎません。
それを手に、Class1.csと呼ばれるクラスライブラリに戻ります(今は無視します)。
名前空間をMyDBからMyDB.DataTableAdaptersに変更します。
クラス宣言をpublic partial class XTableAdapterに変更し、次のようにします。
using System.Data.SqlClient;
namespace MyDB.DataTableAdapters
{
public partial class XTableAdapter
{
public void SetTimeout(int seconds)
{
foreach (SqlCommand cmd in CommandCollection)
{
cmd.CommandTimeout = seconds;
}
}
}
}
呼び出しシーケンスは、ほとんど明確になりません。
int TwoMinutes = 120;
XTableAdapter.SetTimeout(TwoMinutes);
より少ないムス、より少ない騒ぎ、より少ない反射(まあ、なし)、より少ない充填。