PDA

View Full Version : مشکل در استفاده از dgv با entity framework



amir3321
جمعه 23 دی 1390, 17:43 عصر
من یک کوئری با linq نوشتم و مقدار اون و به دیتا سورس dgv پاس کردم ولی در این حالت متد autosort در dgv که بصورت پیش فرض در dgv قرار دارد غیر فعال می شود می خواستم بدونم چطور می تونم با تغییر در نوع کوئری این مشکل رو حل کنم مثلا تبدیل کوئری به دیتاتیبل
از آقایان مدیران خواهشمندم راهنمایی فرمائید

amir3321
یک شنبه 25 دی 1390, 09:15 صبح
کسی نیست یک راهنمایی کند مشکل من در استفاده از EF است چون من قبلا از DS,DA استفاده می کردم این مشکل رو نداشتم ولی حالا که از LINQ برای ایجاد کوئری استفاده می کنم فکر می کنم باید تغییری در نوع کوئری بدهم یا اونو تبدبل به یک دیتاتیبل کنم تا متد AUTOSORT در DGV فعال بشود یا اگر هم کسی می تونه از طریق کد این مشکل من رو حل کند خوشحال می شوم
البته نحوه تبدیل کوئری به دیتاتیبل رو یکی از مدیران عزیز توضیح دهد ممنون می شوم در بعضی از جاها دیدم از متدی در QUERY به نام COPYTODATATABLE استفاده کرده که نفهمیدم توسط کد نویس ایجاد شده یا در کلاس های لینک دات نت وجود دارد

amir3321
سه شنبه 27 دی 1390, 11:41 صبح
مشکل با راهنمایی استاد gwbasic حل شد
با این روش می تونید عمل sort رو در dgv زمان استفاده از EF داشته باشد مانند زمانیکه بوسیله ds,dt کار می کنید ولی یک فرق مهم دارند که در زمانیکه از DS,DT استفاده می کنید برای هر بار SORT کردن اطلاعات از دیتابیس خوانده نمی شوند ولی در این روش هر بار اطلاعات از دیتابس خوانده می شوند یعنی عمل SORT در خود دیتابیس انجام وسپس واکشی انجام می گیرد
bool _isSortAscending ;
DataGridViewColumn _sortColumn;
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{

DataGridViewColumn column = dataGridView1.Columns[e.ColumnIndex];
_isSortAscending = (_sortColumn == null || _isSortAscending == false);
string direction = _isSortAscending ? "ASC" : "DESC";
if (_isSortAscending)

bindingSource1.DataSource = db.part.OrderBy(
string.Format("it.{0} {1}", column.DataPropertyName, direction)).ToList();

else

bindingSource1.DataSource = db.part.OrderBy(
string.Format("it.{0} {1}", column.DataPropertyName, direction)).ToList();

if (_sortColumn != null) dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = SortOrder.None;
dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection =
_isSortAscending ? SortOrder.Ascending : SortOrder.Descending;
_sortColumn = column;

}
من چند تامشکل داشتم اول اینکه نحوه اتصال DGV به BS اشتباه بود
dataGridView1.DataSource = bindingSource1.DataSource;
که با تغییر در BS تغییر در DGV اعمال نمی شد
dataGridView1.DataSource = bindingSource1;
دوم اینکه در کد دوم که گذاشتند متد ها GETVALUE در زمان اجرا باخطا مواجه مشد که می گفت این متد قابل استفاده در EF نیست که من دلیل اون رو نفهمیدم و از کد قبلی استفاده کردم
دیگر اینکه درموقع پاس کردن متد SORTORDER به COLUMN ایجاد شده خطا می گرفت که مجبور شدم بصورت مستقیم با اون کار کنم
dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection

حالا می خواستم بدونم راهی هست که عمل واکشی از دیتابیس مانند DT فقط یک بار انجام شود و عملیات SORT بصورت LOCAL روی همان دیتای لود شده در کوئری انجام گیرد

