none
Use Different CRUD Submit Button in Same View in ASP.NET Core with Entity Framework Core RRS feed

  • Question

  • Hello.
    I manage the read, update and delete process from a database through Entity Framework Core via three different buttons in a Razor page structure on ASP.NET Core.

    I'm sending a class to a .cshtml page via the ASP.NET Core controller; this class contains a database list and a database list item. This way I can show the entire database list if one row is under a database list item.

    I don't have any problems with the "delete" button from these three different buttons that I placed in this .cshtml because I can delete the selected data from the database by sending a getID via this button.
    Similarly, when I use the "delete" and "read" or "delete" and "update" buttons in this .cshtml, I still have no problems.

    My problem is that when "read", "update" and "delete" are simultaneous, I cannot determine the different triggering from the buttons separately into the same [HttpPost] View connected to the Controller.

    What I want to do is very simple:

    If the "read" button is pressed, the item belonging to the "id" value should be shown in a single line in .cshtml according to the entered database "id" value.

    If the "update" button is pressed, changes should be made in the single line item in .cshtml according to the entered database "id" value.

    If the "delete" button is pressed, the database item of the entered database "id" value must be deleted.

    All of these buttons are in a single .cshtml and all return a single "post" value, but there are three different options that I cannot understand on the Controller which button is pressed.

    Sample Code Structure:

    //Here is my sending class. "SendingClass" will be sent to Index.cshtml via HomeController
    
        public class SendingClass
        {
            public IEnumerable<ProductDB> GetDB { get; set; }
            public int GetID { get; set; }
            public ProductDB OneRow { get; set; }
        }
    
    //Here is my HomeController
    
            public class HomeController : Controller
            {
                private IProductRepository repository;
                public HomeController(IProductRepository repo)
                {
                    repository = repo;
                }
    
                public IActionResult DataDel(int id)
                {
                    repository.DeleteDB(id);
                    var send = new SendingClass
                    {
                        GetDB = repository.MyDB,
                        GetID = repository.MyDB.First().ID,
                        OneRow = repository.GetByID(repository.MyDB.First().ID)
                    };
                    return RedirectToAction("Index");
                }
    
                [HttpGet]
                public IActionResult Index()
                {
                    var send = new SendingClass
                    {
                        GetDB = repository.MyDB,
                        GetID = repository.MyDB.First().ID,
                        OneRow = repository.GetByID(repository.MyDB.First().ID)
                    };
                    return View(send);
                }
    
                [HttpPost]
                public IActionResult Index(SendingClass item)
                {
                    item.OneRow.ID = item.GetID;
                    if (item.OneRow == null)
                    {
    
                    }
                    else
                    {
                        repository.UpdateDB(item.OneRow);
                    }
                    var send = new SendingClass
                    {
                        GetDB = repository.MyDB,
                        GetID = item.GetID,
                        OneRow = repository.GetByID(item.GetID)
                    };
                    return View(send);
                }
            }
    
    //UpdateDB: My Ef.Core Database Update Method
    //DeleteDB: My Ef.Core Database Delete Method
    // repository.MyDB: My database which called in Ef.Core

    My View.cshtml:

    @model SendingClass
    @{
    
    }
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body class="align-items-center">
        <form asp-action="Index" asp-controller="Home" method="post">
            <label>Data Row Number</label>
            <p></p>
            <input type="text" asp-for="@Model.GetID" id="@Model.GetID" />
            <p></p>
            <input type="submit" value="READ" />
            <p></p>
            <input type="submit" value="UPDATE" />
            <p></p>
            <input type="submit" asp-action="DataDel" asp-route-id="@Model.GetID" id="@Model.GetID" value="DELETE" />
            <p></p>
            <table>
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Name</th>
                        <th>Customer Number</th>
                        <th>Price (Old)</th>
                        <th>Price (New)</th>
                        <th>Checkout</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td asp-for="@Model.OneRow.ID">@Html.DisplayFor(m => Model.OneRow.ID)</td>
                        <td asp-for="@Model.OneRow.Name">@Html.TextBoxFor(m => Model.OneRow.Name)</td>
                        <td asp-for="@Model.OneRow.CustomerNo">@Html.TextBoxFor(m => Model.OneRow.CustomerNo)</td>
                        <td asp-for="@Model.OneRow.PriceOld">@Html.TextBoxFor(m => Model.OneRow.PriceOld)</td>
                        <td asp-for="@Model.OneRow.PriceNew">@Html.TextBoxFor(m => Model.OneRow.PriceNew)</td>
                        <td asp-for="@Model.OneRow.Checkout">@Html.TextBoxFor(m => Model.OneRow.Checkout)</td>
                    </tr>
                </tbody>
            </table>
        </form>
        <p></p>
        <table border="1">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>NAME</th>
                    <th>NO</th>
                    <th>Price (Old)</th>
                    <th>Price (New)</th>
                    <th>Checkout</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var item in Model.GetDB)
                {
                    <tr>
                        <td>@Html.DisplayFor(m => item.ID)</td>
                        <td>@Html.DisplayFor(m => item.Name)</td>
                        <td>@Html.DisplayFor(m => item.CustomerNo)</td>
                        <td>@Html.DisplayFor(m => item.PriceOld)</td>
                        <td>@Html.DisplayFor(m => item.PriceNew)</td>
                        <td>@Html.DisplayFor(m => item.Checkout)</td>
                    </tr>
                }
            </tbody>
        </table>
        <p></p>
    </body>
    </html>


    • Moved by CoolDadTx Monday, December 23, 2019 3:11 PM ASP.NET related
    Saturday, December 21, 2019 8:41 PM

