第4章 模型(建模、构造基架)

来源:互联网 发布:交大昂立网络教育 编辑:程序博客网 时间:2024/06/06 10:13
模型就是要显示、保存、创建、更新和删除的对象。

一、 为MVC Music Store建模


在Model文件夹下添加类

//专辑

public class Album{    public virtual int AlbumId { get; set; }    public virtual int GenreId { get; set; }    public virtual int ArtistId { get; set; }    public virtual string Title { get; set; }    public virtual decimal Price { get; set; }    public virtual string AlbumArtUrl { get; set; }    public virtual Genre Genre { get; set; }    public virtual Artist Artist { get; set; }}
//艺术家
    public class Artist    {        public virtual int ArtistId { get; set; }        public virtual string Name { get; set; }    }
//电影类型
    public class Genre    {        public virtual int GenreId { get; set; }        public virtual string Name { get; set; }        public virtual string Description { get; set; }        public virtual List<Album> Albums { get; set; }    }

virtual 代表在继承了这个类的子类里面可以使用override将此方法重载。

虚拟属性不是必需的,但是它们给EF提供一个指向纯c#类集的钩子,并为EF启用了一些特性,如高效的修改跟踪机制

编译程序,查看是否有错误。

二、 为商店管理器构造基架

1、 基架的含义

在添加视图对话框允许选择一个用来创建视图代码的模板。这种代码生成过程就叫做“基架”。

技巧:通过NuGet(搜索scaffolding)查询可替代的基架模板。

ASP.Net MVC极速开发:使用MVCScaffolding + EntityFramework CodeFirst

2、 基架和实体框架

新建ASP.NET MVC5项目会自动包含对实体框架(EF)的引用。EF是一个对象关系映射(object-relational mapping,ORM)框架。

(1)、代码优先约定

(2)、DbContext类

当使用EF的代码优先方法时,需要使用从EF的DbContext类派生出一个类访问数据库。
该派生类具有一个或多个DbSet<T>类型的属性,T代表一个想要持久保存的对象。然后通过使用LINQ查询。

3 、执行基架模板

添加控制器





MvcMusicStore.Models是类的命名空间,将数据上下文类命名为MusicStoreDB。


(1)、数据上下文

    //继承实体框架的DbContext类    public class MusicStoreDB : DbContext    {        // You can add custom code to this file. Changes will not be overwritten.        //         // If you want Entity Framework to drop and regenerate your database        // automatically whenever you change your model schema, please use data migrations.        // For more information refer to the documentation:        // http://msdn.microsoft.com/en-us/data/jj591621.aspx        //注释:        //现在代码归我们所有。DbContext的创建是一次性完成的,所以可以自由修改这个类,不用担心所做修改会被重写。        //代码归我们负责。我们需要确保对模型类所做的修改能够会反映到数据库中,反之亦然,即对数据库的修改也会反映到模型类中。        //EF通过使用数据库迁移来帮我们完成这项工作。        public MusicStoreDB() : base("name=MusicStoreDB")        {        }        public System.Data.Entity.DbSet<MvcMusicStore.Models.Album> Albums { get; set; }        public System.Data.Entity.DbSet<MvcMusicStore.Models.Artist> Artists { get; set; }        public System.Data.Entity.DbSet<MvcMusicStore.Models.Genre> Genres { get; set; }        }

EF 4.3中引入的数据迁移是一种系统的、基于代码的方法,用于将更改应用到数据库
第16章将详细介绍迁移

(2)、StroreManagerController

