3

I have Two different ASP.net Core 6.0 applications running that have tables linked to other tables by foreign keys. I create a CRUD for both pages. At the first CRUD (PriceList) page, I will enter the data. At the the second CRUD (CombineStage) of the page I will get the data (Stage) from the first page (Pricelist) using multiple select and the search box and its corresponding price in the Index page after using multiple select. I can't find any code commands to make this work. Any help would be appreciated. My foreign key is PricelistId. Below is my code:

CombineStage.cs

using System.ComponentModel.DataAnnotations;

namespace WebApp.Models
{
public class CombineStage
{
    [Key]
    public int StageId { get; set; }
    [Required(ErrorMessage = "Bạn chưa nhập tên công đoạn")]
    public string Name { get; set; }
    [Required(ErrorMessage = "Bạn chưa chọn công đoạn")]
    public int PricelistId { get; set; }
    [Required(ErrorMessage = "Bạn chưa chọn ảnh")]
    public string Picture { get; set; }
    [Required(ErrorMessage = "Bạn chưa nhập giá tiền")]
    public int Price { get; set; }
    public virtual PriceList PriceList { get; set; }
}
}

CombineStagesController

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using WebApp.Models;

namespace WebApp.Areas.Admin.Controllers
{
[Area("Admin")]
public class CombineStagesController : Controller
{
    private readonly ManageContext _context;

    public CombineStagesController(ManageContext context)
    {
        _context = context;
    }

    // GET: Admin/CombineStages
    public async Task<IActionResult> Index()
    {
        var manageContext = _context.CombineStage.Include(c => c.PriceList);
        return View(await manageContext.ToListAsync());
    }

    // GET: Admin/CombineStages/Details/5
    public async Task<IActionResult> Details(int? id)
    {
        if (id == null || _context.CombineStage == null)
        {
            return NotFound();
        }

        var combineStage = await _context.CombineStage
            .Include(c => c.PriceList)
            .FirstOrDefaultAsync(m => m.StageId == id);
        if (combineStage == null)
        {
            return NotFound();
        }

        return View(combineStage);
    }

    // GET: Admin/CombineStages/Create
    public IActionResult Create()
    {
        ViewData["PricelistId"] = new SelectList(_context.PriceLists, "PricelistId", "Stage");
        return View();
    }

    // POST: Admin/CombineStages/Create
    // To protect from overposting attacks, enable the specific properties you want to bind to.
    // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("StageId,Name,PricelistId,Picture,Price")] CombineStage combineStage)
    {
        if (ModelState.IsValid)
        {
            _context.Add(combineStage);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        ViewData["PricelistId"] = new SelectList(_context.PriceLists, "PricelistId", "Stage", combineStage.PricelistId);
        return View(combineStage);
    }

    // GET: Admin/CombineStages/Edit/5
    public async Task<IActionResult> Edit(int? id)
    {
        if (id == null || _context.CombineStage == null)
        {
            return NotFound();
        }

        var combineStage = await _context.CombineStage.FindAsync(id);
        if (combineStage == null)
        {
            return NotFound();
        }
        ViewData["PricelistId"] = new SelectList(_context.PriceLists, "PricelistId", "Stage", combineStage.PricelistId);
        return View(combineStage);
    }

    // POST: Admin/CombineStages/Edit/5
    // To protect from overposting attacks, enable the specific properties you want to bind to.
    // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, [Bind("StageId,Name,PricelistId,Picture,Price")] CombineStage combineStage)
    {
        if (id != combineStage.StageId)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            try
            {
                _context.Update(combineStage);
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CombineStageExists(combineStage.StageId))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
            return RedirectToAction(nameof(Index));
        }
        ViewData["PricelistId"] = new SelectList(_context.PriceLists, "PricelistId", "Stage", combineStage.PricelistId);
        return View(combineStage);
    }

