PDA

View Full Version : مشکل برای Concurrency violation: the UpdateCommand affected 0 of the expected 1 records



khadem1386
پنج شنبه 22 اسفند 1387, 13:26 عصر
سلام به همه دوستان گرامی:

این یک پروژه هست که در هنگام آپدیت به مشکل بر می خورد.

اگر یک رکورد جدید درست کنم و اطلاعات را بنویسم بعد دکمه ذخیره برای بار اول درست کار می کند ولی برای بار دوم که اطلاعات جدید را می خواهید ذخیره کنید به مشکل بر می خوره

اگر شما یک رکورد جدید درست کنید و بعد اطلاعات را بنویسید بعد دکمه ذخیره را بفشارید و سپس همین دکورد جدید خود را ویرایش کنید. اکنون اگر دکمه ذخیره را بفشارید برنامه به مشکل بر می خوره و این اررور را می ده

Concurrency violation: the UpdateCommand affected 0 of the expected 1 records.

من در باره این error خیلی سرچ کردم ولی اصولا چیزه بدر بخوری پیدا نکردم هر چند واقعا همه دارند ازش مینالند و خیلی مطلب هست. ولی آخرش توی اینترنیت راه حل مشخصی نبود.

پروزه من به این تاپیک اتچ شده

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

__H2__
پنج شنبه 22 اسفند 1387, 14:17 عصر
سلام
این یک خطای خیلی ساده است که البته در موارد بسیار نادری اتفاق می افتد.
در واقع بیشتر یک Warning است تا Error.
هیچ مورد عجیبی هم ندارد، این خطا وقتی بروز میکند که تعدادی سطر در DataTable تغییر کرده باشند ولی زمانی که شما دستور DataAdapter.Update را اجرا میکنید هیچ سطری آپدیت نشود.

این مشکل میتواند از ...
1)عدم طراحی درست جداول و PrimaryKey و Relation باشد و برخی موارد منطقی و عادی و بدون مشکل باشد.
2) یا خود DataAdapter و دستورات SQL ایراد داشته باشند.
3) یا یک مشکل همزمانی فرمان از طرف چند کاربر در برنامه های شبکه ای باشد. (همه کسانی که کار شبکه ای میکنند این مورد را همیشه مد نظر دارند و یک بحث و حالت خاص است که از قدیم بوده.)

شما اول ساختار جداول و PrimaryKey ها خود را بررسی کنید و بعد دستورات SQL داخلی DataAdapter تان را بررسی کنید.

سعی میکنم وقت کردم نگاهی کدتان بیاندازم.
موفق باشید.

khadem1386
دوشنبه 26 اسفند 1387, 10:47 صبح
با تشکر از پاسخ شما:
من یک جدول بیشتر ندارم و آن هم یک ستون PrimaryKey بیشتر نداره که بصورت autonumber است.

از طرفی برنامه به صورت windows app بوده و داخل شبکه نیست که مشکل اشتراک فایلها یاهمزمانی بوجود بیاید. البته شاید برنامه با خودش درگیری داشته باشد که من نمی دونم کجاست.

از توجه شما تشکر

__H2__
دوشنبه 26 اسفند 1387, 12:36 عصر
سلام
متاسفانه وقت نکردم نگاهی بیاندازم ولی با توضیح آخری فکر کنم بدانم مشکل کجا است!

من یک جدول بیشتر ندارم و آن هم یک ستون PrimaryKey بیشتر نداره که بصورت autonumber است.
- شما احتمالا از DataSet/DataTable استفاده کرده اید و یک سطر را INSERT میکنید.
- بعد احتمالا، شاید و ممکن است primarykey جدید را سینک نمیکنید و در DataSet/DataTable سطر مود نظر AcceptChange میشود ولی primarykey آن همچنان یک مقدار غیر مجاز که برابر با نظیرش در دیتابیس نیست، میماند.
- بعد شما این سطر DataSet/DataTable را تغییر میدهید، و سپس دستور UPDATE !
- برنامه شما سعی میکند سطری با primarykey ای که وجود ندارد را پیدا و آپدیت کند! در حالی که همچین سطری در بانک اصلی وجود ندارد.
- چون فقط همین یک تغییر را داده بودید، پس تغییری داشته اید ولی DataAdapter.Update شما هیچ سطری را آپدیت نکرده، نتیجه اش خطای فوق خواهد بود!

اگر متوجه شوید، خواهید دید که خطای عجیب و غریبی نیست و کاملاً منطقی است.
احتمالاً مشکل شما با تغییری در DataAdapter حل خواهد شد.

khadem1386
چهارشنبه 28 اسفند 1387, 09:34 صبح
سلام ظاهرا خیلی از تاپیک های آخری بطور خود بخود حذف شده و احیانا مسولین سایت مجبور شدند از backup قبلی استفاده کنند. چون این تاپیک را قبلا من اضافه کرده بودم و حالا دوباره می نویسم.