با تشکر از جناب GWBASIC

gwbasic
سه شنبه 27 دی 1390, 12:03 عصر
فرض کنید لیست مشتری ها رو می خواید از DataBase بخونید همانطور که در آن پست اشاره کردم باید داده ها رو ابتدا در لیست بریزید و این لیست هست که باید باهاش کار کنید و اون رو Sort کنید به این روش دیگه داده ها دوباره از DB خونده نمی شه کدی رو هم که نوشته بودم رو تست کردم و جواب میده

List<Customer> customers = context.Customer.ToList();

amir3321
سه شنبه 27 دی 1390, 16:16 عصر
با سلام خدمت استاد
حق کاملا با شماست موقعیکه کوئری رو از نوع زیر یا IEnumerable تعریف می کنم جواب میدهد و ولی فقط در حالت زیر اطلاعات رو دوباره واکشی نمی کند

public static List<part> query;
public void button1_Click(object sender, EventArgs e)
{

query = db.part.ToList();

bindingSource1.DataSource = query;
dataGridView1.DataSource = bindingSource1;
}

و نحوه استفاده از کد دوم هم درست می شود
bool _isSortAscending ;
DataGridViewColumn _sortColumn;
private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{

DataGridViewColumn column = dataGridView1.Columns[e.ColumnIndex];
_isSortAscending = (_sortColumn == null || _isSortAscending == false);
string direction = _isSortAscending ? "ASC" : "DESC";
if (_isSortAscending)

bindingSource1.DataSource = query.OrderBy(c => c.GetType().GetProperty(column.DataPropertyName).G etValue(c, null));

else

bindingSource1.DataSource = query.OrderByDescending(c => c.GetType().GetProperty(column.DataPropertyName).G etValue(c, null));

if (_sortColumn != null) dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection = SortOrder.None;
dataGridView1.Columns[e.ColumnIndex].HeaderCell.SortGlyphDirection =
_isSortAscending ? SortOrder.Ascending : SortOrder.Descending;
_sortColumn = column;

}




در باره مقدار واکشی از دیتابیس وقتی که کاربر نیاز به جستجو دارد و دقیقا نمی داند دنبال چیست و با زدن هر حرف یک بار عملیات جستجو بعد از sort انجام میشود اگر بخواهیم صفحه ای واکشی نمائیم مشکل زیاد می شود البته این نوع جستجو رو من در سیستم های بزرگ یکپارچه دیدم مثل جستجو در سطح شرح کالا در انبار در سیستم های تحت lan نه wan
نظر شما اینه که با هر تغییر مثلا در textboxserch یک بار عمل واکشی انجام ولی فقط 20 سطر اخر لود شود ایا این بیشتر زمان گیر نیست

با تشکر فراوان از راهنمایی شما

amir3321
چهارشنبه 28 دی 1390, 13:09 عصر
با سلام
می خواستم یکم راجع به این نحوه گرفتن پراپرتی ها در linq و lambda توضیح بدهید که چگونه می شود به همین صورت که شما نام فیلد رو بوسله پراپرتی گرفتید بگیریم و روی آن فیلد یک شرط خاص قرار دهیم من با چند تا از این ها امتحان کردم ولی نشد

query.where(c => c.GetType().GetProperty(column.DataPropertyName).G etValue(c, null).contains('ab'));




یک چیزی شبیه به این customers.where(c=>c.Name.Contains("john"));

ولی c.name رو بوسیله پراپرتی بسازم مثل نمونه اول

با تشکر از راهنمایی های شما

