PDA

View Full Version : جایی برای نگهداری اطلاعات انتخاب شده در گرید با checkbox



zharfa
پنج شنبه 06 آذر 1393, 12:06 عصر
با سلام خدمت اساتید گرامی
من یک گرید ویو دارم که توش اطلاعات جدولی از دیتابیسمو لود کردم
این گرید ما دارای ستونی از نوع چک باکس هستش
هر سطری از این گرید هم دارای یک سری اطلاعات تو جدول دیگه است
کاری که میخوام انجام بدم اینه که:
میخوام هر سطری که تیک میخوره اطلاعاتش از جدول دیگه برداشته بشه و تو یه جایی برام ذخیره کنه ممکنه مثلا 10 تا سطر انتخاب شده باشه من میخوام با توجه به فیلد سطر های انتخاب شده بره سلکت مورد نظر رو از جدول دیگه بگیره و تو یه تیبل ای جایی برام ذخیره کنه
اگر هم فقط یه سطر باشه اطلاعات همون یه سطر و از جدول دیگه بیاره برام ..
نمیدونم این اطلاعاتو کجا نگهداری کنم ؟؟؟
ممنون میشم کسی راهنمایی کنه
ضمنا بنده قبلش دل سیر سرچ کردم اما سوالم بی جواب موند که تاپیک زدم
روزتون شاد ...

Mahmoud Zaad
پنج شنبه 06 آذر 1393, 14:22 عصر
سلام
یک راه اصولی اینه که با یه حلقه foreach یا for آی دی یا کلید خارجی ردیفهای مورد نظر رو بخونید بعد یه کوئری بنویسید که سلکت رو بر اساس این آی دی ها انجام بده البته بینشون باید OR قرار بدید. یعنی یه stringBuilderی، چیزی داشته باشید که داخل حلقه شرط جدید رو بهش Append کنید.
مثلاً
select*from tbl Where id=1 OR id=10 OR id=100 ....
و نتیجه رو توی DataTable قرار بدید.

راه دوم اینه که باز با یه حلقه foreach یا for آی دی یا کلید خارجی ردیفهای مورد نظر رو بخونید بعد از جدول دوم سلکت کنید و بعد توی یه دیتاتیبل بریزید یعنی محل ذخیره می تونه یه دیتاتیبل باشه:
DataTable dt=new DataTable();
dt.Columns.Add("id");
dt.Columns.Add"name");
.
.
.

در داخل حلقه بعد از سلکت، چیزی شبیه این می نویسید:
dt.Rows.Add("");

zharfa
جمعه 07 آذر 1393, 20:41 عصر
دوست عزیز
ممنون از پاسختون
راه حل دوم رو بیشتر و بهتر تونستم درک کنم
فقط سوالی داشتم این بود که :
من تو حلقه هر بار یه سلکت میگیرم... درست؟ حالا چه جوری نتیجه سلکت هر بار حلقه رو بریزم تو یک دیتاتیبل
منظورم بیشتر کد سلکت گرفتن از دیتابیسه
کدی که من استفاده میکنم نتیجه سلکت رو فیل کردم تو دیتاتیبل چه جوری اون دیتاتیبل رو به دیتا تیبل اصلی اضافه کنم؟

mojtabamalaekeh
جمعه 07 آذر 1393, 21:07 عصر
نه شما توی حلقه نباید هر بار سلکت بگیرید از جدول.
توی حلقه فقط باید ID ردیف هایی که چک باکسشون تیک خورده رو جمع کنید. از حلقه که خارج شدین یه سلکت کافیه برای خروجی گرفتن.


string collectedIds="";
foreach(datagridviewrow)
if(checkboxcol.checked) collectedIds+=(collectedIds==""?"":",")+IdColumn.value;

commandText="select * from tbl where Id in("+collectedIds+")";

توی شبه کد بالا فرض شده که ردیف های جدول مقصد دارای فیلد Id منحصر به فرد هستن. شما select متناسب با بانک خودت رو بنویس.

