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 :D
CodePudding user response:
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);
}
CodePudding user response:
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();
}