gwbasic
چهارشنبه 28 دی 1390, 17:02 عصر
اگه منظورتون رو درست متوجه شده باشم شما می خواید Dynamic Query بسازید. برای این کار باید با Expression Tree آشنا باشید و خودتون Expression را بسازید.
این لینک (http://msdn.microsoft.com/en-us/library/bb397951.aspx) به شما کمک می کنه

amir3321
چهارشنبه 28 دی 1390, 17:34 عصر
با سلام
در مورد dynamic query یک کم مطالعه داشتم ولی نیاز من در اون حد نیست فقط من نحوه کار شما با پراپرتی ها مثل gettype, GetProperty,GetValue که در کوئری نویسی linq نیاز می شود رو می خواستم بدونم فکر کنم نیاز من فقط در همین حد گرفتن نام یک فیلد از خارج کوئری درست مثل کاری که شما کردید و مثلا یک شرط روی اون فیلد مثل contains قرار دهم اگر درست متوجه شده باشم در داینامیک کوئری ما تمام جزئیات یک کوئری رو می تونیم در زمان اجرا با تغیرات احتمالی در سطح برنامه تغییر بدهیم و این از نیاز من خیلی بالاتر می باشد
با تشکر از راهنمای های شما

gwbasic
جمعه 30 دی 1390, 19:09 عصر
سلام امیر جان! چند تا موردو می گم بررسی کن
شما باید فرق IEnumerable و IQueryable‌رو بدونی ( حالا اگه من بگم شما اینو بررسی کن بعد یه توضیحی همینجا بده بقیه دوستان هم استفاده کنن که نمی کنی!! بماند)
وقتی OrderBy روی context می زنیم overload ای وجود داره که string می گیره و کار مارو برای dynamic sort راحت می کنه چون کافیه column.DataPropertyName رو که همون نام پراپرتی مورد نظر ما برای sort هست رو بهش بدیم و کار تمام هست نکته اینجاست که این OrderBy برای Collection هایی هست که IQueryable هستند ولی وقتی روی List می خواهیم عمل OrderBy رو انجام بدیم چون IEnumerable هست بنابراین چنین overload‌ای وجود نداره که string‌بگیره و متاسفانه متد sort هم که برای لیست وجود داره نیاز ما رو برآورده نمی کنه. برای همین هست که از reflection استفاده شده (GetValue, GetProperty, GetType) پس reflection رو با Linq قاطی نکنید.
در هر صورت راه درست استفاده از Expression Tree هست که توصیه می کنم حتما بخونی زیباست
اما کدت رو به سادگی می تونستی درست کنی:

customers = customers.Where(c => c.GetType().GetProperty("Name").GetValue(c,null).ToString().Contains(column.Data PropertyName)).ToList();

amir3321
شنبه 01 بهمن 1390, 11:33 صبح
با سلام خدمت استاد عزیز
در مورد فرق ایندو یک مطلب از سایت آقای نصیری پیدا کردم می گذارم شاید بدرد بخورد
http://www.dotnettips.info/2010/10/iqueryable-ienumerable-orms.html


تفاوت بين IQueryable و IEnumerable در حين كار با ORMs



متد زير را كه يكي از اشتباهات رايج حين استفاده از LINQ خصوصا جهت Binding اطلاعات است، در نظر بگيريد:

IQueryable<Customer> GetCustomers()





اين متد در حقيقت هيچ چيزي را Get نمي‌كند! نام اصلي آن GetQueryableCustomers و يا GetQueryObjectForCustomersاست.
IQueryable قلب LINQ است و تنها بيانگر يك عبارت (expression) از ركوردهايي مي‌باشد كه مد نظر شما است و نه بيشتر.

IQueryable<Customer> youngCustomers = repo.GetCustomers().Where(m => m.Age < 15);




براي مثال زمانيكه يك IQueryable را همانند مثال فوق فيلتر مي‌كنيد نيز هنوز چيزي از بانك اطلاعاتي يا منبع داده‌اي دريافت نشده است. هنوز هيچ اتفاقي رخ نداده است و هنوز رفت و برگشتي به منبع داده‌اي صورت نگرفته است.
به آن بايد به شكل يك expression builder نگاه كرد و نه ليستي از اشياء فيلتر شده‌ي ما. به اين مفهوم، deferred execution (اجراي به تاخير افتاده) نيز گفته مي‌شود (بايد دقت داشت كه IQueryable هم يك نوع IEnumerable است به علاوه expression trees كه مهم‌ترين وجه تمايز آن نيز مي‌باشد).
براي مثال در عبارت زير تنها در زمانيكه متد ToList فراخواني مي‌شود، كل عبارت LINQ ساخته شده، به عبارت SQL متناظر با آن ترجمه شده، اطلاعات از ديتابيس اخذ گرديده و حاصل به صورت يك ليست بازگشت داده مي‌شود:

IList<Competitor> competitorRecords = competitorRepository
.Competitors
.Where(m => !m.Deleted)
.OrderBy(m => m.countryId)
.ToList(); //فقط اينجا است كه اس كيوال نهايي توليد مي‌شود





در مورد IEnumerable ها چطور؟

IEnumerable<Product> products = repository.GetProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);




