Кодирование ASP.NET MVC с базой данных SQL Server с составными ключами и функцией каскадного обновления

Я использую EF 6 с подходом, ориентированным на базу данных, для моего проекта ASP.NET MVC, поскольку мне удобнее работать с SQL, чем с кодированием на C# и LINQ (используя SQL Server 2008, Visual Studio 2015).

У меня есть 4 таблицы в SQL Server для:

Link, Employee, MapLinkEmp, Location 

viz, link_sd1, emp_sd1, MapEmpLink_sd1, loc_sd1 respectively

Таблица Link имеет отношения "многие ко многим" с таблицей Emp, для которой я создал другую таблицу, ссылающуюся на составные первичные ключи обеих таблиц.

Чтобы реализовать обратимое удаление, я исследовал и в конечном итоге следовал подходу, упомянутому в Структура сущностей переопределяет сохранение изменений в объектах обратимого удаления, что предлагает составные ключи, для которых я ссылался на как сопоставить составной ключ в функциях CRUD

В конце базы данных моего проекта: я реализовал каскадную функцию с использованием составных ключей в SQL Server. Но в конце приложения: я не могу включить CRUD + другие функции (включая обратимое удаление, группировку данных Emp & Link по местоположению, Emp с их соответствующими location может обновлять только свои данные emp и данные ссылок и т. д.), когда в моих объектах есть составные ключи.

Диаграмма базы данных ниже:

Код SQL Server для каскадирования:

ALTER TABLE emplinkloc_sd1
ADD emid int

ALTER TABLE emplinkloc_sd1
ADD lmid int

ALTER TABLE emplinkloc_sd1
ADD isdl bit DEFAULT 0 NOT NULL

ALTER TABLE emplinkloc_sd1
ADD isde bit DEFAULT 0 NOT NULL

ALTER TABLE emplinkloc_sd1
ADD PRIMARY KEY (melid)

ALTER TABLE emplinkloc_sd1
ADD CONSTRAINT FK_ell_e_sd1 
    FOREIGN KEY (emid, isde) REFERENCES emp_sd1(eid, isdeleted) 
            ON UPDATE CASCADE;

ALTER TABLE emplinkloc_sd1
ADD CONSTRAINT FK_ell_l_sd1 
    FOREIGN KEY (lmid, isdl) REFERENCES link_sd1(lid, isdeleted) 
            ON UPDATE CASCADE;

Я нашел много методов, таких как ISoftDelete, Interceptor и т. д., но я думаю, что такие концепции используются либо в подходах, основанных на коде, либо в EF Core и т. д. Кроме того, они требуют большого объема программирования, превышающего мой текущий уровень понимания.

Больше всего я сделал в конце базы данных (как предложено в Структура объектов переопределяет сохранение изменений в объектах с обратимым удалением), как мне включить функции на стороне приложения в контроллер и представления ASP.NET MVC с такой схемой базы данных (имеющей составные первичные и внешние ключи) используя подход EF, ориентированный на базу данных?

Заранее спасибо!


person Xplorer    schedule 23.05.2020    source источник


Ответы (1)


Я объясняю технику — Первый подход к базе данных с операцией CRUD с использованием хранимой процедуры с EF6, которая лучше всего сработала для меня после множества экспериментов. Весь процесс включает в себя шаги в конце базы данных, а затем в конце приложения, как описано ниже для объекта — Сотрудник (emp_Oct1 в моем случае, с eid и isdeletede в качестве составных ключей. ):

КОНЕЦ БАЗЫ ДАННЫХ

Шаг 1. Я разработал схему, как показано ниже (с составными ключами): < img src="https://i.stack.imgur.com/86ffb.jpg" alt="Схема базы данных" />

Шаг 2. Я создал хранимые процедуры в SQL Server для создания, обновления и обратимого удаления для моего объекта emp_Oct1, как показано ниже:

 ---- For SOFT DELETION -----
CREATE PROCEDURE [dbo].[sp_deleteempt1_Oc1]
    -- Add the parameters for the stored procedure here
    @eid int
    AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    UPDATE emp_Oct1 SET isdeletede='1' WHERE eid=@eid 
END

