Compare commits

..

4 Commits

Author SHA1 Message Date
jason-zhu 2b2f60b4eb Up to 2023-10-22 2023-10-22 12:15:29 +11:00
jason.zhu 4021889c65 Chap4: Scaffolding a Store Manager (add database initialization strategy) 2021-06-22 16:00:20 +10:00
jason.zhu 9b8dad3957 chap4: scafollding a store manager 2021-06-22 15:57:09 +10:00
jason.zhu 4943788e23 chap4.1: Modeling the Music Store 2021-06-22 15:00:03 +10:00
17 changed files with 624 additions and 12 deletions

View File

@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc;
using MvcMusicStore.Data;
namespace MvcMusicStore.Controllers
{
public class HomeController : Controller
{
public String Index()
public ActionResult Index()
{
return "I like cake!";
return View();
}
public ActionResult About()
@ -26,5 +23,10 @@ namespace MvcMusicStore.Controllers
return View();
}
//public ActionResult Search(string q)
//{
// var albums =
//}
}
}

View File

@ -0,0 +1,137 @@
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 MvcMusicStore.Data;
using MvcMusicStore.Models;
namespace MvcMusicStore.Controllers
{
public class StoreManagerController : Controller
{
private MusicStoreDB db = new MusicStoreDB();
// GET: StoreManager
public ActionResult Index()
{
var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre);
return View(albums.ToList());
}
// GET: StoreManager/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: StoreManager/Create
public ActionResult Create()
{
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name");
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name");
return View();
}
// POST: StoreManager/Create
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details see https://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: StoreManager/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: StoreManager/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details see https://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: StoreManager/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: StoreManager/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);
}
}
}

View File

@ -0,0 +1,52 @@
using MvcMusicStore.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace MvcMusicStore.Data
{
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
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; }
}
public class MusicStoreDbInitializer
: 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.99m,
Title = "Caravan"
});
base.Seed(context);
}
}
}

View File

@ -1,5 +1,7 @@
using System;
using MvcMusicStore.Data;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
@ -8,10 +10,13 @@ using System.Web.Routing;
namespace MvcMusicStore
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
Database.SetInitializer(new MusicStoreDbInitializer());
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcMusicStore.Models
{
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; }
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcMusicStore.Models
{
public class AlbumEditViewModel
{
public Album AlbumToEdit { get; set; }
public System.Web.Mvc.SelectList Genres { get; set; }
public System.Web.Mvc.SelectList Artists { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcMusicStore.Models
{
public class Artist
{
public virtual int ArtistId { get; set; }
public virtual string Name { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcMusicStore.Models
{
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; }
}
}

View File

@ -45,6 +45,12 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />
@ -122,9 +128,15 @@
<Compile Include="App_Start\RouteConfig.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\StoreController.cs" />
<Compile Include="Controllers\StoreManagerController.cs" />
<Compile Include="Data\MusicStoreDB.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Compile Include="Models\Album.cs" />
<Compile Include="Models\AlbumEditViewModel.cs" />
<Compile Include="Models\Artist.cs" />
<Compile Include="Models\Genre.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
@ -163,10 +175,14 @@
<Content Include="Views\Home\About.cshtml" />
<Content Include="Views\Home\Contact.cshtml" />
<Content Include="Views\Home\Index.cshtml" />
<Content Include="Views\StoreManager\Create.cshtml" />
<Content Include="Views\StoreManager\Delete.cshtml" />
<Content Include="Views\StoreManager\Details.cshtml" />
<Content Include="Views\StoreManager\Edit.cshtml" />
<Content Include="Views\StoreManager\Index.cshtml" />
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data\" />
<Folder Include="Models\" />
<Folder Include="Views\Store\" />
</ItemGroup>
<ItemGroup>

View File

@ -28,4 +28,9 @@
<p>You can easily find a web hosting company that offers the right mix of features and price for your applications.</p>
<p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301867">Learn more &raquo;</a></p>
</div>
</div>
</div>
<form action="/Home/Search" method="get">
<input type="text" name="q" />
<input type="submit" value="Search" />
</form>

View File

@ -0,0 +1,67 @@
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Album</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.GenreId, "GenreId", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("GenreId", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.GenreId, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ArtistId, "ArtistId", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("ArtistId", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.ArtistId, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.AlbumArtUrl, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.AlbumArtUrl, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.AlbumArtUrl, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>

View File

@ -0,0 +1,64 @@
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Album</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Artist.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Artist.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Genre.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Genre.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Title)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Price)
</dt>
<dd>
@Html.DisplayFor(model => model.Price)
</dd>
<dt>
@Html.DisplayNameFor(model => model.AlbumArtUrl)
</dt>
<dd>
@Html.DisplayFor(model => model.AlbumArtUrl)
</dd>
</dl>
@using (Html.BeginForm()) {
@Html.AntiForgeryToken()
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" /> |
@Html.ActionLink("Back to List", "Index")
</div>
}
</div>

View File

@ -0,0 +1,58 @@
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<div>
<h4>Album</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Artist.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Artist.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Genre.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Genre.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
@Html.DisplayFor(model => model.Title)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Price)
</dt>
<dd>
@Html.DisplayFor(model => model.Price)
</dd>
<dt>
@Html.DisplayNameFor(model => model.AlbumArtUrl)
</dt>
<dd>
@Html.DisplayFor(model => model.AlbumArtUrl)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.AlbumId }) |
@Html.ActionLink("Back to List", "Index")
</p>

View File

@ -0,0 +1,69 @@
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Album</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.AlbumId)
<div class="form-group">
@Html.LabelFor(model => model.GenreId, "GenreId", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("GenreId", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.GenreId, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ArtistId, "ArtistId", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("ArtistId", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.ArtistId, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.AlbumArtUrl, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.AlbumArtUrl, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.AlbumArtUrl, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>

View File

@ -0,0 +1,57 @@
@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>

View File

@ -1,9 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
https://go.microsoft.com/fwlink/?LinkId=301880
-->
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="MusicStoreDB" connectionString="Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=MusicStoreDB-20210622155056; Integrated Security=True; MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|MusicStoreDB-20210622155056.mdf"
providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
@ -30,7 +38,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
@ -52,4 +60,14 @@
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
</compilers>
</system.codedom>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>

View File

@ -2,6 +2,7 @@
<packages>
<package id="Antlr" version="3.5.0.2" targetFramework="net472" />
<package id="bootstrap" version="3.4.1" targetFramework="net472" />
<package id="EntityFramework" version="6.1.3" targetFramework="net472" />
<package id="jQuery" version="3.4.1" targetFramework="net472" />
<package id="jQuery.Validation" version="1.17.0" targetFramework="net472" />
<package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net472" />