    // GET: Admin/CombineStages/Delete/5
    public async Task<IActionResult> Delete(int? id)
    {
        if (id == null || _context.CombineStage == null)
        {
            return NotFound();
        }

        var combineStage = await _context.CombineStage
            .Include(c => c.PriceList)
            .FirstOrDefaultAsync(m => m.StageId == id);
        if (combineStage == null)
        {
            return NotFound();
        }

        return View(combineStage);
    }

    // POST: Admin/CombineStages/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteConfirmed(int id)
    {
        if (_context.CombineStage == null)
        {
            return Problem("Entity set 'ManageContext.CombineStage'  is null.");
        }
        var combineStage = await _context.CombineStage.FindAsync(id);
        if (combineStage != null)
        {
            _context.CombineStage.Remove(combineStage);
        }
        
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }

    private bool CombineStageExists(int id)
    {
      return _context.CombineStage.Any(e => e.StageId == id);
    }
}
}

Create

@model WebApp.Models.CombineStage

@{
ViewData["Title"] = "Create";
Layout = "~/Areas/Admin/Views/Shared/_AdminLayout.cshtml";
}

<h1>Create</h1>

<h4>CombineStage</h4>
<hr />
<div class="row">
<div class="col-md-4">
    <form asp-action="Create">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input asp-for="Name" class="form-control" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="PricelistId" class="control-label"></label>
            <select asp-for="PricelistId" class ="form-control" asp-items="ViewBag.PricelistId" multiple>
            </select>
        </div>
        <div class="form-group">
            <label asp-for="Picture" class="control-label"></label>
            <input asp-for="Picture" class="form-control" />
            <span asp-validation-for="Picture" class="text-danger"></span>
        </div>
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>
</div>
Thank you so much!

Update Pricelist:

Pricelist.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Drawing;

namespace WebApp.Models
{
public partial class PriceList
{
    public PriceList()
    {
        StageDetails = new HashSet<StageDetail>();
        CombineStages = new HashSet<CombineStage>();
    }
    [Key]
    public int PricelistId { get; set; }
    [Required(ErrorMessage = "Bạn chưa chọn ảnh")]
    public string Image { get; set; }
    [Required (ErrorMessage = "Bạn chưa chọn máy may")]
    public Machine Machine { get; set; }
    [Required (ErrorMessage = "Bạn chưa tên nhập công đoạn")]
    public string Stage { get; set; }
    [Required (ErrorMessage = "Bạn chưa nhập giá tiền")]
    public int Price { get; set; }
    public virtual ICollection<StageDetail> StageDetails { get; set; }
    public virtual ICollection<CombineStage> CombineStages { get; set; }
}
public enum Machine
{
    VS,
    [Display(Name = "1K")]
    OneK
}

}

PriceListsController

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using WebApp.Models;
using WebApp.ViewModel;

namespace WebApp.Areas.Admin.Controllers
{
[Area("Admin")]
public class PriceListsController : Controller
{
    private readonly ManageContext _context;
    private readonly IWebHostEnvironment _environment;
    public PriceListsController(ManageContext context, IWebHostEnvironment environment)
    {
        _context = context;
        _environment = environment;
    }

    public async Task<IActionResult> Index()
    {
        return View(await _context.PriceLists.ToListAsync());
    }

    public async Task<IActionResult> Details(int? id)
    {
        try
        {
            if (id == null)
            {
                return NotFound();
            }

            var priceList = await _context.PriceLists
                .FirstOrDefaultAsync(m => m.PricelistId == id);

            var priceListModelView = new PriceListViewModel()
            {
                Id = priceList.PricelistId,
                ExistingImage = priceList.Image,
                Machine = priceList.Machine,
                Stage = priceList.Stage,
                Price = priceList.Price
            };

            if (priceList == null)
            {
                return NotFound();
            }
            return View(priceList);
        }
        catch (Exception)
        {
            throw;
        }
    }