----- For CREATE & UPDATE -----
CREATE PROCEDURE sp_AddEditEmp_Oct1
    -- Add the parameters for the stored procedure here
    @eid int=0, --Named Parameter setting initial value with the parameter
    @name varchar(100),
    @cpf varchar(50),
    @Designation varchar(50),
    @Contact bigint,
    @email varchar(255),
    @emplocid int,
    @Pwd varchar(100),
    @Remarks varchar(200),
    @isdeletede bit,
    @elast_mod_dt datetime2,
    @elast_mod_by varchar(255) 
    AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    IF(@eid>0)
        BEGIN
        SET NOCOUNT ON;
        UPDATE emp_Oct1 SET 
        name=@name,cpf=@cpf,Designation=@Designation,Contact=@Contact,email=@email, emplocid=@emplocid,
        Pwd=@Pwd ,Remarks=@Remarks,isdeletede=@isdeletede,elast_mod_dt=CURRENT_TIMESTAMP,elast_mod_by=@elast_mod_by
        WHERE eid=@eid 
        END
    ELSE
        BEGIN
        INSERT INTO emp_Oct1(name,cpf,Designation,Contact,email,emplocid,Pwd,Remarks,isdeletede,elast_mod_dt,elast_mod_by) 
        VALUES(@name,@cpf,@Designation,@Contact,@email,@emplocid,@Pwd,@Remarks,@isdeletede,CURRENT_TIMESTAMP,@elast_mod_by)
        SELECT @eid = SCOPE_IDENTITY()
        END
    SELECT @eid as eid
END
GO

ЗАВЕРШЕНИЕ ПРИЛОЖЕНИЯ

Шаг 1. Создайте приложение MVC, добавьте модель данных объекта, как описано здесь

Шаг 2. Я реализовал свой CRUD с помощью хранимых процедур с основной идеей из этого источникаОперации CRUD с использованием хранимой процедуры в Entity Framework.

Шаг 3. Код контроллера

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using llpv5;
using System.Data.Entity.Validation;

namespace llpv5.Controllers
{
    public class emp_Oct1Controller : Controller
    {
       
