PDA

View Full Version : سوال: مشکل در استفاده از تراکنش ( Transaction ) در سی شارپ ( #C )



forodo
جمعه 12 دی 1393, 15:23 عصر
سلام
هنگامی که دکمه ثبت رو می زنم اروره زیر رو میده:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_tblPeyvast_tblErsali". The conflict occurred in database "Radman", table "dbo.tblErsali", column 'ID'.
The statement has been terminated.
کدهای استفاده از تراکنش:
private void SendDataToDatabase()
{
UseDate ud = new UseDate();
SqlTransaction Transaction;
SqlConnection con = new SqlConnection(clsForms.ConnectionString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
con.Open();
Transaction = con.BeginTransaction();
cmd.Transaction = Transaction;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
try
{
cmd.CommandText = @"INSERT INTO tblErsali(SenderUserName,Subject,tabaghe,
SendDate,Sendtime,bazgasht,peyrov,FileFile,Formate File, NameFile,TabagheType,GetLetterGirande,
WhatOutEnterInBazgasht,WhatOutEnterInPeyro, ProjectName
)
VALUES(
@SenderUserName,@Subject,@tabaghe,
@SendDate,@Sendtime,@bazgasht,@peyrov, @FileFile,@FormateFile, @NameFile,@TabagheType,@GetLetterGirande,
@WhatOutEnterInBazgasht,@WhatOutEnterInPeyro, @ProjectName)";

cmd.Parameters.AddWithValue("@SenderUserName", Program.Username);
cmd.Parameters.AddWithValue("@Subject", txtSubject.Text);
cmd.Parameters.AddWithValue("@tabaghe", CmbTabagh.SelectedValue.ToString());
cmd.Parameters.AddWithValue("@SendDate", lblDate.Text);
cmd.Parameters.AddWithValue("@Sendtime", ududud.TimeEightCharacter().ToString());
cmd.Parameters.AddWithValue("@bazgasht", txtAtf.Text);
cmd.Parameters.AddWithValue("@peyrov", txtPeyrov.Text);
cmd.Parameters.AddWithValue("@FileFile", File.ReadAllBytes(MasireFile));
cmd.Parameters.AddWithValue("@FormateFile", FormateFile);
cmd.Parameters.AddWithValue("@NameFile", textBox1.Text);
if (CmbTabagh.Text.Contains("محرمانه"))
{
cmd.Parameters.AddWithValue("@TabagheType", true);
}
else
{
cmd.Parameters.AddWithValue("@TabagheType", false);
}
cmd.Parameters.AddWithValue("@GetLetterGirande", cmbGirande.SelectedValue.ToString());
cmd.Parameters.AddWithValue("@WhatOutEnterInBazgasht", Program.OutInEnterBazgasht);
cmd.Parameters.AddWithValue("@WhatOutEnterInPeyro", Program.OutInEnterPeyro);
cmd.Parameters.AddWithValue("@ProjectName", cmbProjectName.SelectedValue.ToString());

cmd.ExecuteNonQuery();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (Program.LetterPic.Count > 0)
{
int i = 0;
foreach (byte[] s in Program.LetterPic)
{
cmd.CommandText = @"INSERT INTO tblPeyvast(LetterName,LetterPic,LID, FormateFile)
VALUES(@LetterName,@LetterPic,@LID, @FormateFile)
";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@LetterName", Program.PicName[i]);
cmd.Parameters.AddWithValue("@LetterPic", Program.LetterPic[i]);
cmd.Parameters.AddWithValue("@LID", getMaxID());
cmd.Parameters.AddWithValue("@FormateFile", Program.FormateFilePeyvast[i]);

cmd.ExecuteNonQuery();

i++;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Transaction.Commit();
MessageBox.Show("نامه مورد نظر با موفقیت ارسال شد", "ثبت اطلاعات", MessageBoxButtons.OK, MessageBoxIcon.Information);
this.Close();
}
catch (Exception ex)
{
Transaction.Rollback();
MessageBox.Show("در ارتباط با بانک اطلاعاتی مشکلی پیش آمده است", "خطا درون بانک اطلاعاتی", MessageBoxButtons.OK, MessageBoxIcon.Error);
this.Close();
}
finally
{
con.Close();
}
}

abbas.oveissi
جمعه 12 دی 1393, 16:10 عصر
الان این خطا که ربطی به transaction نداره:متفکر:
مشکل از قید کلید خارجی هست.

forodo
جمعه 12 دی 1393, 18:11 عصر
اینسرت توی جدول tblErsali توی یه تابع بوده و اینسرت توی جدول tblPeyvast توی یه جدول دیگه.
توی توابعی جداگانه که بودند به درستی کار می کردند ولی الان که خواستم داخل تراکنش قرارشون بدم این ارور رو می ده.

forodo
جمعه 12 دی 1393, 18:40 عصر
سرچیدم و فهمیدم که این ارور برای این بوجود میاد که وقتی مقداری رو می خوایم داخل کلید خارجی بریزیم باید اون مقدار حتماً داخل کلید اصلی وجود داشته باشه.
حالا در اینجا در اینسرت اول اطلاعات داخل جدول tblErsali میریزه و می خوام در اینسرت دوم اطلاعاتی رو داخل جدول tblPeyvast بریزم که کلید خارجی اون دقیقاً همون مقداری هست که در اینسرت اول در کلید اصلی قرار داره.
در اینسرت دوم اگه دقت کنید یه تابع دارم به نام getMaxID()که دقیقاً همین کار رو برام انجام می ده. یعنی آخرین آی دی اضافه شده به جدول tblErsali رو می گیره و داخل کلید خارجی قرار می ده.
حالا مشکل اینجاست که هنوز کلید اصلی مقداری نگرفته و من می خوام کلید خارجی رو مقداردهی کنیم.
قبلاً که این دو اینسرت در توابع جداگانه ای بودند مشکلی نبود و روال عادی کلید اصلی و خارجی به درستی انجام می شد ولی الان که مجبورم برای استفاده از تراکنش اطلاعات رو همزمان اضافه کنم چیکار باید بکنم؟

Mahmoud.Afrad
جمعه 12 دی 1393, 20:38 عصر
گرفتن بزرگترین آی دی در اینجا اشتباست.
توسط

SCOPE_IDENTITY()

آی دی درج شده رو بدست بیار.

forodo
جمعه 12 دی 1393, 21:18 عصر
اینجوری نوشتم ولی بازم ارور می ده:
اینسرت دومی رو اینجوری تغییر دادم:
int maxid = getMaxID();
if (Program.LetterPic.Count > 0)
{
int i = 0;
foreach (byte[] s in Program.LetterPic)
{
cmd.CommandText = @"INSERT INTO tblPeyvast(LetterName,LetterPic,LID, FormateFile)
VALUES(@LetterName,@LetterPic,@LID, @FormateFile)
";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@LetterName", Program.PicName[i]);
cmd.Parameters.AddWithValue("@LetterPic", Program.LetterPic[i]);
cmd.Parameters.AddWithValue("@LID", maxid);
cmd.Parameters.AddWithValue("@FormateFile", Program.FormateFilePeyvast[i]);

cmd.ExecuteNonQuery();

i++;
}
}
و این هم تابع getMaxID هستش:
private int getMaxID()
{
try
{
SqlConnection objconnection =
new SqlConnection(clsForms.ConnectionString);

SqlDataAdapter objDataAdapter = new SqlDataAdapter();
DataSet objDataSet = new DataSet();

objDataAdapter.SelectCommand = new SqlCommand();
objDataAdapter.SelectCommand.Connection = objconnection;

objDataAdapter.SelectCommand.CommandText =
@"SELECT SCOPE_IDENTITY()
";

objDataAdapter.SelectCommand.CommandType = CommandType.Text;

objconnection.Open();
objDataAdapter.Fill(objDataSet, "tblLetter");
objconnection.Close();
return (int)objDataSet.Tables["tblLetter"].Rows[0][0];

}
catch (Exception)
{
return 0;
}

}

Mahmoud.Afrad
جمعه 12 دی 1393, 22:22 عصر
داری کانکشن جدید ایجاد می کنی که با کانکشن قبلی گه تراکنش در اون انجام میشه متفاوته و البته scop اونها هم متفاوته.


if (Program.LetterPic.Count > 0)
{
command.CommandText = "SELECT SCOPE_IDENTITY()";

int maxid = (int) command.ExecuteScalar();

int i = 0;
foreach (byte[] s in Program.LetterPic)
{
cmd.CommandText = @"INSERT INTO tblPeyvast(LetterName,LetterPic,LID, FormateFile)
VALUES(@LetterName,@LetterPic,@LID, @FormateFile)
";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@LetterName", Program.PicName[i]);
cmd.Parameters.AddWithValue("@LetterPic", Program.LetterPic[i]);
cmd.Parameters.AddWithValue("@LID", maxid);
cmd.Parameters.AddWithValue("@FormateFile", Program.FormateFilePeyvast[i]);

cmd.ExecuteNonQuery();

i++;
}
}

