ASP.NET MVC 结合 AngularJS 实现存储过程处理单个和列表对象






4.61/5 (10投票s)
使用存储过程进行 .net MVC 中的 CRUD 操作,处理单个和列表对象数据,并包含 SQL 事务。
引言
与 LINQ 查询相比,存储过程速度更快,并且可以充分利用 SQL 的各项功能。
本文主要关注 SQL Server 2008/2012 中的存储过程。我们将使用 MVC 框架结合 angularJS,通过存储过程实现 CRUD 操作。本文将涵盖以下主题和功能:
- 如何在 SQL Server 2008/2012 中创建存储过程
- 在 .NET MVC 中使用存储过程结合 angularJS 进行 CRUD 操作
- 用于单个对象数据的存储过程
- 用于列表数据的存储过程(以 XML 数据和 Data Table 的形式)
- 存储过程中的事务
下载项目文件
设置您的数据库
我们将使用以下数据表来展示存储过程如何与您的应用程序协同工作。
dbo.t_Student
在上述表中,所有字段都设置为非空,并且主键的标识规范
按如下所示自动递增 1。
存储过程基础
在创建第一个过程之前,让我们先了解一些命名约定和格式的介绍。
由于默认的数据库过程使用sp_Procedure_Name
作为其命名约定,我们将以略微不同的方式使用它来区分我们的过程。我们将使用usp_ProcedureName
作为用户定义过程。要在过程中传递参数,我们必须在该参数名称前使用"@
"符号,然后声明其数据类型,如相应表中所示。以下是如何创建过程的示例。
CREATE PROCEDURE usp_ProcedureName(
@parameter1Name parameter1Type, @parameter2Name parameter2Type, ...)
AS
BEGIN
SET NOCOUNT ON;
-- query for the required CRUD action
END
GO
创建所需的(单个对象)存储过程
要创建过程,请转到UniversityDB > Programmability > Stored Procedure ,如下图所示。
然后右键单击Stored Procedure文件夹,然后单击Stored Procedure...
。将打开一个脚本窗口,如下图所示,您需要做的就是编写所需的存储过程。
只需将上述默认结构更改为如下所示,该结构用于保存学生数据(单个对象)。编写以下脚本后,只需执行您的脚本即可。嘿!您的第一个过程已创建。您将在Stored Procedure文件夹中找到所有用户定义的存储过程。以下是用于单个数据对象的Save
、Update
、Delete
和Select
过程。
usp_SaveStudent
CREATE PROCEDURE usp_SaveStudent(
@firstName varchar(100), @lastName varchar(100), @email varchar(100),
@address varchar(150), @enrollDate datetime, @departmentId int)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO t_Student(Student_FirstName, Student_LastName, Student_Email, Student_Address,
Student_EnrollmentDate, Student_DepartmentId)
VALUES (@firstName, @lastName, @email, @address, @enrollDate, @departmentId)
END
GO
usp_UpdateStudent
CREATE PROCEDURE usp_UpdateStudent(
@id int, @firstName varchar(100), @lastName varchar(100), @email varchar(100),
@address varchar(150), @enrollDate datetime, @departmentId int)
AS
BEGIN
SET NOCOUNT ON;
UPDATE t_Student
SET Student_FirstName = @firstName, Student_LastName = @lastName, Student_Email = @email,
Student_Address = @address, Student_EnrollmentDate = @enrollDate, Student_DepartmentId = @departmentId
WHERE Student_Id = @id
END
GO
usp_DeleteStudent
CREATE PROCEDURE usp_DeleteStudent(@id int)
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM t_Student WHERE Student_Id = @id
END
GO
usp_GetAllStudentData
CREATE PROCEDURE usp_GetAllStudentData
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM t_Student
END
GO
创建所需的(对象列表)存储过程
要通过存储过程保存列表数据,我们首先需要创建用户定义表(不是实际的数据库表,只是一个副本)。创建新数据类型后,我们必须为通过过程传递的参数使用该数据类型。
在这一部分,我们将创建过程以通过存储过程将数据列表保存到数据库。首先,我们将一个 XML
数据字符串传递给过程,然后将一个 Data Table
从中进行INSERT
操作来保存所有数据。
usp_SaveStudentListFromXml
CREATE PROCEDURE usp_SaveStudentListFromXml(@xmlData xml)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO t_Student(Student_FirstName, Student_LastName, Student_Email, Student_Address,
Student_EnrollmentDate, Student_DepartmentId)
SELECT
std.query('Student_FirstName').value('.','varchar(100)') as LCAItem_LCAFNo,
std.query('Student_LastName').value('.','varchar(100)') as LCAItem_HSCode,
std.query('Student_Email').value('.','varchar(100)') as LCAItem_Unit,
std.query('Student_Address').value('.','varchar(150)') as LCAItem_Quantity,
std.query('Student_EnrollmentDate').value('.','datetime') as LCAItem_TotalPrice,
std.query('Student_DepartmentId').value('.','int') as LCAItem_UnitPrice
FROM @xmlData.nodes('/STUDENTS/STUDENT') as XMLData(std)
END
GO
usp_SaveStudentListFromDataTable
-- First create a type as Student. Make elements exactly as t_Student table
-- This will work as Student object for the procedure
-- Since primary key is auto incremented so we will not include it in this new Student type
CREATE TYPE dbo.StudentType AS TABLE(
Student_FirstName varchar(100),
Student_LastName varchar(100),
Student_Email varchar(100),
Student_Address varchar(150),
Student_EnrollmentDate datetime,
Student_DepartmentId int
)
GO
-- Now create the procedure where @studentList will be the newly created StudentType data
CREATE PROCEDURE usp_SaveStudentListFromDataTable(@studentList dbo.StudentType readonly)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO t_Student(Student_FirstName, Student_LastName, Student_Email, Student_Address,
Student_EnrollmentDate, Student_DepartmentId)
SELECT Student_FirstName, Student_LastName, Student_Email, Student_Address,
Student_EnrollmentDate, Student_DepartmentId FROM @studentList
END
GO
目前,这些是我们创建应用程序所需的数据库元素。当需要描述来关联数据库变量与 C# 变量和代码时,将在代码中描述一些要点。
在 MVC 应用程序中工作
- 首先创建一个空的 MVC 应用程序(我在这里使用的是 VS 2013 & .NET v4.5)。
- 然后转到Tools > Library Package Manager > Manage NuGet Packages for Solution,添加/更新
Bootstrap
、jQuery
、angularJS
和Microsoft ASP.NET MVC
包。构建您的项目以检查任何错误。
- 现在,在您的项目成功构建后,右键单击Views文件夹并添加一个名为Layout的文件夹。然后添加一个MVC 5 Layout Page (Razor)并命名为
_LayoutPage
。然后按照本文档中附加的演示项目中的方式添加所需的样式、主题和脚本。
- 在这一部分,我们将为项目添加一个数据库模型。右键单击Models文件夹并添加一个ADO .NET Entity Data Model并命名为
SprocModel
。然后按照说明将您的UniversityDB
数据库添加到项目中。我们在这里将实体名称设置为SprocEntities
。 - 通过右键单击Controller文件夹,添加一个控制器(MVC 5 Controller - Empty)并命名为
HomeController
。然后向HomeController
添加以下引用和操作。
确保这些引用已添加到您的HomeController
命名空间部分。
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Xml.Linq;
using StoredProcedureMvc.Models;
在创建操作之前创建您的实体实例。
readonly SprocEntities _db = new SprocEntities();
然后为单个对象页面和对象列表页面创建这两个视图。
public ActionResult Index()
{
return View();
}
public ActionResult ListObject()
{
return View();
}
之后,创建以下操作。
public JsonResult GetStudentList()
{
var list = _db.usp_GetAllStudentData().ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
public ActionResult SaveStudent(t_Student student)
{
_db.usp_SaveStudent(student.Student_FirstName, student.Student_LastName, student.Student_Email,
student.Student_Address, student.Student_EnrollmentDate, student.Student_DepartmentId);
var list = _db.usp_GetAllStudentData().ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
public ActionResult UpdateStudent(t_Student student)
{
_db.usp_UpdateStudent(student.Student_Id, student.Student_FirstName, student.Student_LastName, student.Student_Email,
student.Student_Address, student.Student_EnrollmentDate, student.Student_DepartmentId);
var list = _db.usp_GetAllStudentData().ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
public ActionResult DeleteStudent(t_Student student)
{
_db.usp_DeleteStudent(student.Student_Id);
var list = _db.usp_GetAllStudentData().ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
在以下操作中,我们将把学生列表students
转换为 XML 文件,然后将其作为 XML 字符串发送到过程usp_SaveStudentListFromXml
。
public ActionResult SaveStudentAsXml(List
在这里,我们将把同一个学生列表students
转换为 DataTable
,然后将其作为Sql Parameter发送到过程usp_GetAllStudentData
。请仔细遵循参数的创建方式以及该参数的不同值的设置。
public ActionResult SaveStudentAsTable(List
- 现在,由于所有必需的操作都已添加到
HomeController
,我们需要为两个视图Index.cshtml
和ListObject.cshtml
添加两个脚本文件。将这些文件命名为singleObject.js
和listObject.js
,然后将这些文件的引用添加到您的Index.cshtml
和ListObject.cshtml
视图中。 - 右键单击您的Scripts文件夹,并在其中添加一个名为CustomScripts的文件夹,然后在CustomScripts文件夹中创建以下脚本文件。
- 请确保您了解 angularJS 的基础知识以及如何使用它进行 CRUD 操作。
singleObject.js
var app = angular.module('myApp', [])
.controller('myCtrl', ["$scope", "$http", function ($scope, $http) {
$scope.departmentList = [
{ value: 1, name: "Computer Science & Engineering" },
{ value: 2, name: "Electrical & Electronic Engineering" },
{ value: 3, name: "Business Administration" },
{ value: 4, name: "Genetic Engineering" }
];
$scope.GetStudentList = function () {
$http({
traditional: true,
url: "/Home/GetStudentList",
method: 'GET',
contentType: "application/json",
dataType: "json"
}).success(function (data) {
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
}
}).error(function (data) {
alert("Could not get student data!");
});
};
$scope.GetStudentList();
$scope.Save = function (std) {
$http({
traditional: true,
url: "/Home/SaveStudent",
method: 'POST',
data: JSON.stringify({ student: std }),
contentType: "application/json",
dataType: "json"
}).success(function (data) {
$scope.std = {};
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
}
alert("Data saved successfully.");
}).error(function (data) {
alert("Could not save student data!");
});
};
$scope.Update = function (std) {
$http({
traditional: true,
url: "/Home/UpdateStudent",
method: 'POST',
data: JSON.stringify({ student: std }),
contentType: "application/json",
dataType: "json"
}).success(function (data) {
$scope.std = {};
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
}
alert("Data updated successfully.");
}).error(function (data) {
alert("Could not update student data!");
});
};
$scope.Delete = function (item) {
var msg = confirm("Do you want to delete this student data?");
if (msg == true) {
$http({
traditional: true,
url: "/Home/DeleteStudent",
method: 'POST',
data: JSON.stringify({ student: item }),
contentType: "application/json",
dataType: "json"
}).success(function (data) {
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
}
alert("Data deleted successfully.");
}).error(function (data) {
alert("Could not delete student data!");
});
}
};
$scope.Edit = function (item) {
$scope.std = angular.copy(item);
};
$scope.Cancel = function () {
$scope.std = {};
};
$scope.FormatFullDate = function (item) {
var year = item.getFullYear();
var month = ('0' + (item.getMonth() + 1)).slice(-2);
var day = ('0' + (item.getDate())).slice(-2);
var fullDate = year + "/" + month + "/" + day;
return fullDate;
};
}]).filter("deptDetails", function () {
return function (id) {
switch (id) {
case 1:
return "Computer Science & Engineering";
break;
case 2:
return "Electrical & Electronic Engineering";
break;
case 3:
return "Business Administration";
break;
case 4:
return "Genetic Engineering";
break;
default:
}
};
});
listObject.js
var app = angular.module('myApp', [])
.controller('myCtrl', ["$scope", "$http", function ($scope, $http) {
$scope.departmentList = [
{ value: 1, name: "Computer Science & Engineering" },
{ value: 2, name: "Electrical & Electronic Engineering" },
{ value: 3, name: "Business Administration" },
{ value: 4, name: "Genetic Engineering" }
];
$scope.GetStudentList = function () {
$http({
traditional: true,
url: "/Home/GetStudentList",
method: 'GET',
contentType: "application/json",
dataType: "json"
}).success(function (data) {
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
}
}).error(function (data) {
alert("Could not get student data!");
});
};
$scope.GetStudentList();
$scope.studentList1 = [];
$scope.AddStudent = function (std) {
if (std != null) {
$scope.studentList1.push(std);
$scope.std = {};
} else {
alert('Please insert student info first.');
}
};
$scope.DeleteStudent = function (item) {
var index = -1;
var comArr = eval($scope.studentList1);
for (var i = 0; i < comArr.length; i++) {
if (comArr[i] === item) {
index = i;
break;
}
}
if (index === -1) {
alert("Something gone wrong");
}
$scope.studentList1.splice(index, 1);
};
$scope.SaveAsXml = function (studentList1) {
$http({
traditional: true,
url: "/Home/SaveStudentAsXml",
method: 'POST',
data: JSON.stringify({ students: studentList1 }),
contentType: "application/json",
dataType: "json"
}).success(function (data) {
$scope.std = {};
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
$scope.studentList1 = [];
alert("Data saved successfully.");
}
}).error(function (data) {
alert("Could not save student data!");
});
};
$scope.SaveAsTable = function (studentList1) {
$http({
traditional: true,
url: "/Home/SaveStudentAsTable",
method: 'POST',
data: JSON.stringify({ students: studentList1 }),
contentType: "application/json",
dataType: "json"
}).success(function (data) {
$scope.std = {};
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
$scope.studentList1 = [];
alert("Data saved successfully.");
}
}).error(function (data) {
alert("Could not save student data!");
});
};
$scope.Update = function (std) {
$http({
traditional: true,
url: "/Home/UpdateStudent",
method: 'POST',
data: JSON.stringify({ student: std }),
contentType: "application/json",
dataType: "json"
}).success(function (data) {
$scope.std = {};
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
}
alert("Data updated successfully.");
}).error(function (data) {
alert("Could not update student data!");
});
};
$scope.Delete = function (item) {
var msg = confirm("Do you want to delete this student data?");
if (msg == true) {
$http({
traditional: true,
url: "/Home/DeleteStudent",
method: 'POST',
data: JSON.stringify({ student: item }),
contentType: "application/json",
dataType: "json"
}).success(function (data) {
if (data.length > 0) {
for (var i = 0; i < data.length; i++) {
if (data[i].Student_EnrollmentDate != null) {
var tempDate = new Date(parseInt(data[i].Student_EnrollmentDate.substr(6)));
data[i].Student_EnrollmentDate = $scope.FormatFullDate(tempDate);
}
}
$scope.studentList = data;
}
alert("Data deleted successfully.");
}).error(function (data) {
alert("Could not delete student data!");
});
}
};
$scope.Edit = function (item) {
$scope.std = angular.copy(item);
};
$scope.Cancel = function () {
$scope.std = {};
$scope.studentList1 = [];
};
$scope.FormatFullDate = function (item) {
var year = item.getFullYear();
var month = ('0' + (item.getMonth() + 1)).slice(-2);
var day = ('0' + (item.getDate())).slice(-2);
var fullDate = year + "/" + month + "/" + day;
return fullDate;
};
}]).filter("deptDetails", function () {
return function (id) {
switch (id) {
case 1:
return "Computer Science & Engineering";
break;
case 2:
return "Electrical & Electronic Engineering";
break;
case 3:
return "Business Administration";
break;
case 4:
return "Genetic Engineering";
break;
default:
}
};
});
在上面的脚本文件中,我将部门列表创建为静态列表。您也可以从数据库获取它。
- 由于我已将演示项目文件附加到本文档中,因此此处不提供 HTML 页面的标记。而是提供我们需要使用的两个页面的屏幕截图。
单个学生对象截图
在上面的表单中,填写所有字段并单击Save按钮以保存学生数据。单击Action标题下的Edit图标来编辑数据,编辑数据后单击Update按钮进行更新。Trash图标将删除学生对象。
学生列表对象截图
在此,填写完所有字段后,单击Add按钮将该学生数据添加到右侧的表中。您可以根据需要添加任意数量的学生。将所有学生添加到表中后,单击Save Student List as XML以将学生列表保存为XML 数据,或者单击Save Student List as Data Table以将列表保存为Data Table。在这里,第二个表(位于表单下方)中的Edit和Trash图标将执行与上一页所述相同的操作。
关注点
本文主要帮助初学者以及那些真正喜欢存储过程但又在处理列表数据方面遇到困难的中级开发者。许多人可能更喜欢 LINQ 而不是存储过程(因为代码量少),但鉴于性能和安全性,存储过程仍然是一个不错的选择。希望本文能对您有所帮助。
注意
关于 SQL 事务的讨论将尽快添加到本文档中。
历史
已根据反馈解决了演示应用程序文件缺失和下载问题。请查看。