PDA

View Full Version : خطای باز و بسته کردن کانکشن



* joodi *
جمعه 28 خرداد 1395, 14:57 عصر
سلام

من از معماری 3 لایه استفاده کردم برای اتصال از ریدر استفاده میکنم و تو صفحم اینجوری تابع dal رو فراخوانی میکنم
مشکلی که پیش میاد اینه که با اینکه من کانکشن رو سعی کردم مدیریت کنم اما خیلی موقه ها با پیام کانکشن بسته است و یا باز است مواجه میشم!

executereader requires an open and available connection the connection's current state is closed



public void FillDataListNews()
{
DAL.DALBase fill = new DAL.DALBase();


SqlDataReader reader = fill.ExecuteReader(System.Data.CommandType.StoredP rocedure, "FillDataListNews", new SqlParameter[] {
});


DataTable table = new DataTable();
table.Load(reader);
reader.Close();

Dt_ShowNews.DataSource = table;
Dt_ShowNews.DataBind();
}



و این ها توابع من در dal هستن


public static string ConnectionString
{
get
{
return ConfigurationSettings.AppSettings["ConStr"];
}
}
private static SqlConnection _dbCnn;
public static SqlConnection DB
{
get
{
if (_dbCnn == null)
{
SqlConnection oDBCnn = new SqlConnection(ConnectionString);
_dbCnn = oDBCnn;
_dbCnn.Open();
}
return _dbCnn;
}
set
{
_dbCnn = value;
}
}



public SqlDataReader ExecuteReader(CommandType commandType, string commandText, SqlParameter[] commandParameters)
{


SqlCommand cmd = new SqlCommand();
cmd.Connection = DB;
cmd.CommandType = commandType;
cmd.CommandText = commandText;
cmd.Parameters.AddRange(commandParameters);


bool mustCloseConnection = false;
try
{


if (DB.State != ConnectionState.Open)
{
mustCloseConnection = true;
if (DB.State != ConnectionState.Open) DB.Open();
}
else
{
mustCloseConnection = false;
}


SqlDataReader dataReader;




dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) ;


return dataReader;
}
catch
{
if (mustCloseConnection)
DB.Close();
throw;
}
}

* joodi *
پنج شنبه 03 تیر 1395, 12:59 عصر
ای بابا ماشالا این همه استاد یکی نیست جواب منو بده یعنی :(

Answer
پنج شنبه 03 تیر 1395, 15:34 عصر
چرا اینقدر پیچوندی دور سرت
غذا رو این ظرف اون ظرف کردی خیلی
یه مشکلی که به نظرم کد شما داره اینه که موقع استفاده از Reader لازم نیست کانکشن رو ببندید reader.close کفایت میکنه

* joodi *
شنبه 05 تیر 1395, 13:05 عصر
چرا اینقدر پیچوندی دور سرت
غذا رو این ظرف اون ظرف کردی خیلی
یه مشکلی که به نظرم کد شما داره اینه که موقع استفاده از Reader لازم نیست کانکشن رو ببندید reader.close کفایت میکنه


ممنون خب چیجوری یه ظرفش کنم؟ :لبخندساده:
البته من تو دو تا مقاله خوندم که اتفاقا باید حتما کانکشن رو علاوه بر ریدر ببندیم!

Answer
شنبه 05 تیر 1395, 16:14 عصر
بیش از حد تجزیه شده کلاس ها
مثلا connection string رو با DB خیلی راحت میشه ادغام کرد و مشکلی پیش نخواهد اومد
همیشه تجزیه مفید نخواهد بود باید دید آیا نیاز این کلاس تفکیک بشه یا خیر
تجزیه بیش از حد خوانایی برنامه رو پایین میاره
من چک میکنم و مشکل شما رو بررسی میکنم و در مورد reader من c# رو با msdn شروع کردم و تموم مثال هایی که دیدم connection بسته نشده و فقط reader.close

https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.close(v=vs.110 ).aspx
https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx

ولی برای احتیاط شما میتونید بجای قسمت catch قسمت finally رو اضافه کنید و اونجا ببندید کانکشن رو
من کد رو واستون اصلاح میکنم و قرار میدم

Answer
شنبه 05 تیر 1395, 16:17 عصر
قسمت آخر تابع رو به این شکل اصلاح کنید باشد که رستگار شوید :))))


catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (DB.State == ConnectionState.Open)
DB.Close();
}

Mahmoud.Afrad
شنبه 05 تیر 1395, 21:12 عصر
علت خطا به دلیل این هست که کانکشن قبل از استفاده از متد Load به هر دلیلی بسته میشه. نکته دیگر اینکه کانکشن رو در catch می بندید در صورتی که ممکنه catch اصلا اجرا نشه و کانکشن باز بمونه. به دلیل استاتیک بودن کانکشن بعد از catch یک بلاک finally اضافه کنید و منابعی مثل Reader و کانکشن و ... رو در finally ببندید.

اگر لایه ای کد مینویسید، به نظر من اصلا نباید نوع برگشتی متد ExecuteReader از نوع SqlDataReader باشد. یا اینطور بگم بهتره: دریافت داده از دیتابیس باید در لایه DAL صورت بگیره؛ اما شما ریدر رو به لایه بالاتر انتقال دادید و در لایه بالاتر با فراخوانی متد Load اطلاعات رو از دیتابیس دریافت میکنید که این اشتباه هست. میتونید نوع برگشتی را از نوع DataTable بگیرید و داده رو در متد دریافت و برگشت بدید.
به نظرم نیازی نیست کانکشن استاتیک باشه. mustCloseConnection فکر نمیکنم نیاز باشه و چک کردن State کانکشن کافیه. حتی فکر کنم به پراپرتی DB هم نیازی نیست(کانکشن باید خصوصی باشه. اگر نیاز به تغییر کانکشن بود باید از طریق متدی درون Dal این کار رو انجام بدید و خارج از این کلاس نباید به کانکشن دسترسی داشت) .

* joodi *
چهارشنبه 09 تیر 1395, 22:50 عصر
قسمت آخر تابع رو به این شکل اصلاح کنید باشد که رستگار شوید :))))


catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (DB.State == ConnectionState.Open)
DB.Close();
}





با این روشی که من نوشتم و ریدر رو return کردم وقتی در finally کانکشن رو میبندم به علت اتصال گرا بودن ریدر قبل از لود اطلاعات کانکشن بسته میشه و در واقع هیچی لود نمیشه!

* joodi *
چهارشنبه 09 تیر 1395, 23:03 عصر
علت خطا به دلیل این هست که کانکشن قبل از استفاده از متد Load به هر دلیلی بسته میشه. نکته دیگر اینکه کانکشن رو در catch می بندید در صورتی که ممکنه catch اصلا اجرا نشه و کانکشن باز بمونه. به دلیل استاتیک بودن کانکشن بعد از catch یک بلاک finally اضافه کنید و منابعی مثل Reader و کانکشن و ... رو در finally ببندید.

خب کد CommandBehavior.CloseConnection در try باز و بسته بودن رو در خارج از catch مدیریت میکنه



اگر لایه ای کد مینویسید، به نظر من اصلا نباید نوع برگشتی متد ExecuteReader از نوع SqlDataReader باشد. یا اینطور بگم بهتره: دریافت داده از دیتابیس باید در لایه DAL صورت بگیره؛ اما شما ریدر رو به لایه بالاتر انتقال دادید و در لایه بالاتر با فراخوانی متد Load اطلاعات رو از دیتابیس دریافت میکنید که این اشتباه هست. میتونید نوع برگشتی را از نوع DataTable بگیرید و داده رو در متد دریافت و برگشت بدید.