namespace MvcMusicStore.Controllers{    public class StroreManagerController : Controller    {        private MusicStoreDB db = new MusicStoreDB();        // GET: /StroreManager/        public ActionResult Index()        {            var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre);            return View(albums.ToList());        }        // GET: /StroreManager/Details/5        public ActionResult Details(int? id)        {            if (id == null)            {                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);            }            Album album = db.Albums.Find(id);            if (album == null)            {                return HttpNotFound();            }            return View(album);        }        // GET: /StroreManager/Create        public ActionResult Create()        {            ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");            ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");            return View();        }        // POST: /StroreManager/Create        // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关         // 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。        [HttpPost]        [ValidateAntiForgeryToken]        public ActionResult Create([Bind(Include="AlbumId,GenreId,ArtistId,Title,Price,AlbumArtUrl")] Album album)        {            if (ModelState.IsValid)            {                db.Albums.Add(album);                db.SaveChanges();                return RedirectToAction("Index");            }            ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);            ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);            return View(album);        }        // GET: /StroreManager/Edit/5        public ActionResult Edit(int? id)        {            if (id == null)            {                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);            }            Album album = db.Albums.Find(id);            if (album == null)            {                return HttpNotFound();            }            ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);            ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);            return View(album);        }        // POST: /StroreManager/Edit/5        // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关         // 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。        [HttpPost]        [ValidateAntiForgeryToken]        public ActionResult Edit([Bind(Include="AlbumId,GenreId,ArtistId,Title,Price,AlbumArtUrl")] Album album)        {            if (ModelState.IsValid)            {                db.Entry(album).State = EntityState.Modified;                db.SaveChanges();                return RedirectToAction("Index");            }            ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);            ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);            return View(album);        }        // GET: /StroreManager/Delete/5        public ActionResult Delete(int? id)        {            if (id == null)            {                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);            }            Album album = db.Albums.Find(id);            if (album == null)            {                return HttpNotFound();            }            return View(album);        }        // POST: /StroreManager/Delete/5        [HttpPost, ActionName("Delete")]        [ValidateAntiForgeryToken]        public ActionResult DeleteConfirmed(int id)        {            Album album = db.Albums.Find(id);            db.Albums.Remove(album);            db.SaveChanges();            return RedirectToAction("Index");        }        protected override void Dispose(bool disposing)        {            if (disposing)            {                db.Dispose();            }            base.Dispose(disposing);        }    }}

(3)、视图

@model IEnumerable<MvcMusicStore.Models.Album>@{    ViewBag.Title = "Index";}<h2>Index</h2><p>    @Html.ActionLink("Create New", "Create")</p><table class="table">    <tr>        <th>            @Html.DisplayNameFor(model => model.Artist.Name)        </th>        <th>            @Html.DisplayNameFor(model => model.Genre.Name)        </th>        <th>            @Html.DisplayNameFor(model => model.Title)        </th>        <th>            @Html.DisplayNameFor(model => model.Price)        </th>        <th>            @Html.DisplayNameFor(model => model.AlbumArtUrl)        </th>        <th></th>    </tr>@foreach (var item in Model) {    <tr>        <td>            @Html.DisplayFor(modelItem => item.Artist.Name)        </td>        <td>            @Html.DisplayFor(modelItem => item.Genre.Name)        </td>        <td>            @Html.DisplayFor(modelItem => item.Title)        </td>        <td>            @Html.DisplayFor(modelItem => item.Price)        </td>        <td>            @Html.DisplayFor(modelItem => item.AlbumArtUrl)        </td>        <td>            @Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) |            @Html.ActionLink("Details", "Details", new { id=item.AlbumId }) |            @Html.ActionLink("Delete", "Delete", new { id=item.AlbumId })        </td>    </tr>}</table>


4、 执行基架代码

到目前为止尚为应用程序创建数据库,甚至尚为指定数据库链接。

(1)、用实体框架创建数据库

修改web.config

<configuration>  <connectionStrings>    <add name="MusicStoreDB" connectionString="Data Source=.;         Integrated Security=SSPI;initial catalog=MusicStore"      providerName="System.Data.SqlClient" />  </connectionStrings></configuration>
运行程序,浏览http://localhost:20168/StroreManager网址,就会自动创建数据库及表


EF会创建一个叫做__MigrationHistory的表来跟踪代码优先模型的状态,有助于让代码优先模型和数据库模型保持一致。
EF可以使用__MigrationHistory表中存储的信息来判断什么地方发生了变化,然后或者基于新模型重新创建数据库或抛出异常。
不必担心---EF不会在未经我们允许的情况下重新创建数据库;我们需要提供一个数据库初始化器,或者提供一次迁移

如果我们从数据库中删除__MigrationHistory表,我们将要负责数据库中的模式修改,使之匹配模型中变化。

(2)、使用数据库初始化器

保持数据库和模型变化同步的一个简单方法是允许实体框架重新创建一个现有的数据库。
可以告知EF在应用程序每次启动时重新创建数据库或者仅当检测到模型变化时重建数据库。

Global.asax


           //System.Data.Entity.SetInitializer数据库初始化            //每次启动时重建数据库            Database.SetInitializer(new DropCreateDatabaseAlways<MusicStoreDB>());            //模型改变时,重建数据库            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MusicStoreDB>());
为什么有人想在每次应用程序重新启动时,都重新创建数据库,尽管模型改变了,但是难道不想保留其中的数据吗?
在发布一个实际网站并且采用真实的客户信息之前,需要使用迁移,让EF代码优先模型与它们的数据库保持同步。
迁移允许在构建和优化模型定义时,保留数据库中的数据。

(3)、播种数据库

填充一些初始化记录

在Models文件夹中创建一个新的MusicStoreDbInitializer类继承System.Data.Entity.DropCreateDatabaseAlways<MusicStoreDB>,
重写Seed方法

    public class MusicStoreDbInitializer:System.Data.Entity.DropCreateDatabaseAlways<MusicStoreDB>    {        protected override void Seed(MusicStoreDB context)        {            context.Artists.Add(new Artist { Name="Al Di Meola"});            context.Genres.Add(new Genre { Name="Jazz"});            context.Albums.Add(new Album {                Artist = new Artist { Name="Rush"},                Genre = new Genre { Name="Rock"},                Price=9.9m,                Title="Caravan"            });            base.Seed(context);        }    }
修改Global.asax文件

Database.SetInitializer(new MusicStoreDbInitializer());

重新运行浏览器,导航到/StroreManager。会在数据库中插入数据。


注意:不会重新向数据库插入记录

三、 编辑专辑

1、 创建编辑专辑的资源
2、 响应编辑时的POST请求
四、 模型绑定
1、 DefaultModelBinder
2、 显式模型绑定
五、 小结
阅读全文
0 0
原创粉丝点击