3.0 update: intro to MVC/SQL (#13841)

* 3.0 update: intro to MVC/SQL

* 3.0 update: intro to MVC/SQL
pull/13845/head
Rick Anderson 2019-08-14 20:03:00 -04:00 committed by GitHub
parent 218d03bfe1
commit b65e16aed7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 470 additions and 12 deletions

View File

@ -0,0 +1,24 @@
#if Neve
// No includes so you get red lines
#region snippet_1
using System;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
#endregion
#endif

View File

@ -0,0 +1,26 @@
//#define First
#if First
#region snippet_1
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
#endregion
#endif

View File

@ -0,0 +1,26 @@
//#define MovieDateRating
#if MovieDateRating
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
#region snippet
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
public string Rating { get; set; }
}
#endregion
}
#endif

View File

@ -0,0 +1,41 @@
//#define MovieDateRatingDA
#if MovieDateRatingDA
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
#region snippet1
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
[Required]
public string Title { get; set; }
#region snippet2
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
#endregion
[RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$")]
[Required]
[StringLength(30)]
public string Genre { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
[StringLength(5)]
[Required]
public string Rating { get; set; }
}
#endregion
}
#endif

View File

@ -0,0 +1,32 @@
//#define COMBINED
#if COMBINED
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
#region snippet1
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"), DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z""'\s-]*$"), Required, StringLength(30)]
public string Genre { get; set; }
[Range(1, 100), DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
public string Rating { get; set; }
}
#endregion
}
#endif

View File

@ -0,0 +1,25 @@
#if AddDate
#region snippet_1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
#endregion
#endif

View File

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace MvcMovie.Models
{
public class MovieGenreViewModel
{
public List<Movie> Movies;
public SelectList Genres;
public string MovieGenre { get; set; }
public string SearchString { get; set; }
}
}

View File

@ -0,0 +1,68 @@
#define Rating
#if Rating
// Seed without Rating
#region snippet_1
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using MvcMovie.Data;
using System;
using System.Linq;
namespace MvcMovie.Models
{
public static class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = new MvcMovieContext(
serviceProvider.GetRequiredService<
DbContextOptions<MvcMovieContext>>()))
{
// Look for any movies.
if (context.Movie.Any())
{
return; // DB has been seeded
}
#region snippet1
context.Movie.AddRange(
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-2-12"),
Genre = "Romantic Comedy",
Price = 7.99M
},
#endregion
new Movie
{
Title = "Ghostbusters ",
ReleaseDate = DateTime.Parse("1984-3-13"),
Genre = "Comedy",
Price = 8.99M
},
new Movie
{
Title = "Ghostbusters 2",
ReleaseDate = DateTime.Parse("1986-2-23"),
Genre = "Comedy",
Price = 9.99M
},
new Movie
{
Title = "Rio Bravo",
ReleaseDate = DateTime.Parse("1959-4-15"),
Genre = "Western",
Price = 3.99M
}
);
context.SaveChanges();
}
}
}
}
#endregion
#endif

View File

@ -0,0 +1,69 @@
//#define Rating
#if Rating
#region snippet_1
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
namespace MvcMovie.Models
{
public static class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = new MvcMovieContext(
serviceProvider.GetRequiredService<DbContextOptions<MvcMovieContext>>()))
{
// Look for any movies.
if (context.Movie.Any())
{
return; // DB has been seeded
}
#region snippet1
context.Movie.AddRange(
new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-2-12"),
Genre = "Romantic Comedy",
Price = 7.99M,
Rating = "R"
},
#endregion
new Movie
{
Title = "Ghostbusters ",
ReleaseDate = DateTime.Parse("1984-3-13"),
Genre = "Comedy",
Price = 8.99M,
Rating = "G"
},
new Movie
{
Title = "Ghostbusters 2",
ReleaseDate = DateTime.Parse("1986-2-23"),
Genre = "Comedy",
Price = 9.99M,
Rating = "G"
},
new Movie
{
Title = "Rio Bravo",
ReleaseDate = DateTime.Parse("1959-4-15"),
Genre = "Western",
Price = 3.99M,
Rating = "NA"
}
);
context.SaveChanges();
}
}
}
}
#endregion
#endif

View File

@ -5,14 +5,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SQLite" Version="3.0.0-*" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0-preview7.19362.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0-preview7.19362.6">
<PackageReference Include="Microsoft.EntityFrameworkCore.SQLite" Version="3.0.0-preview8.19405.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0-preview8.19405.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0-preview8.19405.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0-preview7.19362.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0-preview7-19378-04" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0-preview8.19405.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0-preview8-19413-06" />
</ItemGroup>
</Project>

View File