اگر هم در آینده موردی داشتین که می بایست هر بار توی حلقه سلکت بگیرید یا کلا خواستید خروجی چند کوئری رو یکجا داشته باشین، اولین آسونترین راه اینه که هر datatable رو به تعداد ردیفهاش پیمایش کنید و با دستوری که آخر پست 2 نوشتن، اون ردیف رو به Datatable نهایی اضافه کنید.

zharfa
جمعه 07 آذر 1393, 22:17 عصر
خب دوست عزیز
من فیلد کلید هام دو تا هستن یعنی کلید اصلی و خارجی دارم ...
ایده خودم اینه که تو حلقه هر سطری که تیک خورده رو با توجه به فیلداش یه سلکت بگیرم نتیجه کوئری رو که تو یه دیتاتیبل فیل شده رو هر بار به یه دیتاتیبل اصلی اضافه کنم بعد برا سطر بعدی هم همینطور
فقط نمیدونم چطور اطلاعات داخل دیتاتیبل رو به دیتاتیبل دیگه ای اضافه کنم...

mojtabamalaekeh
جمعه 07 آذر 1393, 22:35 عصر
اگه دیتاتیبلی که موقت فیل میکنی با دیتاتیبل اصلی، یه ساختار داشته باشن (یعنی فیلدهاشون یکی باشه) کدش خیلی کوتاهه

foreach (DataRow r1 in dt1.Rows)
dt2.Rows.Add(r1);

اما اگه فیلدهاشون فرق میکنه طوری که فقط خودت میدونی توی هر فیلد از دیتاتیبل اصلی چی باید ذخیره بشه:

foreach (DataRow r1 in dt1.Rows)
{
DataRow r2 = dt2.NewRow();
r2["Column1"] = "Value 1";
r2["ColumnN"] = "Value N";
dt2.Rows.Add(r2);
}

zharfa
جمعه 07 آذر 1393, 22:40 عصر
ممنون
من اطلاعاتی که از سطر های انتخاب شده واکشی میکنم مثل هم هستن فقط میخوام برا هر سطر رو واکشی کنم تو یه دیتاتیبل بعد دیتاتیبل رو پاس بدم به فرم دیگه که بقیه کارها انجام بشه
یکم کد هاتون رو کامل میکنین ممنون میشم

mojtabamalaekeh
جمعه 07 آذر 1393, 23:02 عصر
DataTable dt1 = new DataTable();
foreach(dataGridViewRow r in gridView.Rows)
if(r.CheckBoxColumn.Checked)
{
sqlDataReader dr= ...
DataTable dt2 = new DataTable();
dt2.Load(dr);
foreach(DataRow dtr in dt2.Rows)
dt1.Rows.Add(dtr);
}
به دستور if توجه کنید! کدش من درآوردیه و شما کدی جاش بذارید که باهاش تشخیص بدین اون ردیف چک خورده یا نه.
به دستوری که آخرش نقطه چین گذاشتم هم توجه کنید. نحوه ی کوئری گرفتن از بانک با توجه به «فیلد کلید، در ردیف انتخاب شده» با خودتونه :لبخند:
اگر با DataReader مشکل دارین بگین.

ضمنا جمع کردن کلیدها توی یک متغیر رشته ای و کوئری گرفتن بعد از پایان حلقه ی for راحت تره (روش پُست شماره 4).
هم کدنویسیش هم شاید سرعتش (چون هر کوئری نیاز به دسترسی به دیسک داره)

zharfa
جمعه 07 آذر 1393, 23:04 عصر
من چطور ایندکس سطر رو مشخص کنم؟

mojtabamalaekeh
شنبه 08 آذر 1393, 06:02 صبح
توی حلقه ی foreach اینجوری میشه ایندکس سطر رو گرفت:

