-3

I have a Product table in my DB. Also, I have Brand and Category tables in my DB which are not related to each other. I want to relate these. In the form UI when I click the one of the Categories, should come the Brands which they have products in the related category.

I tried this way to do this. First, I get my products by categoryID with GetList method then I get these products' brands and I added these brands to pblist list(Brand type). However, some products have the same brands and pblist have repeated brand names. I tried to fix this with contains method but it does not work. Also, I have the same problem in the other part which I try to remove brands not included in pblist from blist(all brands' list). I tried removing item from blist by taking its index with this code: blist.RemoveAt(blist.IndexOf(item)); but this one also not working.It returns -1. But item is in the blist.

 public class BrandVM : BaseVM
{
    public int ProductCount { get; set; }

}

 public class BaseVM
{
    public int ID { get; set; }
    public string Name { get; set; }

    public override string ToString()
    {
        return this.Name;
    }

 public class BrandService : ServiceBase, IBrandService
{


    public List<BrandVM> GetList(int Count)
    {
        try
        {
            var result = GetQuery();
            result = Count > 0 ? result.Take(Count) : result;

            return result.ToList();
        }
        catch (Exception ex)
        {

            return null;
        }
    }


public List<BrandVM> GetListByCatID(int pCatID)
    {
        var plist = productService.GetListByCatID(pCatID);
        List<BrandVM> pblist = new List<BrandVM>();
        foreach (var item in plist)
        {
            if (!pblist.Contains(item.Brand))
            {
                pblist.Add(item.Brand);
            }
        };

        var blist = GetList(0);
        var blistBackup = GetList(0);

        foreach (BrandVM item in blistBackup)
        {
            if (!pblist.Contains(item))
            {
                blist.Remove(item);
            }       
        };

        return blist;
    } 

These are my classes related to Brand. In BrandService I shared the filled methods there are more methods to fill.

This is method is in my ProductService: I use that method to pull product list by CategoryID (plist)

public List<ProductVM> GetListByCatID(int EntityID)
    {
        try
        {
            var result = GetQuery().Where(x => x.Category.ID==EntityID);

            return result.ToList();
        }
        catch (Exception ex)
        {

            return null;
        }
    }

This GetQuery method for ProductService, in other services there are some differences but there are similar

  private IQueryable<ProductVM> GetQuery()
    {
        return from p in DB.Products
               select new ProductVM
               {
                   ID = p.ProductID,
                   Name = p.ProductName,
                   UnitPrice = (decimal)p.UnitPrice,
                   Category =p.CategoryID==null?null:new CategoryVM()
                   {
                       ID = (int)p.CategoryID,
                       Name = p.Category.CategoryName
                   },
                   Brand = p.BrandID == null ? null :
                   new BrandVM
                   {
                           ID=(int)p.BrandID,
                           Name=p.Brand.BrandName,

                   }


               };
    }
  • 1
    It would be awesome if you could share a [mcve]. Be sure that it is a block of code that I can copy and paste into a console app and run **as is without modification**. Be sure to specify inputs **in code** and be clear as to what the expected output is. – mjwills Sep 12 '19 at 23:17
  • Possible duplicate of [.Contains() on a list of custom class objects](https://stackoverflow.com/questions/2629124/contains-on-a-list-of-custom-class-objects) – trailmax Sep 12 '19 at 23:25
  • It is my entity framework introduction project. There are many classes and projects in the solution which connected to each other. I think, to run this part of code I should share the complete solution of the project. – Ödül Öngören Sep 12 '19 at 23:26
  • 1
    @ÖdülÖngören see the top answer in the linked question. You need to override `Equals()` and `GetHashCode()` in your `BrandVM` class. – trailmax Sep 12 '19 at 23:31
  • @ÖdülÖngören or don't do the comparison by object, rather by description. i.e. use `item.Brand.Name` for comparison. – trailmax Sep 12 '19 at 23:33
  • If you could at least describe the schema somewhat, it would be eaiser to answer. What are the relationships between `Product`, `Brand`, and `Category`? Presumably a `Product` has only one `Brand`, but does it also only belong to one `Category`? – Rufus L Sep 12 '19 at 23:42
  • @trailmax I should return this method as object list. I want to show them in the listbox in the form to see which products are in the selected brand. if I compare them by name I must declare the pblist and blist as a string list right? – Ödül Öngören Sep 12 '19 at 23:42
  • @ÖdülÖngören if you implement the equality overrides (see the duplicate QA link), you will have it working without having to redo the comparisons. – trailmax Sep 12 '19 at 23:47
  • @RufusL in DB side I have Product, Brand and Category table. Product belongs to one category and one brand. Product table has CategoryID but brand table has not.So,I cannot pull the brands with categoryID.I should bring them by relating to products.But I was asked to do it without making any changes to the database. – Ödül Öngören Sep 12 '19 at 23:48

2 Answers2

1

Entity framework will translate Linq queries into SQL statements, which means that Equals (and GetHashCode) will not be used for comparison of database objects. However, if you're comparing local instances of these objects, then these methods will be used for comparisons.

The default Equals does a reference comparison to determine equality, which literally means that two instances of a type are only considered equal if they both refer to the exact same object in memory.

Instead, we want to use the ID property for equality comparison, which means we need to override the Equals (and GetHashCode) methods for the class.

Here's an example of how you could do this:

public class BaseVM
{
    public int ID { get; set; }
    public string Name { get; set; }

    public override string ToString()
    {
        return Name;
    }

    public override bool Equals(object obj)
    {
        return obj is BaseVM &&
               ((BaseVM) obj).ID == ID;
    }

    public override int GetHashCode()
    {
        return ID;
    }
}

Alternatively, if you don't want to modify the class (which I would recommend since it solves this problem everywhere), you can modify your code to filter out any brands that have the same id (or name):

foreach (var item in plist)
{
    // Note: you could potentially use 'Name' instead of 'Id'
    if (!pblist.Any(productBrand => productBrand.Id == item.Brand.Id))
    {
        pblist.Add(item.Brand);
    }
}
Rufus L
  • 36,127
  • 5
  • 30
  • 43
0

Since you don't ensure that two different instances for a same brand are not equal, in the sense that ´.Equals(object other)´ returns true, the ´.Contains´ method as no way to identify them.

I think you'ĺl solve you issue by overriding .Equals in you Brand class.