@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MvcMovie.Data;
using MvcMovie.Models;
using System;
namespace MvcMovie
{
@ -13,7 +12,26 @@ namespace MvcMovie
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<MvcMovieContext>();
SeedData.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>

View File

@ -3,11 +3,125 @@ title: Work with SQL in an ASP.NET Core MVC app
author: rick-anderson
description: Learn about using SQL Server LocalDB or SQLite in a ASP.NET Core MVC app.
ms.author: riande
ms.date: 03/07/2017
ms.date: 8/16/2019
uid: tutorials/first-mvc-app/working-with-sql
---
# Work with SQL in ASP.NET Core
::: moniker range=">= aspnetcore-3.0"
By [Rick Anderson](https://twitter.com/RickAndMSFT)
The `MvcMovieContext` object handles the task of connecting to the database and mapping `Movie` objects to database records. The database context is registered with the [Dependency Injection](xref:fundamentals/dependency-injection) container in the `ConfigureServices` method in the *Startup.cs* file:
# [Visual Studio](#tab/visual-studio)
[!code-csharp[](~/tutorials/first-mvc-app/start-mvc/sample/MvcMovie3/Startup.cs?name=snippet_ConfigureServices&highlight=6-7)]
The ASP.NET Core [Configuration](xref:fundamentals/configuration/index) system reads the `ConnectionString`. For local development, it gets the connection string from the *appsettings.json* file:
[!code-json[](start-mvc/sample/MvcMovie/appsettings.json?highlight=2&range=8-10)]
# [Visual Studio Code / Visual Studio for Mac](#tab/visual-studio-code+visual-studio-mac)
[!code-csharp[](~/tutorials/first-mvc-app/start-mvc/sample/MvcMovie3/Startup.cs?name=snippet_UseSqlite&highlight=6-7)]
The ASP.NET Core [Configuration](xref:fundamentals/configuration/index) system reads the `ConnectionString`. For local development, it gets the connection string from the *appsettings.json* file:
[!code-json[](~/tutorials/first-mvc-app/start-mvc/sample/MvcMovie22/appsettingsSQLite.json?highlight=2&range=8-10)]
---
When the app is deployed to a test or production server, an environment variable can be used to set the connection string to a production SQL Server. See [Configuration](xref:fundamentals/configuration/index) for more information.
# [Visual Studio](#tab/visual-studio)
## SQL Server Express LocalDB
LocalDB is a lightweight version of the SQL Server Express Database Engine that's targeted for program development. LocalDB starts on demand and runs in user mode, so there's no complex configuration. By default, LocalDB database creates *.mdf* files in the *C:/Users/{user}* directory.
* From the **View** menu, open **SQL Server Object Explorer** (SSOX).
![View menu](working-with-sql/_static/ssox.png)
* Right click on the `Movie` table **> View Designer**
![Contextual menu open on Movie table](working-with-sql/_static/design.png)
![Movie table open in Designer](working-with-sql/_static/dv.png)
Note the key icon next to `ID`. By default, EF will make a property named `ID` the primary key.
* Right click on the `Movie` table **> View Data**
![Contextual menu open on Movie table](working-with-sql/_static/ssox2.png)
![Movie table open showing table data](working-with-sql/_static/vd22.png)
# [Visual Studio Code / Visual Studio for Mac](#tab/visual-studio-code+visual-studio-mac)
[!INCLUDE[](~/includes/rp/sqlite.md)]
[!INCLUDE[](~/includes/RP-mvc-shared/sqlite-warn.md)]
---
<!-- End of VS tabs -->
## Seed the database
Create a new class named `SeedData` in the *Models* folder. Replace the generated code with the following:
[!code-csharp[](~/tutorials/first-mvc-app/start-mvc/sample/MvcMovie22/Models/SeedData.cs?name=snippet_1)]
If there are any movies in the DB, the seed initializer returns and no movies are added.
```csharp
if (context.Movie.Any())
{
return; // DB has been seeded.
}
```
<a name="si"></a>
### Add the seed initializer
Replace the contents of *Program.cs* with the following code:
[!code-csharp[](~/tutorials/first-mvc-app/start-mvc/sample/MvcMovie22/Program.cs)]
Test the app
# [Visual Studio](#tab/visual-studio)
* Delete all the records in the DB. You can do this with the delete links in the browser or from SSOX.
* Force the app to initialize (call the methods in the `Startup` class) so the seed method runs. To force initialization, IIS Express must be stopped and restarted. You can do this with any of the following approaches:
* Right click the IIS Express system tray icon in the notification area and tap **Exit** or **Stop Site**
![IIS Express system tray icon](working-with-sql/_static/iisExIcon.png)
![Contextual menu](working-with-sql/_static/stopIIS.png)
* If you were running VS in non-debug mode, press F5 to run in debug mode
* If you were running VS in debug mode, stop the debugger and press F5
# [Visual Studio Code / Visual Studio for Mac](#tab/visual-studio-code+visual-studio-mac)
Delete all the records in the DB (So the seed method will run). Stop and start the app to seed the database.
---
The app shows the seeded data.
![MVC Movie application open in Microsoft Edge showing movie data](working-with-sql/_static/m55.png)
> [!div class="step-by-step"]
> [Previous](adding-model.md)
> [Next](controller-methods-views.md)
::: moniker-end
::: moniker range="< aspnetcore-3.0"
By [Rick Anderson](https://twitter.com/RickAndMSFT)
The `MvcMovieContext` object handles the task of connecting to the database and mapping `Movie` objects to database records. The database context is registered with the [Dependency Injection](xref:fundamentals/dependency-injection) container in the `ConfigureServices` method in the *Startup.cs* file:
@ -116,3 +230,5 @@ The app shows the seeded data.
> [!div class="step-by-step"]
> [Previous](adding-model.md)
> [Next](controller-methods-views.md)
::: moniker-end