foreach (DataGridViewRow dgvRow in dataGridView1.Rows)
{
int index = dgvRow.Index;
}

با این سؤالتون من فکر می کنم foreach کار نکردین. کد با حلقه for اینطوره:

private void button1_Click(object sender, EventArgs e)
{
string ids = "";
for (int i = 0; i < dataGridView1.Rows.Count; i++)
if ((bool)dataGridView1["MyCheckBoxCol", i].Value)
ids += (ids == "" ? "" : ",") + dataGridView1["MyIdCol", i].Value.ToString();

if (ids != "")
{

string cmdText = string.Format("SELECT * FROM tbl1 WHERE Id IN ({0})", ids);
SqlConnection sqlCn = new SqlConnection("Persist Security Info=False;Integrated Security=true;Initial Catalog=dbTest;server=(local)");
sqlCn.Open();
SqlCommand sqlCmd = new SqlCommand(cmdText, sqlCn);
SqlDataReader sqlDr = sqlCmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(sqlDr);
sqlCmd.Dispose();
sqlCn.Dispose();

//Now your 'dt' Data Table has fetched rows
}
else
{
//You hav not any data
}
}

اگر هم دیتاگرید شما خاصیت AllowUserToAddRowsش فعاله و یه سطر خالی همیشه آخرش هست باید تعداد اجرای حلقه رو منهای 1 کنید (همونجا که صورتی شده :لبخند:).

zharfa
شنبه 08 آذر 1393, 08:47 صبح
دوست عزیز از توجهتون بسیاااار سپسگذارم ....
لطف کریدد واقعا
با اندکی تامل روش خودم هم جواب داد
که همون روش اول پیشنهادی پست شماره 2 هم بود

select*from tbl Where id=1 OR id=10 OR id=100 ....



خواستم کد کامل رو برا رفاه حال دوستان بذارم که خطا میده ... حتما کد کامل رو میذارم ...
باز هم ممنون mojtabamalaekeh عزیز

Mahmoud Zaad
شنبه 08 آذر 1393, 09:11 صبح
بفرمایید. به هر دو روش انجام شده، البته شما می تونید کدهای کمتری بنویسید!

zharfa
شنبه 08 آذر 1393, 15:11 عصر
بفرمایید. به هر دو روش انجام شده، البته شما می تونید کدهای کمتری بنویسید!

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

یه جاش برام گنگه
ببینید من نتیجه کوئری رو فیل کردم به یه دیتاتیبل به اسم dt1 خب؟ حالا dt1 دارای یه سطره میخوام این یدونه سطرو به یه دیتاتیبل دیگه به اسم dt2 اضافه کنم
برای سطر بعدی هم همین داستان ... کوئری رو میگیرم باز میریزم تو dt1 بازم dt1 یه سطر داره که باز میخوام اون یدونه سطرو به دنباله dt2 اضافش کنم
موندم چطور واضحتر از این بگم ... :لبخند: مغزم درد گرفت...:گیج:

Mahmoud Zaad
شنبه 08 آذر 1393, 15:51 عصر
دیگه یه دل سیر سرچ نکردی؟!!!!
ببینید روال کار به این صورته:
اول ردیفهای دیتاگریدویو رو می خونیم ببینیم کدوم تیک داره
بعد داخل حلقه اولی، یه حلقه می نویسیم که همه رکوردهای مرتبط با این آی دی رو برامون بیاره
بعد رکوردهای برگشتی از مرحله قبل رو میریزیم تو دیتاتیبل نهایی.

مثلاً فرض کنید سطر اول شما در گرید 1 ردیف توی جدول دوم داره و سطر دوم شما 2 تا ردیف توی جدول دوم داره، و هر دو ردیف رو در گرید تیک زدید خب:
برای ردیف اول گرید: یه سلکت میخوره به دیتابیس می بینه یه ردیف توی جدول دوم هست که اونو بر میگردونه ما هم میریزیمش توی دیتاتیبل خودمون. دوباره میره اول حلقه یعنی میره سراغ ردیف دوم گرید، اینجا باز یه سلکت میخوره به دیتابیس می بینه اینجا دو تا ردیف توی جدول دوم داریم، خب اولیش رو میریزه تو دیتاتیبل، بعد میره سراغ دومیش و الخ...

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

