Я использую Visual Studio 2008 с С#.
У меня есть файл .xsd, и у него есть адаптер таблицы. Я хочу изменить тайм-аут команды адаптера таблицы.
Спасибо за вашу помощь.
Я использую Visual Studio 2008 с С#.
У меня есть файл .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; где-то перед этим .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, которое я в конечном итоге смог решить.
Прежде всего, мне нужно было убедиться, что вы используете правильное пространство имен. Мне потребовалось некоторое время, чтобы выяснить, что файл Designer для набора данных xsd фактически содержит два пространства имен: один для набора данных вообще и один для адаптеров таблицы. Поэтому следует обратить внимание на то, что необходимо использовать пространство имен для адаптера таблицы, а не для набора данных вообще.
Во-вторых, команда 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 в своем классе, поскольку они определены как закрытые для класса.
К счастью, мастер будет генерировать частичные классы, что означает, что вы можете их расширить. Как описано в [этой теме 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;
}
}
}
Заметьте, что я на самом деле не пробовал это сам, но это похоже на жизнеспособное решение.
Скажите, что ваш набор данных называется MySET.
Существует одна таблица под названием MyTable
MySETTableAdapters.MyTableTableAdapter fAdapter =
new MySETTableAdapters.MyTableTableAdapter();
fAdapter.Adapter.SelectCommand.CommandTimeout = <fill inyour value here>;
Вызов функции ChangeTimeout, предоставляя TableAdapter и Time в секундах.
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;
}
Если вы используете частичный класс, сделайте правильное пространство имен. Вероятно, [ваше имя набора данных] + "TableAdapters". Пример:
namespace MyProject.DataSet1TableAdapters
Вы можете открыть папку "Свойства", открыть "Настройки" и изменить свойство "Тайм-аут" вашей строки подключения.
Мне нравится это; Щелкните правой кнопкой мыши Fill()
или GetX()
и выберите Goto Defination
в меню.
Вы увидите исходный код DATATABLE. И найдите
private global::System.Data.SqlClient.SqlCommand[] _commandCollection;
из вашего класса dataadapter. И измените конфиденциальность на общественность.
Теперь вы можете получить доступ к _commandCollection, и вы можете изменить все атрибуты.
Но будьте осторожны при добавлении или изменении любой поданной формы DESIGNER, публика будет снова закрыта системой автогенерации.
А также, когда вы закончите вызов Fill или Get Function, вы должны reset _commandColleciton
вызвать эту функцию (InitCommandCollection()
)
public void InitCommandCollection() {}
Эта функция также является частной с помощью автогена, вы также должны перейти на публикацию.
Пример:
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();
Вот пример кода из MSDN, используя VB.NET:
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)
Это немного устарело и подозревает, что это решение не относится ко всем, но я решил использовать решение AniPol для переопределения элемента управления ObjectDataSource следующим образом:
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;
}
}
}
}
Расширяя уже очень полезные ответы на таблицы, которые мне очень помогли, мне также нужно было узнать фактическое значение тайм-аута. Таким образом:
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;
}
}
}
}
}
Кажется, есть более удобный способ сделать это. Вот краткое описание того, что я нашел.
Скажем, я добавляю к моему решению проект (класс библиотеки) MyDB. В этот проект я добавляю DataSet под названием "Данные". И в этот набор данных я перетащил таблицу под названием "X".
То, что я получаю на поверхности дизайна, является объектом, который показывает, что у меня есть объект под названием "XTableAdapter".
Теперь я открываю сгенерированный код Data.Designer.cs и ищу XTableAdapter. Когда я нахожу это, я отмечаю, что он содержится в пространстве имен MyDB.DataTableAdapters - это просто конкатенация имени проекта, "MyDB", имя DataSet, "Data" и "TableAdapters".
С этим я снова вернусь в библиотеку классов, все еще названный Class1.cs(на который я сейчас проигнорирую).
Я изменяю свое пространство имен от MyDB до MyDB.DataTableAdapters.
Я изменяю объявление класса на открытый частичный класс 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);
Меньше мусс, меньше суеты, меньше отражения (ну, нет), меньше заполняется.
Если вы перейдете к [имя 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 и т.д.