使用 LINQ to SQL 的简单 MVC 应用程序






4.86/5 (50投票s)
本文介绍如何使用 LINQ to SQL 创建 MVC 应用程序。您将创建一个简单的 MVC 应用程序,用于图书注册及其出版社,其中出版社和图书之间存在一对多关系。
引言
本文介绍如何使用 LINQ to SQL 创建 MVC 应用程序。您将创建一个简单的 MVC 应用程序,用于图书注册及其出版社,其中出版社和图书之间存在一对多关系。
数据库设计
您需要创建两个表,一个是以 Publisher
表存储所有出版社的信息,另一个是 BOOK
表存储所有图书的信息。创建 publisher
表的脚本如下:
CREATE TABLE Publisher
(
Id int Primary Key NOT NULL IDENTITY(1,1),
Name nvarchar(50) NOT NULL,
[Year] nvarchar(4) NOT NULL
)
publisher
表有三个字段,Id
是其主键。现在让我们看一下与表创建脚本相关的基本术语。
- 主键(Primary Key):关系表的主键唯一标识表中的每一条记录。它可以是保证唯一性的普通属性(例如,在每个
Publisher
记录不超过一条的表中,Id
字段)或由 DBMS 生成(例如,Microsoft SQL Server 中的全局唯一标识符 (GUID))。主键可以由单个属性或多个属性组合而成。您只能有一个主键,但主键可以包含多个列。 - 非空约束(NOT NULL Constraint):默认情况下,表列可以包含
NULL
值。NOT NULL
约束强制要求列不能接受NULL
值。NOT NULL
约束强制要求字段始终包含一个值。换句话说,您不能在不向此字段添加值的情况下插入新记录或更新记录。 - 标识属性(IDENTITY Property):在表中创建标识列。它用于
CREATE TABLE
和ALTER TABLE
语句。IDENTITY
属性有两个参数,一个是seed
(起始值),另一个是increment
(增量)。例如:IDENTITY [ ( seed , increment ) ]
。Seed
是加载到表中的第一行的值,而increment
是添加到已加载上一行的标识值上的增量。在publisher
表中,我们使用IDENTITY(1,1)
,这意味着publisher
表的第一行 id 列的值将是 1,下一行的 id 列的值将比上一行的 id 值大 1(下一行的 id = 上一行 id + 1)。 - NVARCHAR:它可以存储任何 Unicode 数据。
NVARCHAR
列的读写速度很快,因为所有现代操作系统和开发平台都在内部使用 Unicode。通过使用NVARCHAR
,您可以避免每次读写数据库时都进行编码转换。转换需要时间,并且容易出错。从转换错误中恢复是一个棘手的问题。
BOOK
表创建脚本如下:
CREATE TABLE BOOK
(
Id int Primary Key NOT NULL IDENTITY(1,1),
Title nvarchar(50) NOT NULL,
Auther nvarchar(50)NOT NULL,
[Year] nvarchar (4) NOT NULL,
Price decimal(6,2)NOT NULL,
PublisherId int NOT NULL
)
BOOK
表有六个字段;Id
是其主键。现在让我们看一下与表创建脚本相关的基本术语。
- Decimal:Decimal 数据类型最多可以存储 38 位数字,所有这些数字都可以位于小数点右侧。Decimal 数据类型存储数字的精确表示;存储的值没有近似值。定义 decimal 列、变量和参数的两个属性是
decimal(p,s)
:p
指定精度,即对象可以容纳的总位数;s
指定小数位数,即可以放在小数点右侧的位数。Price
列decimal(6,2)
意味着6
是允许的总位数,2
是小数点右侧的位数。
现在,您可以定义 Publisher
和 BOOK
表之间的关系。我们定义它们之间的一对多关系,换句话说,一个 Publisher
可以与多个 book
s 相关联,但一个 book
只能与一个 publisher
相关联,因此我们在 publisher id 上定义外键。
ALTER TABLE BOOK
ADD CONSTRAINT FK_BOOK_PUBLISHER FOREIGN KEY (PublisherId)
REFERENCES Publisher(Id)ON DELETE CASCADE
- 外键(Foreign Key):外键 (FK) 是一个或多个列,用于在两个表的数据之间建立和强制执行链接。外键约束不一定只链接到另一个表中的主键约束,它也可以定义为引用另一个表中的唯一约束的列。外键约束可以包含
null
值;但是,如果复合外键约束的任何列包含null
值,则会跳过对构成外键约束的所有值的验证。为确保所有复合外键约束的值都得到验证,请在所有参与的列上指定NOT NULL
。外键约束通过确保不能在主键表中更改数据(如果这些更改会使指向外键表的数据的链接失效)来强制执行引用完整性。如果尝试删除主键表中的行或更改主键值,那么当被删除或更改的主键值与另一个表的外键约束中的值对应时,该操作将失败。要成功更改或删除外键约束中的行,您必须首先删除外键表中的外键数据,或者更改外键表中链接外键到其他主键数据的外键数据。 - ON DELETE CASCADE(删除级联):外键约束是引用完整性约束。换句话说,当您想从父表中删除一行,并且该行在另一个表中有关联的子行时,您首先需要删除与父表有关联的所有子表中的关联行,然后再删除父表行。为了避免这种情况,您可以使用
ON DELETE CASCADE
选项,当您从父表中删除一行时,数据库服务器还会删除子表中与该行(外键)相关的所有行。级联删除功能的主要优点是它可以减少执行删除操作所需的 SQL 语句数量。
创建 MVC 应用程序
我将使用 Visual Studio 2012 创建一个 MVC 应用程序。让我们一步一步地看一下如何创建 MVC 应用程序。
步骤 1:转到“文件”-“新建”,然后单击“项目”。
步骤 2:从列表中选择“ASP.NET MVC 4 Web 应用程序”,然后提供应用程序名称“LinqToSQLMvcApplication
”,并在位置输入框中设置要创建应用程序的路径。
步骤 3:现在从下拉列表中选择“空”项目模板,并将“Razor”选为视图引擎。
步骤 4:使用对象关系设计器创建一个 ContextData
文件。
实体类会被创建并存储在 LINQ to SQL 类文件(.dbml 文件)中。当您打开 .dbml 文件时,O/R 设计器会打开。它是一个 DataContext
类,其中包含连接数据库和操作数据库数据的函数和属性。
DataContext
的名称对应于您为 .dbml 文件提供的名称。
步骤 4.1:在解决方案资源管理器中右键单击“Models”文件夹,然后转到“添加”并单击“类…”。
步骤 4.2:从列表中选择“LINQ to SQL 类”,然后为 dbml 名称提供“Operation”。然后单击“添加”。
步骤 4.3:单击“添加”按钮后,将创建 ContextData
文件。现在,我们应该将所有表拖到设计器的左侧并保存(如下图所示)。这将为每个表及其实体创建所有映射和设置。
.dbml 文件的数据库连接字符串在 web.config 文件中定义,如下所示:
<connectionStrings>
<add name="DevelopmentConnectionString"
connectionString="Data Source=sandeepss-PC;Initial Catalog=Development;User ID=sa;
Password=*******" providerName="System.Data.SqlClient" />
</connectionStrings>
我们可以在 web.config 文件中使用连接字符串,或者可以将连接字符串作为参数传递给 DataContext
类的构造函数来创建 DataContext
类的对象。
现在,在控制器(Controllers 文件夹下的 StudentController
类)中创建一个操作方法,该方法在 post 请求后返回带有模型的视图。
为应用程序创建 Publisher
创建了一个空的 MVC 应用程序后,我将创建一个 Model、View 和 Controller 来添加一个新的 Publisher 并显示部门列表。请按照以下步骤进行操作。
步骤 1:创建 Model“PublisherModel.cs”
MVC Model 包含所有应用程序逻辑(业务逻辑、验证逻辑和数据访问逻辑),纯粹的视图和控制器逻辑除外。我们在“Models”文件夹下创建一个 PublisherModel
类(PublisherModel.cs 文件)。PublisherModel
类位于 Models 文件夹中;该文件名是 PublisherModel.cs,如下所示:
namespace LinqToSQLMvcApplication.Models
{
public class PublisherModel
{
public int Id { get; set; }
public string Name { get; set; }
public int Year { get; set; }
}
}
步骤 2:为 Publisher 创建 Controller
现在,我创建一个 Publisher 控制器,它具有用于创建和显示 Publisher 列表的操作。
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using LinqToSQLMvcApplication.DAL;
using LinqToSQLMvcApplication.Models;
namespace LinqToSQLMvcApplication.Controllers
{
public class PublisherController : Controller
{
private OperationDataContext context;
public PublisherController()
{
context = new OperationDataContext();
}
public ActionResult Index()
{
IList<PublisherModel> publisherList = new List<PublisherModel>();
var query = from publisher in context.Publishers
select publisher;
var publishers = query.ToList();
foreach(var publisherData in publishers )
{
publisherList.Add(new PublisherModel()
{
Id= publisherData.Id,
Name = publisherData.Name,
Year = publisherData.Year
});
}
return View(publisherList);
}
public ActionResult Create()
{
PublisherModel model = new PublisherModel();
return View(model);
}
[HttpPost]
public ActionResult Create(PublisherModel model)
{
try
{
Publisher publisher = new Publisher()
{
Name = model.Name,
Year = model.Year
};
context.Publishers.InsertOnSubmit(publisher);
context.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View(model);
}
}
}
}
现在,我们创建一个视图来添加新的 Publisher。要创建视图,请按照以下步骤操作:
- 右键单击“Create”(GET)操作方法。
- 视图名称已填写,请勿更改。
- 视图引擎已选择 Razor,请勿更改。
- 选中“创建强类型视图”复选框,因为我们正在创建强类型视图。
- 选择 Model 类“
PublisherModel
”,以便它可以与视图绑定。 - 从脚手架模板中选择“创建”,以便我们能够快速开发,并获得用于创建新用户的视图。
- 选中“使用布局页或母版页”复选框。
@model LinqToSQLMvcApplication.Models.PublisherModel
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>PublisherModel</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Year)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Year)
@Html.ValidationMessageFor(model => model.Year)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
现在,我们创建视图。要为 publisher
s 列表创建视图,请按照以下步骤操作:
- 成功编译源代码
- 右键单击“Index”操作方法。
- 视图名称已填写,请勿更改。
- 视图引擎已选择 Razor,请勿更改。
- 选中“创建强类型视图”复选框,因为我们正在创建强类型视图。
- 选择 Model 类“
PublisherModel
”,以便它可以与视图绑定。 - 从脚手架模板中选择“列表”,以便可以进行快速开发,并获得显示用户列表的代码视图。
- 选中“使用布局页或母版页”复选框。
@model IEnumerable<LinqToSQLMvcApplication.Models.PublisherModel>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Year)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Year)
</td>
</tr>
}
</table>
为应用程序创建 Books
创建 Publisher 后,我将创建一个 Model、View 和 Controller 来添加新 Book 并显示 Book 列表。让我们一步一步地看一下。
步骤 1:创建 Model“BookModel.cs”
MVC Model 包含所有应用程序逻辑(业务逻辑、验证逻辑和数据访问逻辑),纯粹的视图和控制器逻辑除外。我们在“Models”文件夹下创建一个 BookModel
类(BookModel.cs 文件),BookModel
类位于 Models 文件夹中;该文件名是 BookModel.cs,如下所示:
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.Mvc;
namespace LinqToSQLMvcApplication.Models
{
public class BookModel
{
public BookModel()
{
Publishers = new List<SelectListItem>();
}
public int Id { get; set; }
public string Title { get; set; }
public string Auther { get; set; }
public string Year { get; set; }
public decimal Price { get; set; }
[DisplayName("Publisher")]
public int PublisherId { get; set; }
public string PublisherName { get; set; }
public IEnumerable<SelectListItem> Publishers { get; set; }
}
}
步骤 2:为 Book 创建 Controller
现在,我创建一个 Book
控制器,它具有 book
的所有 CRUD 操作的操作。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using LinqToSQLMvcApplication.DAL;
using LinqToSQLMvcApplication.Models;
namespace LinqToSQLMvcApplication.Controllers
{
public class BookController : Controller
{
private OperationDataContext context;
public BookController()
{
context = new OperationDataContext();
}
private void PreparePublisher(BookModel model)
{
model.Publishers = context.Publishers.AsQueryable<Publisher>().Select(x =>
new SelectListItem()
{
Text = x.Name,
Value = x.Id.ToString()
});
}
public ActionResult Index()
{
IList<BookModel> BookList = new List<BookModel>();
var query = from book in context.BOOKs
join publisher in context.Publishers
on book.PublisherId equals publisher.Id
select new BookModel {
Id = book.Id,Title=book.Title,
PublisherName=publisher.Name,Auther = book.Auther,
Year = book.Year,Price=book.Price
};
BookList = query.ToList();
return View(BookList);
}
public ActionResult Details(int id)
{
BookModel model = context.BOOKs.Where(x => x.Id == id).Select(x =>
new BookModel()
{
Id= x.Id,
Title=x.Title,
Auther=x.Auther,
Price =x.Price,
Year =x.Year,
PublisherName=x.Publisher.Name
}).SingleOrDefault();
return View(model);
}
public ActionResult Create()
{
BookModel model = new BookModel();
PreparePublisher(model);
return View(model);
}
[HttpPost]
public ActionResult Create(BookModel model)
{
try
{
BOOK book = new BOOK()
{
Title = model.Title,
Auther = model.Auther,
Year = model.Year,
Price = model.Price,
PublisherId = model.PublisherId
};
context.BOOKs.InsertOnSubmit(book);
context.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View(model);
}
}
public ActionResult Edit(int id)
{
BookModel model = context.BOOKs.Where(x => x.Id == id).Select(x =>
new BookModel()
{
Id = x.Id,
Title = x.Title,
Auther = x.Auther,
Price = x.Price,
Year = x.Year,
PublisherId = x.PublisherId
}).SingleOrDefault();
PreparePublisher(model);
return View(model);
}
[HttpPost]
public ActionResult Edit(BookModel model)
{
try
{
BOOK book = context.BOOKs.Where(x => x.Id == model.Id).Single<BOOK>();
book.Title = model.Title;
book.Auther = model.Auther;
book.Price = model.Price;
book.Year = model.Year;
book.PublisherId = model.PublisherId;
context.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View(model);
}
}
public ActionResult Delete(int id)
{
BookModel model = context.BOOKs.Where(x => x.Id == id).Select(x =>
new BookModel()
{
Id = x.Id,
Title = x.Title,
Auther = x.Auther,
Price = x.Price,
Year = x.Year,
PublisherName = x.Publisher.Name
}).SingleOrDefault();
return View(model);
}
[HttpPost]
public ActionResult Delete(BookModel model)
{
try
{
BOOK book = context.BOOKs.Where(x => x.Id == model.Id).Single<BOOK>();
context.BOOKs.DeleteOnSubmit(book);
context.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View(model);
}
}
}
}
现在,我将为 book
的每个操作创建一个视图。让我们看一下每个视图及其代码。
1. 创建一个视图来向商店添加新图书
我在 Views/Book 文件夹下创建一个视图“Create.cshtml”,该视图使用控制器(GET 请求)的两个操作方法(Create
)和一个用于 POST 请求的操作方法。
@model LinqToSQLMvcApplication.Models.BookModel
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) {
<fieldset>
<legend>BookModel</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Auther)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Auther)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Year)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Year)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Price)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Price)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.PublisherId)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.PublisherId,Model.Publishers)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
2. 显示所有图书的列表
我在 Views/Book 文件夹下创建一个视图“Index.cshtml”,该视图使用控制器(GET 请求)的一个操作方法(Index
)。
@model IEnumerable<LinqToSQLMvcApplication.Models.BookModel>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Auther)
</th>
<th>
@Html.DisplayNameFor(model => model.Year)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th>
@Html.DisplayNameFor(model => model.PublisherName)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Auther)
</td>
<td>
@Html.DisplayFor(modelItem => item.Year)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.PublisherName)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
@Html.ActionLink("Details", "Details", new { id=item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
3. 编辑图书
我在 Views/Book 文件夹下创建一个视图“Edit.cshtml”,该视图使用控制器(GET 请求)的两个操作方法(Edit
)和一个用于 POST 请求的操作方法。
@model LinqToSQLMvcApplication.Models.BookModel
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm()) {
<fieldset>
<legend>BookModel</legend>
@Html.HiddenFor(model => model.Id)
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Auther)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Auther)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Year)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Year)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Price)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Price)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.PublisherId)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.PublisherId,Model.Publishers)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
4. Book 的详细信息
我在 Views/Book 文件夹下创建一个视图“Details.cshtml”,该视图使用控制器(GET 请求)的一个操作方法(Details
)。
@model LinqToSQLMvcApplication.Models.BookModel
@{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>BookModel</legend>
<div class="display-label">
@Html.DisplayNameFor(model => model.Title)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Title)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.Auther)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Auther)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.Year)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Year)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.Price)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Price)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.PublisherName)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.PublisherName)
</div>
</fieldset>
<p>
@Html.ActionLink("Edit", "Edit", new { id=Model.Id }) |
@Html.ActionLink("Back to List", "Index")
</p>
5. 删除 Book
我在 Views/Book 文件夹下创建一个视图“Delete.cshtml”,该视图使用控制器(GET 请求)的两个操作方法(Delete
)和一个用于 POST 请求的操作方法。
@model LinqToSQLMvcApplication.Models.BookModel
@{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<fieldset>
<legend>BookModel</legend>
<div class="display-label">
@Html.DisplayNameFor(model => model.Title)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Title)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.Auther)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Auther)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.Year)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Year)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.Price)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.Price)
</div>
<div class="display-label">
@Html.DisplayNameFor(model => model.PublisherName)
</div>
<div class="display-field">
@Html.DisplayFor(model => model.PublisherName)
</div>
</fieldset>
@using (Html.BeginForm()) {
<p>
<input type="submit" value="Delete" /> |
@Html.ActionLink("Back to List", "Index")
</p>
}
结论
本文解释了数据库实体(Book
)的基本操作,以及它如何将实体 publisher
与另一个 entity
book 相关联。希望对您有所帮助。