PDA

View Full Version : گفتگو: روش SqlDataAdapter



RoostaYeBekr
دوشنبه 25 آذر 1387, 15:19 عصر
با سلام
:لبخندساده:
خیلی وقته که به نظرم این روش SqlDataAdapter ها ، که در ایبوک ها معرفی می کنند ، مشکل اساسی دارد . هم Insert اش و هم Update اش.
:متفکر:
در متد Update ، اول اتصال را باز کرده و بعد بسته . حالا وسط این باز کردن و بست ، اومده و Proccess مربوط به Update اش را انجام داده . همین به نظرم اشتباه است . چون نباید زمانی که اتصال باز است ، عمل Proccess صورت گیرد.

دوم در متد Insert ، هم با عبارت select * from Table1 ، اول آمده ساختار اون DataSet اش را گرفته . حالا انگار بدون این کواری نمی شد. (اشکال اول) . بعد دوباره Proccess وسط یک اتصال باز ( اشکال دوم ).
:خجالت:
اگر خواستید برنامه اش را دانلود کنید ، دیتابیس در پوشه ی APP_Data است.
http://www.sleezo.com/imgs/2008/dec/15/yyno.png

babakj
پنج شنبه 28 آذر 1387, 01:27 صبح
آره می دونم منم بارها باهاش کار کردم واسم خیلی عجیب بوده اما این برای Insert کردن Single Row نیست
بیشتر موقع Bulk insert یا فله ایی اضافه کردن استفادش کردم ولی واسه منم عجیبه که چرا Select * رو می گیره راستی تا حالا با Select Row کار کردی ولی یک Row دیگه بهش بدی مثلا Select id from tbl_sample

RoostaYeBekr
پنج شنبه 28 آذر 1387, 12:30 عصر
آره می دونم منم بارها باهاش کار کردم واسم خیلی عجیب بوده اما این برای Insert کردن Single Row نیست
بیشتر موقع Bulk insert یا فله ایی اضافه کردن استفادش کردم ولی واسه منم عجیبه که چرا Select * رو می گیره راستی تا حالا با Select Row کار کردی ولی یک Row دیگه بهش بدی مثلا Select id from tbl_sample
با سلام
:لبخندساده:
آره با اینی که گفتید ، کار کردم . ولی در اصل قضیه که من راجع بهش سوال دارم ، تفاوتی نمی کنه.

jaza_sa
پنج شنبه 19 دی 1387, 17:48 عصر
این کد رو از کجا اوردید ؟

emad_67
پنج شنبه 19 دی 1387, 18:19 عصر
منظورت از انجام process در اتصال باز چیه؟ اتصال بازی وجود نداره اصلا.
الان در متد update اطلاعات در dataset ریخته شده و بعد از تغییرات روی اون دوباره در دیتابیس ذخیره شده.

محمدامین شریفی
پنج شنبه 19 دی 1387, 18:49 عصر
این کد معلوم هست که از ebook نیست!،شاید هم من تاحالا اینجوری insert کردن را توی کتاب ها ندیدم،دوست من کاشکی منبعش را ذکر میکردی
2 تا سوال واسم پیش اومد:
اول اینکه:sqlcommandbuilder رو که ایجاد کردی کجا ازش استفاده کردی؟،اصلا چرا ایجادش کردی؟
دوم اینکه:insert آخریت چرا اینجوری هست؟،حالا اگر بخواهیم کدهامون رو توی storedprocedure بنویسیم،با مدل شما چجوری میشه؟

---------------------------------

همانطور که عماد جون گفت اتصال بازی نداریم.هنگامی که adapter میخواهد جدول را پر کند connection را باز میکند.

