[英]How to execute DataAdapter.Fill() simultaneously
我已經在 ASP.Net 應用程序上工作了很長時間,並且有超過 10 個客戶端在使用該應用程序。 但是現在我在應用程序中發現了一個問題,就是我有一個存儲過程調用,大約需要30秒才能執行。 這不是問題,因為 SQL 代碼高度復雜且循環多次。 問題是:每當執行該存儲過程調用時,我都無法使用任何其他函數或存儲過程調用。 當我嘗試調試時,問題是 'DataAdapter.Fill()' function 正在等待第一個存儲過程調用完成。
我執行存儲過程調用並返回數據的代碼是:
public static DataSet ExecuteQuery_SP(string ProcedureName, object[,] ParamArray)
{
SqlDataAdapter DataAdapter = new SqlDataAdapter();
DataSet DS = new DataSet();
try
{
if (CON.State != ConnectionState.Open)
OpenConnection();
SqlCommand cmd = new SqlCommand();
cmd.CommandTimeout = 0;
cmd.CommandText = ProcedureName;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = CON;
cmd.Transaction = SqlTrans;
string ParamName;
object ParamValue;
for (int i = 0; i < ParamArray.Length / 2; i++)
{
ParamName = ParamArray[i, 0].ToString();
ParamValue = ParamArray[i, 1];
cmd.Parameters.AddWithValue(ParamName, ParamValue);
}
DataAdapter = new SqlDataAdapter(cmd);
DataAdapter.Fill(DS);
cmd.CommandText = "";
}
catch (Exception ea)
{
}
return DS;
}
所有存儲過程調用都通過這個 function 工作。 因此,當我的第一個存儲過程調用“A”正在運行時,存儲過程調用“B”在“A”完成之前不會執行。
這會降低應用程序的整體性能並導致數據檢索出現問題。 我瀏覽了谷歌,發現“線程”可能會有所幫助,但我無法正確執行線程。 我對這類事情不是很熟悉。 如果您可以糾正問題,這將很有幫助。 我的第一個存儲過程調用是:
ds = DB.ExecuteQuery_SP("SelectOutstandingReportDetailed", parArray);
其中 ds 是數據集 object。 第二個存儲過程調用是:
ds = DB.ExecuteQuery_SP("[SelectAccLedgersDetailsByID]", ParamArray);
我當前打開的數據庫連接 function 是:
public static bool OpenConnection()
{
try
{
Server = (String)HttpContext.GetGlobalResourceObject("Resource", "Server");
DBName = (String)HttpContext.GetGlobalResourceObject("Resource", "DBName");
UserName = (String)HttpContext.GetGlobalResourceObject("Resource", "UserName");
PassWord = (String)HttpContext.GetGlobalResourceObject("Resource", "PassWord");
string ConnectionString;
ConnectionString = "server=" + Server + "; database=" + DBName + "; uid=" + UserName + "; pwd=" + PassWord + "; Pooling='true';Max Pool Size=100;MultipleActiveResultSets=true;Asynchronous Processing=true";
CON.ConnectionString = ConnectionString;
if (CON.State != ConnectionState.Open)
{
CON.Close();
CON.Open();
}
}
catch (Exception ea)
{
}
return false;
}
其中 'CON' 是一個公共 SqlConnection 變量
static SqlConnection CON = new SqlConnection();
我發現了問題,就是所有的存儲過程調用都是通過這個'CON' object來執行的。 如果每個存儲過程調用都有單獨的 SqlConnection object,則沒有問題。 那么是否可以為每個 ExecuteQuery_SP 調用創建單獨的 SqlConnection 。 如果有任何疑問,請發表評論。 謝謝
這是我可以為您創建的最簡單的版本。 重要提示:要了解您應該閱讀有關 async-await 的信息。
您可以從Microsoft C# Async-Await Docs開始
// TODO set up your connection string
private string connectionString = "<your connection string>";
// Gets data assyncronously
public static async Task<DataTable> GetDataAsync(string procedureName, object[,] ParamArray)
{
try
{
var asyncConnectionString = new SqlConnectionStringBuilder(connectionString)
{
AsynchronousProcessing = true
}.ToString();
using (var conn = new SqlConnection(asyncConnectionString))
{
using (var SqlCommand = new SqlCommand())
{
SqlCommand.Connection = conn;
SqlCommand.CommandText = procedureName;
SqlCommand.CommandType = CommandType.StoredProcedure;
string ParamName;
object ParamValue;
for (int i = 0; i < ParamArray.Length / 2; i++)
{
ParamName = ParamArray[i, 0].ToString();
ParamValue = ParamArray[i, 1];
SqlCommand.Parameters.AddWithValue(ParamName, ParamValue);
}
conn.Open();
var data = new DataTable();
data.BeginLoadData();
using (var reader = await SqlCommand.ExecuteReaderAsync().ConfigureAwait(true))
{
if (reader.HasRows)
data.Load(reader);
}
data.EndLoadData();
return data;
}
}
}
catch (Exception Ex)
{
// Log error or something else
throw;
}
}
public static async Task<DataTable> GetData(object General, object Type, string FromDate, string ToDate)
{
object[,] parArray = new object[,]{
{"@BranchID",General.BranchID},
{"@FinancialYearID",General.FinancialYearID},
{"@Type",Type},
{"@FromDate",DateTime.ParseExact(FromDate, "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture)},
{"@ToDate",DateTime.ParseExact(ToDate, "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture)}
};
return await DataBaseHelper.GetDataAsync("SelectOutstandingReportDetailed", parArray);
}
// Calls database assyncronously
private async Task ConsumeData()
{
DataTable dt = null;
try
{
// TODO configure your parameters here
object general = null;
object type = null;
string fromDate = "";
string toDate = "";
dt = await GetData(general, type, fromDate, toDate);
}
catch (Exception Ex)
{
// do something if an error occurs
System.Diagnostics.Debug.WriteLine("Error occurred: " + Ex.ToString());
return;
}
foreach (DataRow dr in dt.Rows)
{
System.Diagnostics.Debug.WriteLine(dr.ToString());
}
}
// Fired when some button is clicked. Get and use the data assyncronously, i.e. without blocking the UI.
private async void button1_Click(object sender, EventArgs e)
{
await ConsumeData();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.