PDA

View Full Version : سوال: استفاده از Transaction در کدهاي #C



bftarane
جمعه 08 دی 1391, 10:24 صبح
من مي خوام اين دو تا Insert با هم اتفاق بيفتند بنابراين اونا رو در رويداد کليک يک دکمه نوشتم مي دونم که بايد از Transaction استفاده کنم


int categoryId=Convert.ToInt32(MyDALBase.ExecuteScaler (System.Data.CommandType.StoredProcedure, "insertmainmenu", new SqlParameter[]{
new SqlParameter("@NodeName",txt_mainmenuname.Text),
new SqlParameter("@MenuType","Dynamic"),
new SqlParameter("@MenuGroup","Other"),
new SqlParameter("@PageId",txt_MainEnName.Text)
}));
string url = txt_MainEnName.Text + ".aspx" + "&CategoryId=" + categoryId;
MyDALBase.ExecuteNoneQuery(System.Data.CommandType .StoredProcedure, "InsertUrl", new SqlParameter[]{
new SqlParameter("@Url",url)
});


اين هم متد ExecuteScaler که در کلاس DALBase نوشتم

public object ExecuteScaler(CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
using (SqlConnection con = new SqlConnection(ConnectionString))
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = commandType;
cmd.CommandText = commandText;
cmd.Parameters.AddRange(commandParameters);
con.Open();
object retVal = cmd.ExecuteScalar();
con.Close();
return retVal;
}
}
لطفاً راهنمايي کنيد چطور اين کار رو انجام بدم؟

p.parsaee
جمعه 08 دی 1391, 12:07 عصر
SqlConnection con = new SqlConnection(ConnectionString);
SqlTransaction tran = null;

try
{
con.Open();
tran = con.BeginTransaction();

SqlCommand cmd = new SqlCommand();

cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "insertmainmenu";
cmd.Parameters.AddWithValue("@NodeName", txt_mainmenuname.Text);
cmd.Parameters.AddWithValue("@MenuType", "Dynamic");
cmd.Parameters.AddWithValue("@MenuGroup", "Other");
cmd.Parameters.AddWithValue("@PageId", txt_MainEnName.Text);
cmd.Connection = con;
cmd.Transaction = tran;

cmd.ExecuteNonQuery();

string url = txt_MainEnName.Text + ".aspx" + "&CategoryId=" + categoryId;

SqlCommand cmd1 = new SqlCommand();

cmd1.CommandType = CommandType.StoredProcedure;
cmd1.CommandText = "InsertUrl";
cmd1.Parameters.AddWithValue("@Url", url);
cmd1.Connection = con;
cmd1.Transaction = tran;

cmd1.ExecuteNonQuery();

tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();

}
finally { con.Close(); }

bftarane
جمعه 08 دی 1391, 13:03 عصر
ممنونم ازتون. اگه بخوام از همون روش که در پست اول استفاده کردم يعني کلاس DALBase داشته باشم نمي شه اين کار رو کرد؟ يعني مدل کدنويسيم عوض نشه؟
آخه تو کتاب آقاي قمي تقريباً کدهايي مشابه کدهاي شما بود ولي من نتونستم اون رو با روش خودم انجام بدم.
مثلاً قسمت
اين کدها رو با تغييراتي من از کتاب ايشون نوشتم براي يه قسمت ديگه از سايتم

protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection conn = null;
SqlTransaction trans = null;
SqlCommand cmd;
try
{
string strCon = ConfigurationManager.ConnectionStrings["ConStr"].ToString();

conn = new SqlConnection(strCon);
conn.Open();
trans = conn.BeginTransaction();
cmd = new SqlCommand();
cmd.Connection = conn;
cmd.Transaction = trans;
cmd.CommandText = "INSERT INTO tbl_orders(Username,od_date,Name,Address,PostCode, Total)" + "VALUES (@Username, @od_date, @Name, @Address, @PostCode, @Total);" +
"SELECT CAST(scope_identity() AS int)";
cmd.Parameters.Add("@Username", SqlDbType.NVarChar, 50);
cmd.Parameters.Add("@od_date", SqlDbType.DateTime);
cmd.Parameters.Add("@Name", SqlDbType.NVarChar, 50);
cmd.Parameters.Add("@Address", SqlDbType.NVarChar, 50);
cmd.Parameters.Add("@PostCode", SqlDbType.NVarChar, 15);
cmd.Parameters.Add("@Total", SqlDbType.Money);
cmd.Parameters["@Username"].Value = User.Identity.Name;
cmd.Parameters["@od_date"].Value = DateTime.Now;
cmd.Parameters["@Name"].Value = txtName.Text;
cmd.Parameters["@Address"].Value = txtAddress.Text;
cmd.Parameters["@PostCode"].Value = txtPostCode.Text;
cmd.Parameters["@Total"].Value = ((ShoppingCart)Cache[HttpContext.Current.User.Identity.Name]).Total;
int OrderID = Convert.ToInt32(cmd.ExecuteScalar());
cmd.CommandText = "INSERT INTO tbl_orderlines(od_id, pd_id, odl_quantity, odl_price)" +
"VALUES (@od_id, @pd_id, @odl_quantity, @odl_price)";
cmd.Parameters.Clear();
cmd.Parameters.Add("@od_id", SqlDbType.Int);
cmd.Parameters.Add("@pd_id", SqlDbType.Int);
cmd.Parameters.Add("@odl_quantity", SqlDbType.Int);
cmd.Parameters.Add("@odl_price", SqlDbType.Money);
cmd.Parameters["@od_id"].Value = OrderID;
foreach (CartItem item in ((ShoppingCart)Cache[HttpContext.Current.User.Identity.Name]).items)
{
cmd.Parameters["@pd_id"].Value = item.pdid;
cmd.Parameters["@odl_quantity"].Value = item.quantity;
cmd.Parameters["@odl_price"].Value = item.price;
cmd.ExecuteNonQuery();
}
trans.Commit();

}
catch (SqlException SqlEx)
{
if (trans != null)
trans.Rollback();
throw new Exception("خطا", SqlEx);
}
finally
{
if (conn != null)
conn.Close();
}
((ShoppingCart)Cache[HttpContext.Current.User.Identity.Name]).items.Clear();
}

ولي بلد نيستم اين رو با روش خودم تطبيق بدم.
مثلاً وقتي trance تو کلاس تعريف شده باشه چطور بيام تو قسمت catch براش Rllback رو بنويسم يا وقتي پارامترهام تو کلاس تعريف شدن چطوري cmd.parameters.clear رو انجام بدم.

p.parsaee
جمعه 08 دی 1391, 14:13 عصر
نمي تونيد از متد ExecuteScaler كه در DALBase هست استفاده كنيد. به دليل اين كه هر بار كه اين متد صدا زده مي شه كانكشني باز ميشه بعد دستور اجرا ميشه و در نهايت كانكشن بسته ميشه. به عبارت ديگه به دليل اين كه اولا در حين اجراي transaction نبايد كانكشن بسته بشه، و ثانيا كانكشن هر دستوري كه ميخواد اجرا بشه بايد يكسان باشه، و ثالثا transaction مربوط به همه اين دستورها بايد يكسان باشه.

نتيجه گيري مي شه كه چون كانكشن و transaction همه اين كانكشن ها بايد يكي باشه نمي تونيد از متد ExecuteNonQuery يا ExecuteScalar كلاس DALBase استفاده كنيد.

اگه بخوايد با معماري نرم افزارتون يكي باشه بايد يك متد ديگه داخل DALBase اضافه كنيد كه شرايط گفته شده رو داشته باشن. ولي دقيقا نمي دونم بايد چطوري پياده سازيش كنيد. در هر صورت بايد شرايط گفته شده رو داشته باشن

p.parsaee
جمعه 08 دی 1391, 14:25 عصر
در رابطه با TransactionScope جستجو كنيد شايد به نتيجه برسيد. موفق باشيد

براي نمونه
http://http://msdn.microsoft.com/En-US/library/ms131084.aspx