使用 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 可以与多个 books 相关联,但一个 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>  

现在,我们创建视图。要为 publishers 列表创建视图,请按照以下步骤操作:
- 成功编译源代码
- 右键单击“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 相关联。希望对您有所帮助。