خیلی ممنون از توضیحتون متاسفانه این ایراد رو داره که برخی جاها فقط اسمش سه لایه است !و رعایت نکردم و از قضا خیلی قسمت ها دچار این مشکل شده و الان نمیتونم اصلاح کنم در سرچی که انجام دادم این توضیحات آقای راد رو دیدم : http://barnamenevis.org/showthread.php?122584-%DA%86%D8%B1%D8%A7-DataReader-%D9%87%D9%85%D9%8A%D8%B4%D9%87-Close-%D8%A7%D8%B3%D8%AA-%D8%9F
و کدم رو در لایه ی dal اینجوری اصلاح کردم کلا try catch رو برداشتم چون ریدر به خاطر انتقال به لایه ی بالاتر با کانکش بسته مواجه میشد! به نظرتون درسته؟



public SqlDataReader ExecuteReader(CommandType commandType, string commandText, SqlParameter[] commandParameters)
{




SqlCommand cmd = new SqlCommand();
cmd.Connection = DB;
cmd.CommandType = commandType;
cmd.CommandText = commandText;
cmd.Parameters.AddRange(commandParameters);

if (DB.State != ConnectionState.Open)
{
DB.Open();
}


SqlDataReader dataReader;




return dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) ;

}





به نظرم نیازی نیست کانکشن استاتیک باشه. mustCloseConnection فکر نمیکنم نیاز باشه و چک کردن State کانکشن کافیه. حتی فکر کنم به پراپرتی DB هم نیازی نیست(کانکشن باید خصوصی باشه. اگر نیاز به تغییر کانکشن بود باید از طریق متدی درون Dal این کار رو انجام بدید و خارج از این کلاس نباید به کانکشن دسترسی داشت) .


من در کلاس های دیگه کانکشن رو اینطوری فراخوانی میکنم و ازش استفاده میکنم :


SqlCommand command = new SqlCommand("DeleteAdmins", DALBase.DB);


به نظرتون ایرادی داره؟ کانکشن رو چطور بنویسم که این ایرادهایی که میگین نداشته باشه و قابل دسترس هم باشه از کلاس های دیگه. میشه نمونه کد بدین

تشکر

kamranetemadi
پنج شنبه 10 تیر 1395, 02:32 صبح
شمار از این روش استفاده کنید-- خروجی DataTable خواهد بود و کانکشن رو توی فاینالی ببندید.

SqlCommand cmd = new SqlCommand(ProcName, connectionString);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add...
try
{
SqlDataAdapter dap = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
dap.Fill(ds);
return ds.Tables[0];
}
catch (Exception)
{
...;
}
finally
{
connectionString.Close();
}

* joodi *
جمعه 11 تیر 1395, 14:09 عصر
شمار از این روش استفاده کنید-- خروجی DataTable خواهد بود و کانکشن رو توی فاینالی ببندید.

SqlCommand cmd = new SqlCommand(ProcName, connectionString);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add...
try
{
SqlDataAdapter dap = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
dap.Fill(ds);
return ds.Tables[0];
}
catch (Exception)
{
...;
}
finally
{
connectionString.Close();
}


من تو پروژه بسیااااار از ریدر استفاده کردم به همون روش خودم و تغییر دادنش خیلی سخته راهی برای اصلاح همون ریدر وجود نداره؟
علاوه بر این من تو چن تا مقاله خوندم ریدر نسبت به دیتا ست کارایی بهتری داره
فرقشون در زمان استفاده چیه؟

کد تابع کانکشن رو چطور باید اصلاح کنم؟

kamranetemadi
جمعه 11 تیر 1395, 16:33 عصر
من فقط روشی رو گفتم که خودم با استفاده از اون دیگه به مشکل کانکشن بر نخوردم
در ضمن من این کد ها رو در یک متد از یک کلاس سرارسی تعریف کردم که پارامتر ها رو به صورت param میگیره تا هر تعداد دلخواه پارامتر که خواستم به عنوان ورودی به متد بدم و برای هر پروسجر با هر تعداد ورودی به مشکل نخورم
کاری هم به کارایی ریدر و دیتا ست نداشتم
این کارو کردم چون خروجی Datatable رو لازم داشتم در بسیاری از جاهای کارم

حالا شما هم کمی تکنیک به خرج بدید و چیزای مختلفی که از دوستان یاد میگیرید رو به کار بگیرید و شک نکنید با ابتکار شخصی همیشه بهترین نتیجه رو میگیرید