    public IActionResult Create()
    {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(PriceListViewModel model)
    {
        try
        {
            if (ModelState.IsValid)
            {
                string uniqueFileName = ProcessUploadedFile(model);
                PriceList priceList = new()
                {
                    Image = uniqueFileName,
                    Machine = model.Machine,
                    Stage = model.Stage,
                    Price = model.Price

                };

                _context.Add(priceList);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
        }
        catch (Exception)
        {
            throw;
        }
        
        return View(model);
    }

    public async Task<IActionResult> Edit(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        var priceList = await _context.PriceLists.FindAsync(id);
        var priceListViewModel = new PriceListViewModel()
        {
            Id = priceList.PricelistId,
            ExistingImage = priceList.Image,
            Machine = priceList.Machine,
            Stage = priceList.Stage,
            Price = priceList.Price
        };

        if (priceList == null)
        {
            return NotFound();
        }
        return View(priceListViewModel);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, PriceListViewModel model)
    {
        if (ModelState.IsValid)
        {
            var priceList = await _context.PriceLists.FindAsync(model.Id);
            priceList.Machine = model.Machine;
            priceList.Stage = model.Stage;
            priceList.Price = model.Price;

            if (model.PricelistImage != null)
            {
                if (model.ExistingImage != null)
                {
                    string filePath = Path.Combine(_environment.WebRootPath, "Images", model.ExistingImage);
                    System.IO.File.Delete(filePath);
                }

                priceList.Image = ProcessUploadedFile(model);
            }

            _context.Update(priceList);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View();
    }

    public async Task<IActionResult> Delete(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        var priceList = await _context.PriceLists
            .FirstOrDefaultAsync(m => m.PricelistId == id);

        var priceListViewModel = new PriceListViewModel()
        {
            Id = priceList.PricelistId,
            ExistingImage = priceList.Image,
            Machine = priceList.Machine,
            Stage = priceList.Stage,
            Price = priceList.Price
        };

        if (priceList == null)
        {
            return NotFound();
        }

        return View(priceListViewModel);
    }

    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteConfirmed(int id)
    {
        var priceList = await _context.PriceLists.FindAsync(id);
        //string deleteFileFromFolder = "wwwroot\\Uploads\\";
        string deleteFileFromFolder = Path.Combine(_environment.WebRootPath, "Images");
        var CurrentImage = Path.Combine(Directory.GetCurrentDirectory(), deleteFileFromFolder, priceList.Image);
        _context.PriceLists.Remove(priceList);
        if (System.IO.File.Exists(CurrentImage))
        {
            System.IO.File.Delete(CurrentImage);
        }
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }

    private bool SpeakerExists(int id)
    {
        return _context.PriceLists.Any(e => e.PricelistId == id);
    }

    private string ProcessUploadedFile(PriceListViewModel model)
    {
        string uniqueFileName = null;
        string path = Path.Combine(_environment.WebRootPath, "Images");
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        if (model.PricelistImage != null)
        {
            string uploadsFolder = Path.Combine(_environment.WebRootPath, "Images");
            uniqueFileName = Guid.NewGuid().ToString() + "_" + model.PricelistImage.FileName;
            string filePath = Path.Combine(uploadsFolder, uniqueFileName);
            using (var fileStream = new FileStream(filePath, FileMode.Create))
            {
                model.PricelistImage.CopyTo(fileStream);
            }
        }

        return uniqueFileName;
    }
}
}

Update Create(HTTPPost) CombineStagesController: (But it still hasn't solved my request. I want when I select multiple then I get the entire corresponding Price value in Index Page)

public IActionResult Create()
    {
        ViewData["PricelistId"] = new SelectList(_context.PriceLists, "PricelistId", "Stage");
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("StageId,Name,PricelistId,Picture,Price")] CombineStage combineStage, int[] PricelistId)
    {
        foreach (var id in PricelistId)
        {
            var stage = _context.PriceLists.Where(m => m.PricelistId == id).Select(x => x.Stage).ToString();

        }
        if (ModelState.IsValid)
        {
            _context.Add(combineStage);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(combineStage);
    }

Update Things I'm looking forward to

enter image description here

Next I will choose 2 option stages that I created

enter image description here

Next step, I want the total price of the 2 process options I have selected here

enter image description here

Finally, I want to show all the stages and prices of my 2 options that I have selected

enter image description here

That's all my request.

  • Welcome to Stack Overflow. Please take the [tour] to learn how Stack Overflow works and read [ask] on how to improve the quality of your question. Then [edit] your question to include your source code as a working [mcve], which can be compiled and tested by others. – Progman Sep 04 '22 at 17:00
  • Can you help me this function? – Lâm Trương Sep 06 '22 at 12:13
  • I have updated my question again and hope to get some help. – Lâm Trương Sep 12 '22 at 15:09
  • I have shared the code from Index page for you – Lâm Trương Sep 12 '22 at 15:56
  • @Dimitris Maragkos Are you still interested in my question? I see you deleted all of my comments on this question. I really need your help to solve this problem. Reply me if you need more information on the question. Thank you very much! – Lâm Trương Sep 13 '22 at 10:53
  • I need some help for my problem. Can someone help me? – Lâm Trương Sep 13 '22 at 15:31
  • 1
    Please paste your code directly, don't use pictures. @Lâm Trương – Chen Sep 22 '22 at 05:41
  • 1
    @JamesRisner wait for me, just a little bit. I will replace them with my own code – Lâm Trương Sep 25 '22 at 12:01
  • I've been stuck with this error for quite some time. I will be happy to solve it – Lâm Trương Sep 25 '22 at 12:33
  • Do you currently have any errors? Whether the model validation can pass? – Chen Sep 26 '22 at 09:59
  • @Chen I don't know how to display all the Price corresponding to the Stage that I use multiple select. That's my main problem right now. Your code is so good but I think still not enough to solve my problem. – Lâm Trương Sep 26 '22 at 11:57
  • What is your expected result? If you choose two options, add two records with their respective prices? – Chen Sep 27 '22 at 06:37
  • @Chen Yes, that's the result I expected. I want to show in index page their total price. In the details page is the corresponding price of the stages I have selected – Lâm Trương Sep 27 '22 at 08:01
  • @Chen It's too complicated for a newbie like me. Hope you can help me so I can learn more – Lâm Trương Sep 27 '22 at 08:02

2 Answers2

2

It's not entirely clear what you're expected result is with regard to records and their respective prices, but the binding code in your Create(CombinedStage, int[]) appears problematic given the PricelistId binding to CombinedStage. I would suggest creating a view model that reflects the form elements with an array/collection of simple values for PriceListIds in order for <select multiple>. For example, the new CombinedStageViewModel posted to the Create should have a property for `PricelistIds' such as the following for :

public IEnumerable<int> PricelistIds { get; set; }

Again, it's not entirely clear from the provided sample code or the accompanying description of the problem what the desired behavior is with respect to getting "...the entire corresponding Price value in Index Page." If you can post a sample project and define the expected results, it would make it much easier to provide a comprehensive answer to your question.

2

I made a simple test, you can refer to it.

I added a field to CombineStage to store your options:

public class CombineStage
    {
        [Key]
        [ForeignKey("StageId")]
        public int StageId { get; set; }
        [Required(ErrorMessage = "Bạn chưa nhập tên công đoạn")]
        public string Name { get; set; }
        [Required(ErrorMessage = "Bạn chưa chọn công đoạn")]
        [ForeignKey("PricelistId")]
        public int PricelistId { get; set; }
        [Required(ErrorMessage = "Bạn chưa chọn ảnh")]
        public string Picture { get; set; }
        [Required(ErrorMessage = "Bạn chưa nhập giá tiền")]
        public int Price { get; set; }
        public string PricelistIdList { get; set; }
        public virtual PriceList PriceList { get; set; }
    }

CombineStagesController:

public class CombineStagesController : Controller
    {
        private readonly ManageContext _context;

        public CombineStagesController(ManageContext context)
        {
            _context = context;
        }

        // GET: Admin/CombineStages
        public async Task<IActionResult> Index()
        { 
            var manageContext = _context.CombineStage.Include(c => c.PriceList);
            return View(await manageContext.ToListAsync());
        }

        // GET: Admin/CombineStages/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null || _context.CombineStage == null)
            {
                return NotFound();
            }

            var combineStage = await _context.CombineStage
                .Include(c => c.PriceList)
                .FirstOrDefaultAsync(m => m.StageId == id);
            int[] PriceIdList = combineStage.PricelistIdList.Split(',').Select(n => Convert.ToInt32(n)).ToArray();
            List<PriceList> priceLists = new List<PriceList>();
            foreach(var PriceId in PriceIdList)
            {
                var PriceDetails = _context.PriceLists.Where(c => c.PricelistId == PriceId).FirstOrDefault();
                priceLists.Add(PriceDetails);
            }
            ViewBag.priceLists = priceLists;
            if (combineStage == null)
            {
                return NotFound();
            }

            return View(combineStage);
        }

        // GET: Admin/CombineStages/Create
        public IActionResult Create()
        {
            
            var priceLists = _context.PriceLists.ToList();
            List<SelectListItem> mylist = new List<SelectListItem>();
            foreach (var price in priceLists)
            {
                mylist.Add(new SelectListItem { Text = price.Stage, Value = price.PricelistId.ToString() });

            }
            ViewBag.PricelistId = mylist;
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("Name,PricelistId,Picture,Price,PriceList")] CombineStage combineStage, int[] PricelistId)
        {
            int price = 0;
            var stage = "";
            PriceList  priceList = new PriceList();

            foreach (var id in PricelistId)
            {
                stage = _context.PriceLists.Where(m => m.PricelistId == id).FirstOrDefault().Stage.ToString();
                price += _context.PriceLists.Where(m => m.PricelistId == id).FirstOrDefault().Price;
                priceList = _context.PriceLists.Where(m => m.PricelistId == id).FirstOrDefault();

            }
            combineStage.Price = price;
            combineStage.PriceList = priceList;
            combineStage.PricelistIdList = string.Join(",", PricelistId);
            ModelState.Clear();
            if (TryValidateModel(combineStage))
            {
                _context.Add(combineStage);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(combineStage);
        }
}

Create.cshtml:

@model _2022092602.Models.CombineStage

@{
ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>CombineStage</h4>
<hr />
<div class="row">
<div class="col-md-4">
    <form asp-action="Create">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Name" class="control-label"></label>
            <input asp-for="Name" class="form-control" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="PricelistId" class="control-label"></label>
            <select asp-for="PricelistId" class ="form-control" asp-items="@ViewBag.PricelistId" multiple>
                
            </select>
        </div>
        <div class="form-group">
            <label asp-for="Picture" class="control-label"></label>
            <input asp-for="Picture" class="form-control" />
            <span asp-validation-for="Picture" class="text-danger"></span>
        </div>
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>
</div>

Details.cshtml:

@model _2022092602.Models.CombineStage

<div>@Model.Name</div>
<div>@Model.Picture</div>
<div>@Model.Price</div>

<div>
    @foreach (var price in ViewBag.priceLists)
    {
        <div>
            <span>@price.PricelistId</span>
            <span>@price.Price</span>
            <span>@price.Stage</span>
        </div>

    }
</div>

Test Result: enter image description here enter image description here

Chen
  • 4,499
  • 1
  • 2
  • 9
  • OMG! That's all I needed for quite a while. I wish you all the best! – Lâm Trương Sep 27 '22 at 10:15
  • Can I ask you to finish uploading the file and the rest of Edit, and Delete? I will review your complete work for reference to learn more. This is my excessive request but please help me. Thank you so much! – Lâm Trương Sep 27 '22 at 12:03
  • You can make a separate post for this issue, just to avoid confusion. @Lâm Trương – Chen Sep 28 '22 at 01:01
  • I will create a new question for this problem. It's here https://stackoverflow.com/questions/73877029/image-upload-function-in-crud – Lâm Trương Sep 28 '22 at 06:25