مرجع تخصصی برنامه نویسان

انجمن تخصصی برنامه نویسان فارسی زبان

کاربر سایت

alibahman47

عضویت از 1395/11/13

نوشن کوری روی جداول با ارتباط چند به چند

  • سه شنبه 28 آذر 1396
  • 11:54
تشکر میکنم

درود,

جداولی با ارتباط زیر رو دارم ,

Tbl_Color : جدول رنگ ها

Tbl_ColorProduct : اختصاص دادن رنگ به یک محصول

در بخش جستجوی سایت میخوام وقتی کاربر چندتا رنگ رو انتخاب میکنه محصولاتی که همه اون رنگ های انتخابی در جدول Tbl_ColorProduct براشون ثبت شده رو نشون بدم.

- توضیح مراحل انجام کار :

بعد از اینکه کاربر در Ui سایت چندتا رنگ رو انتخاب کنه و تیک بزنه:

یک لیست از آی دی رنگ های انتخابی به سمت اکشن زیر فرستاده میشه :

و بعد روی جداول مربوط کوری زیر رو میزنم :

حالا این کوری رو چطور بنویسم که  فقط محصولاتی رو انتخاب کنه که همه اون رنگ های انتخابی براشون در جدول Tbl_ColorProduct ثبت شده باشه ؟

پاسخ های این پرسش

تعداد پاسخ ها : 26 پاسخ
کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 12:03

کد زیر را بررسی کنید:

        var colors = new List<int>();

            Products = (from a in db.Tbl_Products
                from b in db.Tbl_ColorProduct
                where a.Id == b.Product_Id && colors.Contains(b.Color_Id)
                select a).ToList();

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 12:23

ممنون مهندس , تست کردم ,

تو این حالت اگه مثلا من رنگ آبی و زرد رو انتخاب کنم هم محصولی که رنگ آبی برایش تو جدول (Tbl_ColorProduct) ثبت شده و هم محصولی که رنگ زرد براش ثبت شده رو نشون میده ,

من میخوام فقط محصولاتی سرچ بشن که جفش این دو رنگ انتخابی براشون تو جدول (Tbl_ColorProduct) ثبت شده باشه (یعنی فقط اگه دوتا رنگ انخابی براشون ثبت شده بود تو نتیجه کوری باشن) .

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 13:57
  var colors = new List<int>();

            Products = (from a in db.Tbl_Products
                from b in db.Tbl_ColorProduct
                where a.Id == b.Product_Id && colors.Where(i => i == b.Color_Id)
                select a).ToList();

به جای Contains از Where استفاده کنید.

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 14:15

دستور where رو به اینصورت بنویسم که اخطار میده :

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 14:21

عذرخواهی میکنم اصلاح شد:

colors.Where(i => i == b.Color_Id).Any()

یا 

colors.Any(i => i == b.Color_Id)

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 15:25

خواهش میکنم , نتیجه این کوری هم دقیقا مثل Contains میشه و اگه دوتا رنگ رو انتخاب کنم هر محصولی که یکی از رنگ ها براش ثبت شده باشه تو نتیجه کوری میاد .

عذرمیخوام مهندس متوجه توضیحی که بالا دادم شدید ؟!

من میخوام انتخاب محدودتر باشه و فقط محصولی انتخاب بشه که همه رنگ های انتخابی براش ثبت شده باشه ؟

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 17:00

مدل های Product و productColor را قرار بدید.

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 17:19

.........................................................................................................

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 17:54

مدل هایی که توسط EF تولید شده و در برنامه شما وجود دارد را نمایش دهید.

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 18:12

..........................................................................................

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 18:16

بنده میخوای کدهای سی شارپ رو بررسی کنم Ef یه سری مدل به صورت کلاس برروی پروژه شما قرار داده است. برروی sloution خود نام جداول را جستجو کنید تا بتوان آن را پیدا کنید.

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 18:21
شرمنده مهندس,
منظورتون همینه ؟

Tbl_Color


    using System;
    using System.Collections.Generic;
    
    public partial class Tbl_Color
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Tbl_Color()
        {
            this.Tbl_ColorProduct = new HashSet<Tbl_ColorProduct>();
        }
    
        public int Id { get; set; }
        public string Title { get; set; }
        public string CodeOrName { get; set; }
    
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Tbl_ColorProduct> Tbl_ColorProduct { get; set; }
    }