mojtabamalaekeh
شنبه 08 آذر 1393, 16:56 عصر
سلام


ببینید من نتیجه کوئری رو فیل کردم به یه دیتاتیبل به اسم dt1 خب؟
خب بلافاصله بعدش باید از این foreach استفاده کنی:

foreach(DataRow dtr in dt1.Rows)
dtFinal.Rows.Add(dtr);
dt1 چه یه سطر داشته باشه چه هزارتا داشته باشه، این دو خط کد، سطرهای dt1 رو به دنباله dtFinal اضافه می کنه.

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

zharfa
شنبه 08 آذر 1393, 18:17 عصر
سلام


خب بلافاصله بعدش باید از این foreach استفاده کنی:

foreach(DataRow dtr in dt1.Rows)
dtFinal.Rows.Add(dtr);
dt1 چه یه سطر داشته باشه چه هزارتا داشته باشه، این دو خط کد، سطرهای dt1 رو به دنباله dtFinal اضافه می کنه.

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


این خطائیه که میده ...
This row already belongs to another table.

zharfa
شنبه 08 آذر 1393, 18:22 عصر
فرستادن این نوع کوئری به sql چقدر کار درستیه؟


select * from tbl where (code1=int1 and code2=int2 and code3=int3) Or (code1=int4 and code2=int5 and code3=int6) Or (code1=int7 and code2=int8 and code3=int8)

و الی آخر مثلا تعداد or ها به 50 عدد برسه

mojtabamalaekeh
شنبه 08 آذر 1393, 19:04 عصر
علت اول خطاش اینه که دیتاتیبل نهایی رو یادم رفت ستون بهش بدم :بامزه:

foreach (DataColumn dtc in dt1.Columns)
dtFinal.Columns.Add(new DataColumn(dtc.ColumnName, dtc.DataType));
دلیل دوم خطاش هم اینه که حلقه رو خودم تست نکردم. الان فهمیدم که اشتباهه و باید به یکی از دو صورت زیر باشه:

foreach (DataRow dtr in dt1.Rows)
dtFinal.Rows.Add(dtr.ItemArray);
یا اینجوری:

foreach (DataRow dtr in dt1.Rows)
dtFinal.ImportRow(dtr);

برای فرستادن کوئری به SQL هم اگه نگران طولانی شدن متنش هستید نگران نباشید. من کوئری با حجم حدود 1MB هم بهش دادم توی چند ثانیه اجرا کرده. 200-300 تا and , or که چیزی نمیشه.

zharfa
یک شنبه 09 آذر 1393, 19:40 عصر
لطف کردید آقا....
بالاخره سناریوی سنگین پست ما حل شد فقط راجع به بهینه بودنش موندم .... کدوم روش بهتره؟

mojtabamalaekeh
یک شنبه 09 آذر 1393, 20:23 عصر
مسلما یک بار یه دیسک مراجعه کنید بهتره تا این که در هر بار اجرای حلقه بخواین از دیتابیس، کوئری بگیرید.
مخصوصا اگه تعداد کوئری ها زیاد باشه یا حجم کوئری زیاد باشه یا هارد کند باشه یا CPU کند باشه.

Mahmoud Zaad
یک شنبه 09 آذر 1393, 20:43 عصر
ضمن تایید فرمایش دوستمون، روش دوم در جایی کاربرد داره که شما به هر دلیلی می خواید از چند جدول مختلف در دیتابیس فیلدهایی با ماهیت یکسان رو استخراج کنید، ولی در اینجا که یک جدول داریم با همون OR مساله حل میشه!