مساله اینجاست که هنگام ساختن یک رکور جدید و حتی هنگام پر کردن آن اشکال بوجود نمیاد.
یعنی اگر یک رکور درست کنی بعد شروع کنی به تایپ اطلاعات و دخیره کنی مشکل پیش نمیاد اگر هم از برنامه بری بیرون و برگردی هم مساله وجود نداره همه اطلاعات جدید ذخیره شده است.

ولی اگر یک رکود جدید درست کنی اطلاعات را توش بریزی و ذخیره کنی
بعد بخواهی اطلاعات جدید را ویرایش کنی و دوباره دکمه ذخیره را بفشاری آنگاه به شما error می ده.

پس مشکل نمی تونه از autonumber باشه


با تشکر از کمک شما

__H2__
سه شنبه 04 فروردین 1388, 12:49 عصر
سلام
با توجه به اینکه اولین پست من در سال 88 است، عید نوروز را به شما و تمام دوستان و اعضای سایت تبریک میگم.
==============

میتوانید سطر ID سطر جدید درج شده را با IDENTITY@@ به دست آورید
مثلاً:


SELECT @@IDENTITY;

یا

SELECT * FROM [tablename] WHERE (autonumberprimarykeyname = @@IDENTITY);


==============

من نمونه کد شما را دیدم، رایانه من سخت افزار نصبتاً خوبی دارد ولی برنامه شما را به کندی بسیار اجرا میکند.
نگاهی هم به کدهایتان کردم، متاسفانه و با عرض شرمندگی تمام، باید ببخشید، واقعاً و بدون شوخی دچار سردرد شدم.
شرمنده من نمیتوانم کد شما اصلاح و صحیح کنم، چون با عاداتی که دارم مجبور میشوم اصلاح را با NewProject شروع کنم.
میبخشید کمک بیشتری نمیتوانم به این کد بکنم.


سال خوبی را برایتان آرزو مندم و انشا ا...، همواره موفق و پیروز و سربلند باشید.

khadem1386
سه شنبه 25 فروردین 1388, 12:30 عصر
با تشکر از دوستان ضمن عرض پوزش بابت دیرکرد.
من فایل ضمیه شده را عوض کردم و بقول آقای H2 از NewProject و همه چیز بسیار ساده و مرتب شده
قرار داره

ولی باز هم همین مشکل به وجود می یاد.
Concurrency violation: the UpdateCommand affected 0 of the expected 1 records

اگر شما یک رکورد جدید درست کنید و بعد اطلاعات را بنویسید بعد دکمه ذخیره را بفشارید و سپس همین دکورد جدید خود را ویرایش کنید. اکنون اگر دکمه ذخیره را بفشارید برنامه به مشکل بر می خوره و این اررور را می ده:عصبانی++:

فایل ضمیمه جدید تمیز شده و دیگه باعث سردرد نخواد شد:چشمک: که در همان تاپیک اول قرار دادم و تغییر کرده

مرسی

__H2__
یک شنبه 30 فروردین 1388, 00:12 صبح
سلام
با عرض پوزش، کمی کار داشتم و نتوانستم زودتر جواب بدهم.
من یک نمونه مثال بسیار ساده برایتان درست کردم که مشکل فوق را ندارد.

یک نمونه مخصوص Access و موتور JET است و یک نمونه مخصوص SQLServer.
(به نظرم برای پروژه های کوچک هم SQLServerExpress بسیار بهتر و کارامدتر است)

در مورد Access شما باید به کد فایل MainDataSet.vb دقت کنید.

در مورد SQLServer کدهای خودکار صحیح تولید میشوند و میتوانید در داخل برنامه به دستور SQL بخش InserCommand از dataAdapter دقت کنید.

1- مشکل شما یک راه حل به ظاهر ساده و با کدمتر هم دارد، ولی این کد ظاهراً ساده خیلی کندتر است و بازدهی لازم را ندارد، پس بیان نمیکنم.

2- در کل اگر تعداد سطرهای دیتابیستان خیلی زیاد باشد، استفاده از سیستم DataSet و DataAdapter چندان منطقی نیست و میتواند بازدهی و سرعت برنامه را به شدت کاهش دهد، سریعترین کد runtime استفاده از روشهای Command و DataReader است که البته راه نمشکل تری است.

3- توجه داشته باشید که حالت پیشفرض فایلهای دیتابیس در داخل VS کپی است.
به این معنا که با هر بار اجرای برنامه از داخل خود VS فایل بانک اطلاعاتی خالی موجود یکبار به محل exe کپی میشود و سپس برنامه اجرا میشود.
نتیجتاً ...
الف- با هر اجرا هر تغییری در جداول و فیلدهای دیتابیس داده باشید، اعمال میگردد
ب- با هر بار جرا کل اطلاعات قبلی که وارد دیتابیس کرده بودید حذف میشود.

