skip to Main Content

I have two entities (Product and Supply) that have a many-to-many relationship. I also have an entity between then that holds the two ID’s (SupplyProduct).

My entities:

    public class Product
    {
        [Key]
        public int ProductId { get; set; }
        [Required]
        public string? ProductName { get; set; }
        [Required]

        [Column(TypeName = "decimal(6,2)")]
        public decimal UnitPrice { get; set; }
        public int Quantity { get; set; }
        public string? Brand { get; set; }
        public DateTime CreatedDateTime { get; set; } = DateTime.Now;

        //Many to many relationship between the products and the stocks
        public virtual ICollection<SupplyProduct>? SupplyProducts { get; set; }
    }

    public class Supply
    {
        [Key]
        [Required]
        public int SupplyId { get; set; }
        [Required]

        [DisplayName("Supply's Label")]
        public string? Label { get; set; }
        
        //One to many relationship between the Stock and the Merchant
        public Merchant? Merchant { get; set; }

        //Many to many relationship between the stocks and the products
        public virtual ICollection<SupplyProduct>? SupplyProducts { get; set; }

    }

    public class SupplyProduct
    {
        [Key]
        public int SupplyId { get; set; }
        public virtual Supply? Supply { get; set; }
        [Key]
        public int ProductId { get; set; }
        public virtual Product? Product { get; set; }
    }

I want to assign a supply to a product while creating it . and then show the supply with it’s associated products

this is my products controller:

ProductsController.cs

public class ProductController : Controller
    {
        private readonly ApplicationDbContext _db;

        public ProductController(ApplicationDbContext db)
        {
            _db = db;
        }

        // GET: ProductController
        public ActionResult Index()
        {
            IEnumerable<Product> ProductsList = _db.Products;
            return View(ProductsList);
        }

        // GET: ProductController/Create
        public ActionResult Create()
        {
            IEnumerable<Supply> SuppliesList = _db.Supplies.Include(s => s.Merchant);
            ViewBag.Supplies = SuppliesList;
            return View();
        }

        // POST: ProductController/Create
        [HttpPost]
        public ActionResult Create(Product model, List<int> supplyIds)
        {
            _db.Products.Add(model);
            _db.SaveChanges();
            
            SupplyProduct SP = new();
            foreach (var supplyId in supplyIds)
            {
                SP.SupplyId = supplyId;
                SP.ProductId = model.ProductId;
                SP.Product = model;
                SP.Supply = _db.Supplies.Where(x => x.SupplyId == supplyId).FirstOrDefault();
            }
            _db.SupplyProducts.Add(SP);
            _db.SaveChanges();
            return RedirectToAction(nameof(Index));
        }
}

Can you please check my post Create method if it is as it should be, and how can I get the Products data while returning the Supplies in the Index method into the index view?

Thank you so much for your help and happy coding 😀

2

Answers


  1. You can remove the SupplyProduct tabble if there are no additional properties in anything other than Supply Product you don’t need it for many-to many.
    Then initialize the collections in the Supply and Product

    public class Product
    {
        public Product()
        {
            this.Supplys = new HashSet<Supply>();
        }
    
        //... your props
    
        public virtual ICollection<Supply> Supplys { get; set; }
    }
    
    public class Supply
    {
        public Supply()
        {
            this.Products = new HashSet<Product>();
        }
    
        //... your props
    
        public virtual ICollection<Product> Products { get; set; }
    }
    
    

    Add Product to Supplys with only one query (in your code you make query for everyone Id in supplyIds)

    [HttpPost]
    public ActionResult Create(Product model, List<int> supplyIds)
    {
         //Get all supplys you need by id
         var supplys = _db.Supplys
             .Where(x => supplyIds.Contains(x.SupplyId))
             .ToList();
         
         //Add product in each supply
         foreach (var supply in supplys)
         {
             supply.Products.Add(model);
         }
    
         //Update db
         _db.SaveChanges();
    
         return RedirectToAction(nameof(Index));
    }
    
    

    Get from DB

    public ActionResult GetSuplys(List<int> supplyIds)
    {
         //Here you get all Supplys with the Products in it
         var supplys = _db.Supplys
             .Include(x => x.Products)
             .Where(x => supplyIds.Contains(x.SupplyId))
             .ToList();
    
         //...
    }
    
    

    Save new Supply of Product

    public ActionResult NewSuply()
    {
    
         var supply = new Supply
         {
            ProductName = name,
            //Add all props you need
            //You can add Product here or add empty collection
            Products.Add(product), or = new List<Product>();
         }
         
         //No need to save Product separate
         _db.Add(supply);
         _db.SaveChanges();
    }
    
    Login or Signup to reply.
  2. Can you please check my post Create method if it is as it should be

    Modify your code like below, otherwise you will always store the second supply in supplyIds:

     [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(Product model, List<int> supplyIds)
    {
        _context.Product.Add(model);
        _context.SaveChanges();
    
        SupplyProduct SP = new();
        foreach (var supplyId in supplyIds)
        {
            SP.SupplyId = supplyId;
            SP.ProductId = model.ProductId;
            SP.Product = model;
            SP.Supply = _context.Supply.Where(x => x.SupplyId == supplyId).FirstOrDefault();
            _context.SupplyProducts.Add(SP);   //move to here...
            _context.SaveChanges();
        }
        // _context.SupplyProducts.Add(SP);
        //_context.SaveChanges();
        return RedirectToAction(nameof(Index));
    }
    

    how can I get the Products data while returning the Supplies in the Index method into the index view?

    Change your Index method like below:

    // GET: Products
    public async Task<IActionResult> Index()
    {
        var data = await _context.Product.Include(p => p.SupplyProducts)
                                 .ThenInclude(sp => sp.Supply).ToListAsync();
        return View(data);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search