Tbl_ColorProduct{

    using System;
    using System.Collections.Generic;
    
    public partial class Tbl_ColorProduct
    {
        public int Id { get; set; }
        public int Color_Id { get; set; }
        public int Product_Id { get; set; }
    
        public virtual Tbl_Color Tbl_Color { get; set; }
        public virtual Tbl_Products Tbl_Products { get; set; }
    }

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 18:34

این کد هم بررسی کنید:

  var colorFilter = new List<int>();
  var colors = db.Colors.Where(c => colorFilter.Any(x => x == c.ColorId)).ToList();
  var products = db.Products.Where(p => p.ProductColor.Any(pc => colors.Any(x => x == pc.ColorId))).ToList();

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 18:44

اگر بازهم نشد به جای Any() از All() استفاده کنید.

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 18:52

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 18:55
      var colorFilter = new List<int>();
            var colors = db.Colors.Where(c => colorFilter.Any(x => x == c.ColorId)).ToList();
            var products = db.Products.Where(p => p.ProductColor.Any(pc => colors.Any(x => x.Id == pc.ColorId))).ToList();

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 18:57

در خط دوم از کدی که گذاشتید c.ColorId رو نمیشه گذاشت چون کوری روی خود جدول Tbl_Color هست و Id رو نوشتم .

در خط بعد هم اخطار رو میبینید .

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 19:02

کد های اصلاح شده جدید را تست کردید (بنده intellisense  ندارم به همین دلیل اشتباه نوشتم اون قسمت رو)

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 19:17

شرمنده مهندس که وقتت رو گرفتم ,

به این شکل نوشتم ولی خط آخر رو که میخونه به خطا میخوره و به قسمت Catch میره .

                    var colorFilter = new List<int>(PColor);
                    var colors = db.Tbl_Color.Where(c => colorFilter.Any(x => x == c.Id)).ToList();
                    var products = db.Tbl_Products.Where(p => p.Tbl_ColorProduct.Any(pc => colors.Any(x => x.Id == pc.Color_Id))).ToList();

راهی هست که خطای رخ داده رو ببینیم ؟

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • سه شنبه 28 آذر 1396
  • 20:25

مهندس همون کد قبلی که گفتید :

                    var colors = new List<int>(PColor);

                    Products = (from a in db.Tbl_Products
                                from b in db.Tbl_ColorProduct
                                where a.Id == b.Product_Id && colors.Where(i => i == b.Color_Id).Any()
                                select a).ToList();

بخوام به جای From دوم از جوین استفاده کنم کد رو به چه صورت باید ویرایش کنم , میشه لطف کنید این رو هم بگید که تست کنم ؟

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • سه شنبه 28 آذر 1396
  • 22:01

شما از Lazy Load استفاده می کنید به همین دلیل نیاز نیست join بزنید رابطه ایجاد شده به صورت خودکار واکشی می شود.

برای نمایش خطا هم از کد زیر استفاده کنید:

       try
            {
                // code
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw;
            }

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • پنجشنبه 30 آذر 1396
  • 13:16

اگه کد رو بصورت زیر بنویسم :

                   IEnumerable<Tbl_Products> Products = Bl_Product.Select(); // انتخاب همه محصولات
                    var colors = new List<int>(PColors);
                    foreach (var color in colors)
                    {
                        Products = (from a in Products
                            from b in db.Tbl_ColorProduct
                            where a.Id == b.Product_Id && b.Color_Id == color
                            select a).ToList();

                    }

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

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • پنجشنبه 30 آذر 1396
  • 13:45

باید کوئری تولید شده را بررسی کنیم و چند راه کار را امتحان کنیم:

    var query = db.tBl_Product.AsNoTracking(); 

            var colors = new List<int>(PColors);

            foreach (var color in colors)
            {
                query = query.Where(x => x.Tbl_ColorProduct.Any(o => o.Color_Id == color)).AsQueryable()
            }

            var result = query.ToList();

            db.Database.Log = log => Debug.WriteLine(log);

برای مشاهده کوئری پنجره output را باز کنید.

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • پنجشنبه 30 آذر 1396
  • 16:12

بازهم ممنون ,

بصورت زیر نوشتم بازهم هر محصولی که یکی از رنگ هی انتخابی کاربرا رو داشت برگشت میده :

بصورت زیر نوشتم اوکی شد :

کاربرد اون .AsNoTracking(); چیه ؟ و اون Log که خط آخر نوشتید ؟

حالا به این صورت که گفتید بنویسم دیگه حله ؟  نوشتن کوری داخل حلقه که باعث ایرادی بعدا نمیشه ؟

کاربر سایت

سهیل علیزاده

عضویت از 1396/04/09

  • پنجشنبه 30 آذر 1396
  • 16:33

در آخر گفتم کوئری که توسط این کد تولید شده را با استفاده از کدی که نوشتیم میتوانیم مشاهده کنیم. حال برای این کار پنجره ای در VS وجود دارد به نام output برای مشاهده آن کوئری میتوان آن پنجره را باز کنید.(برای این کار از EF Profiler هم می توانید استفاده کنید.)

AsNoTracking را در مقاله ای که برای بهبودی عملکر نوشته بودم توضیح دادم . 

کاربر سایت

alibahman47

عضویت از 1395/11/13

  • پنجشنبه 30 آذر 1396
  • 20:56

رفتم دوباره مقاله رو نگاه کردم , ریپوزیتوری Select رو بصورت AsNoTracking کردم .

برای بخش سایز و رنگ بنظرم همین کدی که گفتید عالیه ,

میخوام بین چک فیلتر های یک فیلتر خاص کوری بصورت Or اجرا بشه و بین دوتا فیلتر مختلف رابطه And باشه .

نتیجه این کوری همون چیزی هست که میخوام ,

مشکل اینه که با اجرا شدن چند باره ی کوری بخش Or یک محصول چندبار انتخاب میشه و در نتیجه میبینید که یک محصول چند بار نمایش داده میشه .

 - برای جلوگیری از ذخیره سطر های تکراری در لیست IEnumerable<Tbl_Products> Products چه کدی رو باید بنویسم ؟

 - یا میشه در آخر یک دستور روی Products  بنویسم که سطر های تکراری رو حذف  کنه ؟

کاربرانی که از این پست تشکر کرده اند

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

اگر نیاز به یک مشاور در زمینه طراحی سایت ، برنامه نویسی و بازاریابی الکترونیکی دارید

با ما تماس بگیرید تا در این مسیر همراهتان باشیم :)