دو سطر فوق به اين معنا است:
لطفا ابتدا به بانك اطلاعاتي رجوع كن و تمام ركوردهاي محصولات موجود را بازگشت بده. سپس بر روي اين حجم بالاي اطلاعات، محصولاتي را كه قيمت بالاي 25 دارند، فيلتر كن.

اگر همين دو سطر را با IQueryable بازنويسي كنيم چطور؟

IQueryable<Product> products = repository.GetQueryableProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);




در سطر اول تنها يك عبارت LINQ ساخته شده است و بس. در سطر دوم نيز به همين صورت. در طي اين دو سطر حتي يك رفت و برگشت به بانك اطلاعاتي صورت نخواهد گرفت. در ادامه اگر اين اطلاعات به نحوي Select شوند (يا ToList فراخواني شود، يا در طي يك حلقه براي مثال Iteration ايي روي اين حاصل صورت گيرد يا موارد مشابه ديگر)، آنگاه كوئري SQL متناظر با عبارت LINQ فوق ساخته شده و بر روي بانك اطلاعاتي اجرا خواهد شد.
بديهي است اين روش منابع كمتري را نسبت به حالتي كه تمام اطلاعات ابتدا دريافت شده و سپس فيلتر مي‌شوند، مصرف مي‌كند (حالت بازگشت تمام اطلاعات ممكن است شامل 20000 ركورد باشد، اما حالت دوم شايد فقط 5 ركورد را بازگشت دهد).

سؤال: پس IQueryable بسيار عالي است و از اين پس كلا از IEnumerable ها ديگر نبايد استفاده كرد؟
خير! توصيه اكيد طراحان اين است كه لطفا تا حد امكان متدهايي كه IQueryable بازگشت مي‌دهند ايجاد نكنيد! IQueryable يعني اينكه اين نقطه‌ي آغازين كوئري در اختيار شما، بعد برو هر كاري كه دوست داشتي با آن در طي لايه‌هاي مختلف انجام بده و هر زمانيكه دوست داشتي از آن يك خروجي تهيه كن. خروجي IQueryable به معناي مشخص نبودن زمان اجراي نهايي كوئري و همچنين مبهم بودن نحوه‌ي استفاده از آن است. به همين جهت متدهايي را طراحي كنيد كه IEnumerable بازگشت مي‌دهند اما در بدنه‌ي آن‌ها به نحو صحيح و مطلوبي از IQueryable استفاده شده است. به اين صورت حد و مرز يك متد كاملا مشخص مي‌شود. متدي كه واقعا همان فيلتر كردن محصولات را انجام مي‌دهد، همان 5 ركورد را بازگشت خواهد داد؛ اما با استفاده از يك ليست يا يك IEnumerable و نه يك IQueryable كه پس از فراخواني متد نيز به هر نحو دلخواهي قابل تغيير است.

از کدی که به همراه توضیحات گذاشتید بسیار ممنون در اولین فرصت امتحان می کنم