میتوانید پیشفرض فوق را در VS تغییر دهید و یا مستقیماً exe را اجرا کنید، میل خودتان است!

دانلود مستقیم:
http://h02.ir/Download.aspx?File=IDENTITY_In_DataAdapter.zip
موفق باشید.

khadem1386
سه شنبه 01 اردیبهشت 1388, 13:20 عصر
ضمن تشکر از شما: مخصوصا بابت وقتی که گذاشته اید.

khadem1386
پنج شنبه 03 اردیبهشت 1388, 09:46 صبح
ضمن تشکر از شما: مخصوصا بابت وقتی که گذاشته اید.

من کلاس Partial Public Class Table1TableAdapter را داخل فایل دیتا ست خودم همان طور که شما گفته بودید گذاشتم.
اگر امکان دارد در مورد این قسمت ها کمی توضیح دهید




Partial Public Class Table1TableAdapter
Private m_Command As System.Data.OleDb.OleDbCommand


Private Sub _adapter_RowUpdated(ByVal sender As Object, ByVal e As System.Data.OleDb.OleDbRowUpdatedEventArgs) Handles _adapter.RowUpdated
If ((e.StatementType = StatementType.Insert) AndAlso (e.RecordsAffected > 0)) Then

If (Me.m_Command Is Nothing) Then
Me.m_Command = New System.Data.OleDb.OleDbCommand("SELECT @@IDENTITY;", Me._connection)
End If

'Try
e.Row(0) = CInt(Me.m_Command.ExecuteScalar())
'Catch
'End Try
End If

End Sub

Private Sub Table1TableAdapter_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
If (Me.m_Command IsNot Nothing) Then Me.m_Command.Dispose()
End Sub



با تشکر مجدد

__H2__
پنج شنبه 03 اردیبهشت 1388, 12:01 عصر
سلام
خوشبختانه بانک قدرمتمند SQLServer اجازه اجرای همزمان دو دستور INSERT و پس از ان SELECT را میدهد.
ولی متاسفانه موتور JET (نرم افزار Access) اجازه این عمل را نمیدهد.
نتیجتاً در SQLServer با تغییر کوچکی در دستور SQL مشکل حل میشود (که البته قالباً خودکار این تغییر انجام میشود.)
ولی در JET شما نیازمند آن هستید که خودتان دستی دستور SELECT را اضافه کنید.
- - - - - - - - - - - - - -
متد فوق بعد از آپدیت هر یک سطر بانک اطلاعاتی اجرا میشود و باید حواستان باشد که این متد باید حدالامکان سریع الاجرا باشد تا بازده برنامه را کاهش ندهد.
(که الآن به نظر من خوب و سریع الاجرا است.)

- در اولین If چک کرده ایم که آیا یک عمل Insert بوده و عملاً سطری به بانک اضافه شده یا نه.
- در If بعدی تضمین کردیم که Command با دستور SELECT @@IDENTITY وجود داشته باشد.
(
این همان دستور SELECT بود که در فوق گفتم و JET اجازه اجرا خودکار آن بعد از Insert را نمیداد.
این دستور آخرین AutoNumber درج شده در جلسه جاری را باز میگرداند، که طبیعتاً primarykey همین سطر آخری خواهد بود و این سطر آخری با این عدد primarykey در بانک ثبت شده و برای سریهای بعد باید با این عدد خود را آپدیت کند.
)

- درنهایت هم دستور را اجرا و عدد را به اولین فیلد (صفر امین ایندکسی!) Row که میدانیم همان Primarykey خودمان است تخصیص میدهیم.
(
در واقع دستورات If قبلی بسیار بسیار پرسرعت هستند، چون فقط اعداد و اشاره گرها چک شدند، و سرعت اصلی کد به همین متد ExecuteScalar بر میگردد که این متدهم باز از یک دستور Insert قبلی که توسط DataAdapter انجام شده بود، پرسرعت تر است.
)


- دستور Try باعث چشمپوشی از خطای احتمالی میشود!!

- در شرایط عادی و با کاری که ما کرده ایم، یک دستور e.Row.AcceptChanges باید در انتها اضافه شود، ولی با توجه به اجرای این دستور توسط DataAdapter در سطح DataTable دیگری نیازی به دستور ما نیست.

- متد Table1TableAdapter_Disposed هم با نابودی DataAdapter در صورت وجود، Command دستی ما را هم نابود میکند، تا منابع سیستم به خوبی و تضمینی آزاد شوند.

موفق باشید.