All replies

  • You can use the 'name' attribute on the 'input' statement to determine what button is pushed.

    @model  PayRollVM.Payroll
    
    <!DOCTYPE html>
    
    <style type="text/css">
        .editor-field > label {
            float: left;
            width: 150px;
        }
    
        .txtbox {
            font-family: Arial, Helvetica, sans-serif;
            font-size: 12px;
            background: white;
            color: black;
            cursor: text;
            border-bottom: 1px solid #104A7B;
            border-right: 1px solid #104A7B;
            border-left: 1px solid #104A7B;
            border-top: 1px solid #104A7B;
            padding-top: 10px;
        }
    </style>
    <html>
    <head>
        <title>Edit</title>
    </head>
    
    <body>
        <h1>Author Payroll</h1>
    
        @using (Html.BeginForm())
        {
    
            @Html.ValidationSummary(false, "", new { @class = "text-danger" })
    
    <fieldset>
    
        <legend>Edit</legend>
    
        @Html.HiddenFor(model => model.PayrollId)
        @Html.HiddenFor(model => model.AuthorId)
    
        <div class="form-group">
            <div class="editor-field">
                @Html.Label("First Name:")
                @Html.DisplayTextFor(model => model.AuthorFirstName)
            </div>
        </div>
        
        <div class="form-group">
            <div class="editor-field">
                @Html.Label("Last Name:")
                @Html.DisplayTextFor(model => model.AuthorLastName)
            </div>
        </div>
      
        <div class="editor-field">
            @Html.Label("Salary:")
            @Html.TextBoxFor(model => model.Salary, new { @Cssclass = "txtbox" })
            @Html.ValidationMessageFor(model => model.Salary, "", new { @class = "text-danger" })
        </div>
        <br />
        <p>
            <input type="submit" name="submit" value="Save" />
            <input type="submit" name="submit" value="Cancel" />
        </p>
    
    </fieldset>
        }
    
    </body>
    </html>


    Then in the controller you can interrogate want submit button was pressed.

     public ActionResult Edit(int id = 0)
            {
                return id == 0 ? null : View(pdm.Update(id));
            }
    
            [HttpPost]
            public ActionResult Edit(PayRollVM.Payroll payroll, string submit)
            {
                if (submit == "Cancel") return RedirectToAction("Index");
    
                if (!ModelState.IsValid) return View(payroll);
    
                pdm.Update(payroll);
                return RedirectToAction("Index");
            }

    However, the repository pattern is not a data persistence pattern.

    https://martinfowler.com/eaaCatalog/repository.html

    https://programmingwithmosh.com/net/common-mistakes-with-the-repository-pattern/

    https://www.thereformedprogrammer.net/is-the-repository-pattern-useful-with-entity-framework-core/

    And besides, EF already uses the repository pattern, and repositroy over repository is not  optional.

    One also avoids the generic repository, becuase it's too generic and not flexible to change.

    A normal repository object uses the DAO. You can use the DAO by itself in a Data Access Layer (DAL) without the generic repository being involved.

    https://blog.sapiensworks.com/post/2012/11/01/Repository-vs-DAO.aspx

    https://en.wikipedia.org/wiki/Data_access_object

    https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm

    Here is an example of the DAO being used in  the DAL.

    using Entities;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace DAL
    {
        public interface IDaoPayroll
        {
            Task<List<DtoPayroll>> GetAll();
            Task<DtoPayroll> Find(int id);
            Task<DtoPayroll> FindPayRollByAuthorId(int id);
            Task Add(DtoPayroll dto);
            Task Update(DtoPayroll dto);
            Task Delete(int id);
        }
    }
    
    =======================================================
    using DAL.Models;
    using System;
    using System.Threading.Tasks;
    using Entities;
    using System.Collections.Generic;
    using Microsoft.EntityFrameworkCore;
    using System.Data.SqlClient;
    using System.Linq;
    
    namespace DAL
    {
        public class DaoPayroll :IDaoPayroll
        {
            private PublishingCompanyContext pc;
            private IDaoAuthor _daoauthor;
    
            public DaoPayroll(PublishingCompanyContext dbcontext, IDaoAuthor daoAuthor)
            {
                pc = dbcontext;
                _daoauthor = daoAuthor;
            }
    
            public async Task<List<DtoPayroll>> GetAll()
            {
                var dtos = new List<DtoPayroll>();
    
                var payrolls = await pc.Payroll.ToListAsync();
    
                foreach (var payroll in payrolls)
                {
                    var dtoauthor = await _daoauthor.Find(payroll.AuthorId); 
    
                    var dto = new DtoPayroll
                    {
                        PayrollId = payroll.PayrollId,
                        AuthorId = payroll.AuthorId,
                        AuthorFirstName = dtoauthor.FirstName,
                        AuthorLastName = dtoauthor.LastName,
                        Salary = payroll.Salary
                    };
    
                    dtos.Add(dto);
                }
    
                return dtos;
            }
    
            public async Task<DtoPayroll> Find(int id)
            {
                var dto = new DtoPayroll();
    
                var payroll = await pc.Payroll.FindAsync(id);
    
                if (payroll != null)
                { 
                    var dtoauthor = await _daoauthor.Find(payroll.AuthorId);
    
                    if (dtoauthor != null)
                    {
                        dto.PayrollId = payroll.PayrollId;
                        dto.AuthorId = payroll.AuthorId;
                        dto.AuthorFirstName = dtoauthor.FirstName;
                        dto.AuthorLastName = dtoauthor.LastName;
                        dto.Salary = payroll.Salary;
                    }
                    else
                    {
                        throw new Exception($"Author with ID = {id} was not found.");
                    }
                }
                else
                {
                    throw new Exception($"Payroll with ID = {id} was not found.");
                }
    
                return dto;
    
            }
    
            public async Task<DtoPayroll> FindPayRollByAuthorId(int id)
            {
                var dto = new DtoPayroll();
                
                var payroll = await pc.Payroll.Where(a =>a.AuthorId == id).SingleOrDefaultAsync();
    
                if (payroll != null)
                {
                    dto.PayrollId = payroll.PayrollId;
                }
    
                return dto;
            }
    
            public async Task Add(DtoPayroll dto)
            {
                var payroll = new Payroll
                {
                    AuthorId = dto.AuthorId,
                    Salary = dto.Salary
                };
    
                pc.Payroll.Add(payroll);
                await pc.SaveChangesAsync();
    
            }
    
            public async Task Update(DtoPayroll dto)
            {
                var payroll = new Payroll
                {
                    PayrollId = dto.PayrollId,
                    AuthorId = dto.AuthorId,
                    Salary = dto.Salary
                };
    
                pc.Entry(payroll).State = EntityState.Modified;
                await pc.SaveChangesAsync();
    
            }
    
            public async Task Delete(int id)
            {
                var payroll =  pc.Payroll.Find(id);
    
                if (payroll != null)
                {
                    pc.Payroll.Remove(payroll);
                    await pc.SaveChangesAsync();
                }
            }
    
        }
    }
    
    

    The small part of the controller that was shown, there is no direct call to the database from the controller or a direct call to a DAO, the calls are made from the Models folder. Objects from the Models folder are injected into the controller.

    https://www.c-sharpcorner.com/UploadFile/56fb14/understanding-separation-of-concern-and-Asp-Net-mvc/

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/overview/understanding-models-views-and-controllers-cs

    <copied>

    An MVC model contains all of your application logic that is not contained in a view or a controller. The model should contain all of your application business logic, validation logic, and database access logic. For example, if you are using the Microsoft Entity Framework to access your database, then you would create your Entity Framework classes (your .edmx file) in the Models folder.

    A view should contain only logic related to generating the user interface. A controller should only contain the bare minimum of logic required to return the right view or redirect the user to another action (flow control). Everything else should be contained in the model.

    In general, you should strive for fat models and skinny controllers. Your controller methods should contain only a few lines of code. If a controller action gets too fat, then you should consider moving the logic out to a new class in the Models folder.

    <end>

    Finally ASP.NET Core and EF Core have forms in ASP.NET forums.

    http://forums.asp.net/

     

    Saturday, December 21, 2019 10:37 PM
  • This forum is for C#-specific questions only. Please post questions related to ASP.NET in the ASP.NET forums.

    Michael Taylor http://www.michaeltaylorp3.net

    Monday, December 23, 2019 3:11 PM