forodo
شنبه 13 دی 1393, 08:03 صبح
ارور می ده میگه نمی تونم null رو به نوع دیگه ای تبدیل کنم.
یه مسیج باکس گذاشتم دیدم خالیه.
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
MessageBox.Show(cmd.ExecuteScalar().ToString());
این به من خالی رو نشون می ده.

SabaSabouhi
شنبه 13 دی 1393, 13:44 عصر
سلام
استفاده از Scope_Identity مشکل ایجاد می‌کنه به‌ویژه وقتی جدول‌ها Trigger داشته باشن.
پیشنهاد می‌کنم از ('IDENT_CURRENT( 'TableName استفاده کنی.

صباصبوحی

Mahmoud Zaad
شنبه 13 دی 1393, 14:17 عصر
سلام
استفاده از Scope_Identity مشکل ایجاد می‌کنه به‌ویژه وقتی جدول‌ها Trigger داشته باشن.
پیشنهاد می‌کنم از ('IDENT_CURRENT( 'TableName استفاده کنی.

صباصبوحی

با سلام، اینها هر کدوم یه مشکلی دارن! بالاخره کدوم بهتره؟



IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope.


@@IDENTITY returns the last identity value generated for any table in the current session, across all scopes.


SCOPE_IDENTITY returns the last identity value generated for any table in the current session and the current scope.

منبع (http://msdn.microsoft.com/en-us/library/ms175098.aspx)

forodo
یک شنبه 14 دی 1393, 07:52 صبح
اینجوری زدم درست شد:
cmd.CommandText = "SELECT IDENT_CURRENT('tblErsali')";
int maxid = Convert.ToInt32(cmd.ExecuteScalar());
کجا از کدوم باید استفاده کنیم؟

SabaSabouhi
یک شنبه 14 دی 1393, 11:59 صبح
با سلام، اینها هر کدوم یه مشکلی دارن! بالاخره کدوم بهتره؟


سلام
بستگی داره کجا استفاده کنی.
اگه بلافاصله بعد از INSERT کردن بخوای مقدار Id اختصاص یافته رو بدست بیاری بهترین روش Ident_Current هست.
چون شما یه Transaction باز می‌کنی می‌تونی مطمئن باشی که حتماً مقدار Id مربوط به رکورد خودت رو دریافت می‌کنی.
و دلیلش هم اینه که داخل Trigger شما هیچ کدی نمی‌تونه به اون جدول دسترسی داشته باشه.

اما در مورد Scope_Identity مشکل وقتی به وجود می‌آد که شما از Trigger استفاده می‌کنی.
مثلاً فرض کن که با ایجاد یک رکورد فاکتور در جدول فاکتورها، با Trigger یک رکورد در جدول اسناد حسابداری و یک رکورد هم
در جدول حواله‌ی انبار ایجاد می‌کنی.
در این حالت مقداری که Scope_Identity بر می‌گردونه مربوط به آخرین جدولی هست که توش رکورد وارد کردی، یعنی حواله‌ی انبار
که باعث مشکل در سیستم می‌شه.

صبا صبوحی

forodo
جمعه 03 بهمن 1393, 14:56 عصر
هنگام استفاده دوباره این ارور رو میده که در پست 1 گفتم ولی این بار نمی خوام آخرین آی دی وارد شده رو بگیرم:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_tblDaryafti_tblLetterSadere". The conflict occurred in database "Radman", table "dbo.tblLetterSadere", column 'ID'.
The statement has been terminated.
این کدهام هستش:
UseDate uddd = new UseDate();
frmFonoshtDesc FonoshtDesc = new frmFonoshtDesc();
FonoshtDesc.Tag = "توضیح صادره";
FonoshtDesc.ShowDialog();
SqlTransaction Transaction;
SqlConnection con = new SqlConnection(clsForms.ConnectionString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
con.Open();
Transaction = con.BeginTransaction();
cmd.Transaction = Transaction;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
try
{
cmd.CommandText = @"UPDATE tblLetterSadere
SET ControlProzheFinish = 1, FonoshtDesc = N'" + "کنترل پروژه" + "-" + Program.FonoshtDesc + "' WHERE NumberForAC = (SELECT NumberForAC FROM tblLetterSadere WHERE ID = " + Program.LetterID + ")";



cmd.ExecuteNonQuery();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
string NumberIdAC = NACFunctionBaygani();
string lvlvevel = CatchLevel();

cmd.CommandText = @"INSERT INTO tblDaryafti(SadereLetterID,ErjaDate,ErjaTime,Level L, NumberForAC
)
VALUES(
@SadereLetterID,@ErjaDate,@ErjaTime,@LevelL, @NumberForAC
)";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@SadereLetterID", NumberIdAC);
cmd.Parameters.AddWithValue("@ErjaDate", uddd.GhamariToShamsi());
cmd.Parameters.AddWithValue("@ErjaTime", uddd.TimeEightCharacter());
cmd.Parameters.AddWithValue("@LevelL", lvlvevel + "-" + "بایگانی" + " (اختتام نامه)" + " " + uddd.GhamariToShamsi().ToString() + " " + uddd.TimeEightCharacter().ToString());
cmd.Parameters.AddWithValue("@NumberForAC", NumberIdAC);

cmd.ExecuteNonQuery();
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Transaction.Commit();
MessageBox.Show("جریان نامه مورد نظر به اتمام رسید", "ثبت اطلاعات"
, MessageBoxButtons.OK, MessageBoxIcon.Information);
this.Close();

}
catch (Exception)
{
Transaction.Rollback();
MessageBox.Show("در ارتباط با بانک اطلاعاتی مشکلی پیش آمده است", "خطا درون بانک اطلاعاتی", MessageBoxButtons.OK, MessageBoxIcon.Error);
this.Close();
}
finally
{
con.Close();
}
این کدهای تابع NACFunctionBaygani:
SqlConnection objconnection =
new SqlConnection(clsForms.ConnectionString);
try
{


SqlDataAdapter objDataAdapter = new SqlDataAdapter();
DataSet objDataSet = new DataSet();

objDataAdapter.SelectCommand = new SqlCommand();
objDataAdapter.SelectCommand.Connection = objconnection;

objDataAdapter.SelectCommand.CommandText =
@"SELECT NumberForAC
FROM tblLetterSadere
WHERE ID = " + Program.LetterID;


objDataAdapter.SelectCommand.CommandType = CommandType.Text;

objconnection.Open();
objDataAdapter.Fill(objDataSet, "tblLetterSadere");
objconnection.Close();

return objDataSet.Tables["tblLetterSadere"].Rows[0]["NumberForAC"].ToString();
}
catch (Exception)
{
return "";
}
finally
{
objconnection.Close();
}
و این هم کدهای تابع CatchLevel:
SqlConnection objconnection =
new SqlConnection(clsForms.ConnectionString);
try
{


SqlDataAdapter objDataAdapter = new SqlDataAdapter();
DataSet objDataSet = new DataSet();

objDataAdapter.SelectCommand = new SqlCommand();
objDataAdapter.SelectCommand.Connection = objconnection;

objDataAdapter.SelectCommand.CommandText =
@"SELECT LevelL
FROM tblDaryafti
WHERE Peynevesht = N'1c' AND NumberForAC = (SELECT NumberForAC
FROM tblLetterSadere
WHERE ID = " + Program.LetterID + ")";


objDataAdapter.SelectCommand.CommandType = CommandType.Text;

objconnection.Open();
objDataAdapter.Fill(objDataSet, "tblLetterSadere");
objconnection.Close();

return objDataSet.Tables["tblLetterSadere"].Rows[0]["LevelL"].ToString();
}
catch (Exception)
{
return "";
}
finally
{
objconnection.Close();
}
توی هیچ کدوم نمی خوام آی دی آخر رو بگیرم.

forodo
یک شنبه 05 بهمن 1393, 07:26 صبح
اگه جایی رو بد توضیح دادم بگید تا دوباره توضیح بدم.

forodo
سه شنبه 07 بهمن 1393, 22:02 عصر
دوستان پروژه گیر کرده.
لطفاً بگید کدام قسمتش رو باید تغییر بدم.

forodo
سه شنبه 14 بهمن 1393, 07:31 صبح
به نظر من همه چی درسته. چون مقادیری که می خوام بگیرم از یه جدول دیگه هستش.