در مورد Expression Tree جستجو کردم ولی هنوز یک چیزی که کامل بفهمش پیدا نکردم چون نحوه DYNAMIC QUERY در LINQ TO SQL بسیار ساده شده بود طوری که من دیدم حتی می تونستیم مستقیما بصورت STRING کار کنیم البته این باعث همان مشکل ناهمخوانی زبانها می گردد که با TSQL در سی شارپ داشتیم ولی Expression Tree این مشکل رو ندارد انشاءالله بزودی این رو هم با مطالعه و کمک استادان عزیز یاد می گیرم

با تشکر فراوان

amir3321
یک شنبه 02 بهمن 1390, 19:10 عصر
با سلام خدمت استاد عزیز
یک نمونه عمل filter و sort که با linq انجام دادم رو جهت مشاهده و استفاده از نظرات شما قرار دادم

82312

چند جا به مشکل خوردم که بعضی هاش رو دیگه دور زدم
1 . نتونستم کل کوئری خودم رو dynamic کنم
2 . در استفاده از یک کوئری جهت کلیه عملیات ها در سراسر پروژه موفق نشدم .
3 . بعد از عمل فیلتر چون کوئری با کوئری sort عوض می شد حالت گرافیکی sort بالای column دیتاگرید از بین می رفت.
4. ببخشید چون دنبال یک موضوع خاص بودم از کلاس و تابع استفاده نکردم .

ببخشید در خود بایندینگ عمل sort , filter دارد آیا می توان از آن مانند dataview استفاده نمود چون من حتی نتونستم از فیلتر اون هم استفاده کنم .
منتظر راهنمایی های ارزنده شما هستم

Boy_nn
یک شنبه 09 بهمن 1390, 08:34 صبح
سلام امیر جان! چند تا موردو می گم بررسی کن
شما باید فرق IEnumerable و IQueryable‌رو بدونی ( حالا اگه من بگم شما اینو بررسی کن بعد یه توضیحی همینجا بده بقیه دوستان هم استفاده کنن که نمی کنی!! بماند)
وقتی OrderBy روی context می زنیم overload ای وجود داره که string می گیره و کار مارو برای dynamic sort راحت می کنه چون کافیه column.DataPropertyName رو که همون نام پراپرتی مورد نظر ما برای sort هست رو بهش بدیم و کار تمام هست نکته اینجاست که این OrderBy برای Collection هایی هست که IQueryable هستند ولی وقتی روی List می خواهیم عمل OrderBy رو انجام بدیم چون IEnumerable هست بنابراین چنین overload‌ای وجود نداره که string‌بگیره و متاسفانه متد sort هم که برای لیست وجود داره نیاز ما رو برآورده نمی کنه. برای همین هست که از reflection استفاده شده (GetValue, GetProperty, GetType) پس reflection رو با Linq قاطی نکنید.
در هر صورت راه درست استفاده از Expression Tree هست که توصیه می کنم حتما بخونی زیباست
اما کدت رو به سادگی می تونستی درست کنی:

customers = customers.Where(c => c.GetType().GetProperty("Name").GetValue(c,null).ToString().Contains(column.Data PropertyName)).ToList();


سلام
من می خوام یه برنامه سه لایه باLinq بنویسم
یه لایه به اسم DAL ایجاد کردم و توش یه Linq to SQL ایجاد کردم و یک جدول هم داخلش ادد کردم
لایه دوم رو به اسم bll ایجاد کردم و لایه DAL رو ادد کردم
و یه لیست پایلیک ازنوع جدولم ایجاد کردم و اطلاعات جدول رو توش ریختم
حالا لایه به اسم UI هم ایجاد کردم که داخلش هم یه دیتاگریدویو ایجاد کردم و لایه bll رو ادد کردم
حالا می خوام اطلاعات جدولی که در لایه DALقرارداره از طریق لایه BLLتوی دیتا گریدویو لایهUI نمایش داده بشه و همینطور بتونم اطلاعات رو فیلتر کنم
ولی سیستم ارورر میده و میگه که لایه DAL رو باید توی لایه UI ادد کنم

ممنون میشم اگه کمکم کنی