sepehr.net
پنج شنبه 19 دی 1387, 19:43 عصر
سلام
این کد اصلا استاندارد لازم رو نداره . ساختن شی های بیهوده برای دو عمل ساده !!!
به جای اینکه کاربر بفهمه چی شده تازه گیج میشه!!
من هم تا حالا همچین نمونه ایی ندیدم.
با نظر aminsharifi67 (http://barnamenevis.org/forum/member.php?u=45828) موافقم این کد اصلا مربوط به کتاب یا Ebook ای نیست.

SMRAH1
پنج شنبه 19 دی 1387, 19:47 عصر
سلام

براي کار با پايگاه داده تحت SQL SERVER،دات نت کلاس SqlDataAdapter رو تدارک ديده که همراه SqlCommand و SqlConnection ،بيشتر وظايف رو به عهده مي گيرند (کلاس هاي ديگر رو در System.Data.SqlClient ببينيد).البته شما در اين کد عملا دو کلاس SqlCommand و SqlConnection رو نمي بينيد که با پارامتر هايي که به SqlDataAdapter فرستاديد (ConnectionString و دستور SQL خواندن داده ها) ،خوده SqlDataAdapter اونها رو براتون مي سازي (هر چند برنامه نويس هاي حرفه اي معمولا ترجيح ميدهند خودشون اين اشيا رو بسازند و به Adapter اختصاص بدهند).اما نکته اصلي روي Command يا دستور کار با پايگاه داده (که از نوع SqlCommand است) مي باشد.براي کار با يک پايگاه داده ،چها دستور لازم است که عبارتند از Select و Upadet و Delete و Insert که البته معادل هرکدوم در SqlDataAdapter يک خصوصيت داريم (مثلا UpdateCommand و DeleteCommand و ..).
حالا سئوال اين بود که اين آداپتور با داشتن فقط دستور Select ،چه طوري دستور Update يا ... رو توليد مي کنه؟جواب ساده است.به اين خط برنامه توجه کنيد:

SqlCommandBuilder builder = new SqlCommandBuilder(adapter);به عبارت ديگه دات نت کلاسي به نام SqlCommandBuilder تدارک ديده که با دادن دستور Select مي تونه بقيه رو توليد کنه (کار سختي نيست و مي تونيد دستي امتحان کنيد!).يکي از سازنده هاي اين کلاس با دريافت يک شي SqlDataAdapter و فرض درست بودن Select (اين دستور در بين چهار دستور بالا رايج تر است) بقيه رو توليد مي کنه و به SqlDataAdapter تخصيص مي ده (توسط همان خصوصيات UpdateCommand و ... خواندن و نوشتن SqlCommand ) انجام ميشه.
براي اطلاعات تکميلي هم پيشنهاد مي کنه کاربرد هاي SqlCommandBuilder رو (در همين سايت يا MSDN) ببينيد.

در ضمن کد های بالا صحیح اند و کار می کنند.

موفق باشيد

RoostaYeBekr
پنج شنبه 19 دی 1387, 21:58 عصر
با سلام
jaza_sa (http://barnamenevis.org/forum/member.php?u=45588) گفتید :

این کد رو از کجا آوردید ؟
MS Press - Programming Microsoft .NET Core Reference.chm

emad_67 (http://barnamenevis.org/forum/member.php?u=35031) گفتید :
منظورت از انجام process در اتصال باز چیه؟
هم در متد اول و هم در دوم ، منظور از Proccess: تغییر مقدار _username . ( حالا اینجا Proccess کوچک بوده ، وگرنه می تواند خیلی بزرگتر از این حرف ها باشد )

و اینکه گفتید :
اتصال بازی وجود نداره اصلا.
اگه وجود نداشته باشه که پس چطوری اطلاعات Insert و Update می شود؟

aminsharifi67 (http://barnamenevis.org/forum/member.php?u=45828) گفتید:
این کد معلوم هست که از ebook نیست!،شاید هم من تاحالا اینجوری insert کردن را تویکتاب ها ندیدم،دوست من کاشکی منبعش را ذکر میکردی
آره ، دیتابیسش را خودم ساختم .:لبخند:

aminsharifi67 (http://barnamenevis.org/forum/member.php?u=45828) گفتید:
اول اینکه:sqlcommandbuilder رو که ایجاد کردی کجا ازش استفاده کردی؟،اصلا چراایجادش کردی؟
البته اگر یک بار همون خط رو کامنت می گرفتید ، متوجه می شدید که بدون اون اصلا برنامه اجرا نمی شه. SMRAH1 (http://barnamenevis.org/forum/member.php?u=44567) خوب و کامل توضیح دادند. دیگر فکر نمی کنم نیاز به توضیح من باشه.

aminsharifi67 (http://barnamenevis.org/forum/member.php?u=45828) گفتید:

همانطور که عماد جون گفت اتصال بازی نداریم.هنگامی که adapter میخواهد جدول را پر کند connection را باز میکند.
حالا این شد همونی که از اول منتظر بودم ، یکی بگه ( اون هم با ذکر دلیل ) . البته منتظر یک چیز دیگه هم بودم و آن اینکه وقتی در لحظه ی adapter.Fill(ds, "Table1"); ، اتصال باز می شود ، در همین متد هم اتصال بسته می شود. چون اگر بسته نشود ، بلافاصله بعدش یک Proccess هست و این یعنی Proccess در حین انجام یک اتصال باز و این یعنی مشکل . و بعید هم هست که متد Fill ، هم اتصال را باز کند و هم ببندد.

sepehr.net (http://barnamenevis.org/forum/member.php?u=46790)گفتید :
با نظرaminsharifi67 (http://barnamenevis.org/forum/member.php?u=45828) موافقم این کد اصلا مربوط به کتاب یا Ebook اینیست.
زود قضاوت کردید. همین .

با متد Adapter.Fill ، اتصال که بسته نمی شود . بعد ، بسته نشده ، Proccess آغاز کرده و بعد بسته. هنوز تو این گیر دارم.

SMRAH1 (http://barnamenevis.org/forum/member.php?u=44567) گفتید:
در ضمن کد های بالا صحیح اند و کار می کنند.
راستش داشتم از تعجب شاخ درمی آوردم که چطور کسی این کدها رو ندیده . امیدوارم کردید.

emad_67
جمعه 20 دی 1387, 01:31 صبح
SqlDataAdopter خودش موقعي که متد fill فراخواني ميشه connection رو باز ميکنه و بعد از ذخيره اطلاعات در dataset اونو close ميکنه. بنابراين ديگه connection اي باز نيست.

The connection object associated with the SELECT statement must be valid, but it does not need to be open. If the connection is closed before Fill is called, it is opened to retrieve data, then closed. If the connection is open before Fill is called, it remains open.
http://msdn.microsoft.com/en-us/library/377a8x4t.aspx
متد update مشکلي نداره و کاملا منطقي هست ولي متد insert اون کوئري select رو بي خودي نوشته. فکر کنم هدفش اين بوده که از روي select بياد insert و ... رو هم بسازه.

RoostaYeBekr
جمعه 20 دی 1387, 11:42 صبح
SqlDataAdopter خودش موقعي که متد fill فراخواني ميشه connection رو باز ميکنه و بعد از ذخيره اطلاعات در dataset اونو close ميکنه. بنابراين ديگه connection اي باز نيست.

http://msdn.microsoft.com/en-us/library/377a8x4t.aspx
متد update مشکلي نداره و کاملا منطقي هست ولي متد insert اون کوئري select رو بي خودي نوشته. فکر کنم هدفش اين بوده که از روي select بياد insert و ... رو هم بسازه.
با سلام
مرسی. فقط ببین این لینکی که دادی را هرچی روش کلیک می کنم ، یو آر ال اش را نمی شناسد. یک بار دیگه این یو آر ال را چک می کنی. آخه دیدن منبعش برایم مهم است.

بعد اینکه گفتی : Insert اش مشکل دارد ، همان است که من از همون اولین پستم گفتم :
حالا انگار بدون این کواری نمی شد. (اشکال اول)

حالا کسی پاسخی برای این مشکل نمیشناسد ؟

emad_67
جمعه 20 دی 1387, 12:02 عصر
فقط ببین این لینکی که دادی را هرچی روش کلیک می کنم ، یو آر ال اش را نمی شناسد. یک بار دیگه این یو آر ال را چک می کنی. آخه دیدن منبعش برایم مهم است.
چک کردم و مشکلی نداشت. شما در مورد متد Fill کلاسSqldataAdopter جستجو کن، معمولا همین مورد رو ذکر میکنن در اون.

حالا کسی پاسخی برای این مشکل نمیشناسد ؟
مشکل الان همون Insert هست؟ خوب اون کوئری select رو پاک کن و خودت دستی یه کوئری update برای UpdateCommand بنویس.

RoostaYeBekr
جمعه 20 دی 1387, 13:06 عصر
چک کردم و مشکلی نداشت.
با سلام
آخه من دفعه ی سوم است که به اینترنت وصل می شوم و روی این لینک شما کلیک می کنم. باز هم لینک شناخته نمی شود.

مشکل الان همون Insert هست؟ خوب اون کوئری select رو پاک کن و خودت دستی یه کوئری update برای UpdateCommand بنویس.
:لبخندساده: مشکل من که ارتباط با دیتابیس نیست. خوب بالاخره از این راه نشد ، کلی راه دیگر هم هست. مسئله ی من همان است که در پست قبلیم قرمزش کردم.

راستی یک قضیه ی دیگه:
اگر اینطور باشه که Fill ، کانکشن را باز می کند و بعد می بندد ، به دلیل این که موقع آپدیت ، یک بار دیگه کانکشن باید باز شود و بسته شود ، متد Update در زیر هم ، باید به تنهایی بتواند کانکشن را باز کرده و سپس ببندد. درسته ؟


adapter.Update(inserts);

SMRAH1
جمعه 20 دی 1387, 13:53 عصر
سلام

اجازه بدهيد که در مورد adapter.Fill ،نوشته هاي دوست عزيزم emad_67 رو تکميل کنم:
1) اگر شي Connection (از نوع SqlConnection - گفته شد که در کد بالا به شکل اتوماتيک ساخته شده ليکن مي تواند آن را جدا ساخت و به Adapter يا Command ها معرفي کرد - اين شي در واقع توسط Command ها استفاده مي شود به همين دليل براي دست يابي به آن بايد از آنها استفاده کرد به عنوان مثال adapter.DeleteCommand.Connection ) موجود، باز باشد،عمليات انجام شده ولي Connection بسته نميشود
2) ولي اگر Connection بسته باشد ،در هنگام يک پردازش،ابتدا باز شده،تغييرات پايگاه داده انجام و سپس بسته مي شود
نتيجه : به عبارت ديگر ،هر کس يا شي اي Connection را باز کند،خودش بايد آن را ببندد!

اما در مورد 'حالا انگار بدون اين کواري نمي شد. (اشکال اول)' :
قبلا هم گفتم که کد ها صحيح اند (کافيه توي يک برنامه ساده تست کنيد - در موقع تست در ConnectionString به نام سرور توجه کنيد براي نمونه در کد فرستاده شده نام سرور localhost است ولي در سيستم من اين نام کار نميکند و حتما بايد SQLExpress/. باشد!).اما اينکه چطور Query براي Insert ساخته ميشه هم ،توسط همون SqlCommandBuilder است.نکته ظريفي اينکه اين شي تا زماني که Adapter وجود دارد،نيز وجود دارد(هر چند که ممکن است يک متغير محلي به نظر آيد که خود به خود از بين مي رود و حذف مي شود).در واقع وقتي دستوراتي نظير adapter.Update را فراخوانيد مي کنيد ابتدا ،Adapter از شي SqlCommandBuilder مي خواهد که يک Update Query مناسب ايجاد کند (همانطور که ذکر شد هماهنگ با SelectCommand توجه کنيد که Schema را مي توانيد توسط DataSet نيز بدست آوريد) و سپس اقدام به بروز رساني مي کند.يادآوري مي شود که در دستور:

SqlDataAdapter adapter = new SqlDataAdapter("select * from Table1",...);
شما عملا Select Query يا همان دستور SelectCommand را مشخص مي کنيد.

موفق باشيد

milade
جمعه 20 دی 1387, 14:34 عصر
سلام
ببخشید توی بحثتون نظر غیر اصولی و نامرتبط میدم !
(اخه خیلی وقته از ادابتور و دیتاست و ... استفاده نمیکنم!)
من زمان قدیم این روش رو به کار میبستم و مشکلی نبود:
یه دیتاست یا دیتاتیبل میساختم اونو با پایگاه به روز میکردم و حالا اگه insert بود دستورش و اگه delete بود دستورش رو مینوشتم و با یه دیتاگرید اونو BIND میکردم !
هیچ مشکلی هم نبود !
(اگه در این مورد کمک خواستید در خدمتم!)

RoostaYeBekr
جمعه 20 دی 1387, 15:17 عصر
سلام

اجازه بدهيد که در مورد adapter.Fill ،نوشته هاي دوست عزيزم emad_67 رو تکميل کنم:
1) اگر شي Connection (از نوع SqlConnection - گفته شد که در کد بالا به شکل اتوماتيک ساخته شده ليکن مي تواند آن را جدا ساخت و به Adapter يا Command ها معرفي کرد - اين شي در واقع توسط Command ها استفاده مي شود به همين دليل براي دست يابي به آن بايد از آنها استفاده کرد به عنوان مثال adapter.DeleteCommand.Connection ) موجود، باز باشد،عمليات انجام شده ولي Connection بسته نميشود
2) ولي اگر Connection بسته باشد ،در هنگام يک پردازش،ابتدا باز شده،تغييرات پايگاه داده انجام و سپس بسته مي شود
نتيجه : به عبارت ديگر ،هر کس يا شي اي Connection را باز کند،خودش بايد آن را ببندد!

اما در مورد 'حالا انگار بدون اين کواري نمي شد. (اشکال اول)' :
قبلا هم گفتم که کد ها صحيح اند (کافيه توي يک برنامه ساده تست کنيد - در موقع تست در ConnectionString به نام سرور توجه کنيد براي نمونه در کد فرستاده شده نام سرور localhost است ولي در سيستم من اين نام کار نميکند و حتما بايد SQLExpress/. باشد!).اما اينکه چطور Query براي Insert ساخته ميشه هم ،توسط همون SqlCommandBuilder است.نکته ظريفي اينکه اين شي تا زماني که Adapter وجود دارد،نيز وجود دارد(هر چند که ممکن است يک متغير محلي به نظر آيد که خود به خود از بين مي رود و حذف مي شود).در واقع وقتي دستوراتي نظير adapter.Update را فراخوانيد مي کنيد ابتدا ،Adapter از شي SqlCommandBuilder مي خواهد که يک Update Query مناسب ايجاد کند (همانطور که ذکر شد هماهنگ با SelectCommand توجه کنيد که Schema را مي توانيد توسط DataSet نيز بدست آوريد) و سپس اقدام به بروز رساني مي کند.يادآوري مي شود که در دستور:

SqlDataAdapter adapter = new SqlDataAdapter("select * from Table1",...);
شما عملا Select Query يا همان دستور SelectCommand را مشخص مي کنيد.

موفق باشيد

با سلام و تشکر از توضیحاتتون

من گفته بودم که :
حالا انگار بدون اين کواري نمي شد.

که اصلا منظورم این نبود که برنامه ای که فرستادم ، کار نمی کنه. چون بالاخره در همان پست اولم ، کل برنامه را فرستاده بودم. منظورم چیزی بود که خودتان هم اشاره کردید :
همانطور که ذکر شد هماهنگ با SelectCommand توجه کنيد که Schema را مي توانيد توسط DataSet نيز بدست آوريد

یعنی منظور من این بود که می شد بدون اینکه به دیتابیس کواری زده شود ، مثلا با کد زیر ، ساختار یا به قول شما ، Schema را گرفت. مثل زیر : ( البته من از DataTable استفاده کردم . نوشتن DataSet اش هم خیلی کاری ندارد )


private System.Data.DataTable getDataTable()
{
DataTable l_DataTable = new DataTable();
l_DataTable.TableName = "My_Table";
l_DataTable.Columns.Add("Column1");
l_DataTable.Columns.Add("Column2");
return l_DataTable;
}


در حقیقت این تو کواری اول در Insert ، آمده ساختار یا شما را گرفته و بعد در کواری دوم رکوردی را اینسرت کرده . حرف من این است که با توجه به اینکه باید فشار روی دیتابیس کم شود ، و با توجه به اینکه بدون اون کواری اول هم می شد ساختار را گرفت ، پس کواری اول اضافی است . حالا اگر اون خط کواری اول را کامنت بگیریم دیگه اصلا برنامه کار نمی کند. اصلا بدیهی است و تازه خودتان هم توضیحش را دادید. و نتیجه ای که من از همان پست اولم از این قضیه گرفته بودم این است که این روش یک کواری اضافی دارد .

یک چیز دیگه : اگر اینطور است که متد Fill ، کانکشن را باز می کند و بعد می بندد ، پس چرا در بعضی از کدها می بینیم که اینطوری نوشته :


private System.Data.DataView give_Select(String a_String_Request)
{

System.Data.DataView L_dw = new System.Data.DataView();

System.Data.SqlClient.SqlConnection L_con = new System.Data.SqlClient.SqlConnection(System.Configu ration.ConfigurationManager.ConnectionStrings["B"].ConnectionString);
System.Data.DataSet L_objDataSet = new System.Data.DataSet();
System.Data.SqlClient.SqlDataAdapter L_objDataAdapter = new System.Data.SqlClient.SqlDataAdapter();
L_objDataAdapter.SelectCommand = new System.Data.SqlClient.SqlCommand(a_String_Request, L_con);

L_con.Open();
L_objDataAdapter.Fill(L_objDataSet, "my_DataTable");
L_dw = L_objDataSet.Tables["my_DataTable"].DefaultView;
L_con.Close();

return (L_dw);

}


الان به اون قسمتی که کانکشت توسط متغیر L_con باز و بسته شده نگاه کنید. اگر که که خود متد Fill ، کانکشن را باز و بسته می کند ، پس دیگر چرا از متغیر L_con ، برای باز و بسته شدن استفاده می شود؟

فکر کنم الان مرا با کاتیوشا تیرباران می کنند ، برای اینکه فقط از من بپرسند این کد را از کجا آوردی ؟

RoostaYeBekr
جمعه 20 دی 1387, 15:40 عصر
با سلام
اینی که من می گم این دو کواری در Insert زده که کواری اول لازم نبود ، به خاطر کد زیر است که خودم نوشتم . الان دقت کنید که اصلا من این متد Fill را کامنت گرفتم تا اصلا اجرا نشود یا بعبارتی در کل متد برای عمل اینسرت فقط یک دفعه سراغ دیتابیس برویم و نه دو دفعه ( یکبار در Fill و یکبار در متد Update )


privatevoid Insert()
{
SqlDataAdapter adapter = newSqlDataAdapter("select _username from Table1",
"Data Source=localhost;Initial Catalog=My_alert;Integrated security=true;");
SqlCommandBuilder builder = newSqlCommandBuilder(adapter);
DataTable l_DataTable = newDataTable();
l_DataTable = getDataTable().Copy();
//adapter.Fill(ds, "Table1");
//DataTable table = l_DataTable.Tables["Table1"];
DataRow row = l_DataTable.NewRow();
// Initialize the DataRow
row["_username"] = "ZZH";
// Add the DataRow to the DataTable
l_DataTable.Rows.Add(row);
//DataTable inserts = l_DataTable.GetChanges(DataRowState.Added);
adapter.Update(l_DataTable);
}



private System.Data.DataTable getDataTable()
{
DataTable l_DataTable = new DataTable();
l_DataTable.TableName = "My_Table";
l_DataTable.Columns.Add("_username");
return l_DataTable;
}

دقت هم کنید که چطور ساختار را از سمت Server گرفتم ، به جای اینکه با استفاده از Fill ، و در یک کواری جدا ، ساختار یا Schema از دیتابیس آورده شود . نتیجه : یک کواری کمتر .

emad_67
جمعه 20 دی 1387, 16:51 عصر
خوب او کوئری اول که خودت و ما هم گفتیم اضافی هست و حرفی هم درش نیست، شاید هدف اون کد معرفی SqlCommandBuiler بوده،

الان به اون قسمتی که کانکشت توسط متغیر L_con باز و بسته شده نگاه کنید. اگر که که خود متد Fill ، کانکشن را باز و بسته می کند ، پس دیگر چرا از متغیر L_con ، برای باز و بسته شدن استفاده می شود؟
خوب اون open و close اضافه هست، نوشته نمیشد هم مشکلی نبود.
اما ممکنه مواردی پیش بیاد که شما شما connection رو برای یک کوئری باز میکنی و بعد هم قرار برای یک کوئری دیگه مثلا data adopter یک کانکت بزنه، در همچین مواردی خوب دیگه لازم نیست یکبار connection رو ببندی و تا دوباره data adopter خودش باز کنه. و در واقع با یکبار باز کردن connection دو تا کوئری میزنی، البته بعدشم دیگه باید خودت close کنی. اما در کد بالا نوشتنش بی فایده هست.