        private MyEntity db = new MyEntity();

       
        // Emp with their respective location can see only the data  of their location
        public ActionResult resplocemp_linq()
        {
            
            var usercpf = System.Web.HttpContext.Current.User.Identity.Name;
            var userlocid = (from e in db.emp_Oct1 where e.cpf == usercpf select e.emplocid).FirstOrDefault(); //To find location ID of the logged in user
            var linkresult = (from l in db.emp_Oct1
                              join loc in db.loc_Oct1
                              on l.emplocid equals loc.locid
                              where l.emplocid == userlocid
                              && l.isdeletede == false
                              && l.name != "Admin"
                              select l).ToList();

            if (System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
            {
                linkresult = (from l in db.emp_Oct1
                              join loc in db.loc_Oct1
                              on l.emplocid equals loc.locid
                              where l.emplocid == userlocid
                              && l.isdeletede == false
                              && l.name != "Admin"
                              select l).ToList();
            }
            return View(linkresult.ToList());
        }
        //For Admin only - Deleted items
        
        // GET: emp_sd1
        public ActionResult isdeindex()
        {
            var emp_sd1 = db.emp_Oct1.Include(e => e.loc_Oct1).Where(e => e.isdeletede).Where(e => e.name != "Admin");
            return View(emp_sd1.ToList());
        }
        
        // GET: emp_Oct1
        public ActionResult Index()
        {
            var emp_Oct1 = db.emp_Oct1.Include(e => e.loc_Oct1).Where(e => !e.isdeletede).Where(e => e.name != "Admin");
            return View(emp_Oct1.ToList());
        }
       
        // GET: emp_Oct1/Details/5
        public ActionResult Details(int? eid, bool isdeletede)
        {
            if (eid == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            emp_Oct1 emp_Oct1 = db.emp_Oct1.Find(eid, isdeletede);
            if (emp_Oct1 == null)
            {
                return HttpNotFound();
            }
            return View(emp_Oct1);
        }
       
        // GET: emp_Oct1/Create
        public ActionResult Create()
        {
            ViewBag.emplocid = new SelectList(db.loc_Oct1, "locid", "LocationName");
            return View();
        }
        
        // POST: emp_Oct1/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "eid,name,cpf,Designation,Contact,email,emplocid,Pwd,Remarks,isdeletede,elast_mod_dt,elast_mod_by")] emp_Oct1 emp_Oct1)
        {
            if (ModelState.IsValid)
            {
                emp_Oct1.elast_mod_by = System.Web.HttpContext.Current.User.Identity.Name;
                db.emp_Oct1.Add(emp_Oct1);
                db.SaveChanges();
                return RedirectToAction("gindex_filter1");
            }

            ViewBag.emplocid = new SelectList(db.loc_Oct1, "locid", "LocationName", emp_Oct1.emplocid);
            return View(emp_Oct1);
        }
       
        // GET: emp_Oct1/Edit/5
        public ActionResult Edit(int? eid, bool isdeletede)
        {
            if (eid == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            emp_Oct1 emp_Oct1 = db.emp_Oct1.Find(eid, isdeletede);
            if (emp_Oct1 == null)
            {
                return HttpNotFound();
            }
            ViewBag.emplocid = new SelectList(db.loc_Oct1, "locid", "LocationName", emp_Oct1.emplocid);
            return View(emp_Oct1);
        }
       
        // POST: emp_Oct1/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "eid,name,cpf,Designation,Contact,email,emplocid,Pwd,Remarks,isdeletede,elast_mod_dt,elast_mod_by")] emp_Oct1 emp_Oct1)
        {
            if (ModelState.IsValid)
            {
                emp_Oct1.elast_mod_by = System.Web.HttpContext.Current.User.Identity.Name;
                db.Entry(emp_Oct1).State = EntityState.Modified;
              
                return RedirectToAction("gindex_filter1");
            }
            ViewBag.emplocid = new SelectList(db.loc_Oct1, "locid", "LocationName", emp_Oct1.emplocid);
            return View(emp_Oct1);
        }
       
        // GET: emp_Oct1/Delete/5
        public ActionResult Delete(int? eid, bool isdeletede)
        {
            if (eid == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            emp_Oct1 emp_Oct1 = db.emp_Oct1.Find(eid, isdeletede);
            if (emp_Oct1 == null)
            {
                return HttpNotFound();
            }
            return View(emp_Oct1);
        }
        
        // POST: emp_Oct1/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int eid, bool isdeletede)
        {
            emp_Oct1 emp_Oct1 = db.emp_Oct1.Find(eid, isdeletede);
            db.emp_Oct1.Remove(emp_Oct1);
            db.SaveChanges();
            return RedirectToAction("gindex_filter1");
        }


        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

Шаг 4. Внесите соответствующие изменения в автоматически сгенерированные представления, используя эта ссылка: как сопоставить составной ключ в функциях CRUD. Пример кода представления выглядит следующим образом:

@model IEnumerable<llpv5.emp_Oct1>
@{
    ViewBag.Title = "Location-specific Users";
}

<center><h2>Location-specific Users</h2></center>


<table class="table table-hover  table-bordered table-striped">
    <tr class="table-primary">
        <th>
            @Html.DisplayNameFor(model => model.cpf)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.name)
        </th>
        <th>

            @Html.DisplayNameFor(model => model.Designation)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Contact)
        </th>
        <th>
               @Html.DisplayNameFor(model => model.Pwd)   
        </th>
        <th>
            @Html.DisplayNameFor(model => model.loc_Oct1.LocationName)
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.cpf)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Designation)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Contact)
            </td>
            <td>
                @if (User.IsInRole("Admin"))
                { @Html.DisplayFor(modelItem => item.Pwd)   }
            </td>


            <td>
                @Html.DisplayFor(modelItem => item.loc_Oct1.LocationName)
            </td>


            <td>

                @Html.ActionLink("Details", "Details", new { eid = item.eid, isdeletede = item.isdeletede }) <text> | </text>
              
               @Html.ActionLink("Edit", "Edit", new { eid = item.eid, isdeletede = item.isdeletede }) <text> | </text>
                @Html.ActionLink("Delete", "Delete", new { eid = item.eid, isdeletede = item.isdeletede })
              
            </td>
        </tr>
    }

</table>
person Xplorer    schedule 07.01.2021