Dela via


Del 4, lägg till en modell i en ASP.NET Core MVC-app

Note

Det här är inte den senaste versionen av den här artikeln. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Warning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Important

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Av Rick Anderson och Jon P Smith.

I den här självstudien har klasser lagts till för att hantera filmer i en databas. Dessa klasser är "Model"-delen av MVC-appen.

Dessa modellklasser används med Entity Framework Core (EF Core) för att arbeta med en databas. EF Core är ett ramverk för objektrelationsmappning (ORM) som förenklar den dataåtkomstkod som du måste skriva.

De modellklasser som skapas kallas POCO-klasser , från Plain Old CLR Objects. POCO-klasser har inget beroende av EF Core. De definierar bara egenskaperna för de data som ska lagras i databasen.

I den här självstudien skapas modellklasser först och EF Core skapar databasen.

Lägga till en datamodellklass

Högerklicka på mappen >Lägg till>klass. Ge filen namnet Movie.cs.

Uppdatera filen Models/Movie.cs med följande kod:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    public decimal Price { get; set; }
}

Klassen Movie innehåller ett Id fält som krävs av databasen för den primära nyckeln.

Attributet DataTypeReleaseDate anger typen av data (Date). Med det här attributet:

  • Användaren behöver inte ange tidsinformation i datumfältet.
  • Endast datumet visas, inte tidsinformation.

DataAnnotations behandlas i en senare handledning.

Frågetecknet efter string anger att egenskapen är null. För mer information, se nullbara referenstyper.

Lägga till NuGet-paket

Visual Studio installerar automatiskt de paket som krävs.

Skapa projektet som en kontroll av kompilatorfel.

Strukturera filmsidor

Använd verktyget scaffolding för att skapa Create, Read, Updateoch Delete (CRUD) sidor för filmmodellen.

Högerklicka på mappen Controllers i Solution Explorer och välj Lägg till > nytt autogenererat objekt.

vy över ovanstående steg

I dialogrutan Lägg till nytt scaffoldat objekt

  • I den vänstra rutan väljer du Installerad>gemensam>MVC.
  • Välj MVC-styrenhet med vyer med Entity Framework.
  • Välj Lägg till.

Lägg till stommens dialog

Slutför dialogrutan Lägg till MVC-styrenhet med vyer med hjälp av entitetsramverket :

  • I listrutan Modellklass väljer du Film (MvcMovie.Models).
  • I raden Datakontextklass väljer du tecknet + (plus).
    • I dialogrutan Lägg till datakontext genereras klassnamnet MvcMovie.Data.MvcMovieContext .
    • Välj Lägg till.
  • I listrutan Databasprovider väljer du SQL Server.
  • Vyer och kontrollantnamn: Behåll standardvärdet.
  • Välj Lägg till.

Lägg till datakontext behåll standardvärden

Om du får ett felmeddelande väljer du Lägg till en andra gång för att försöka igen.

Scaffolding lägger till följande paket:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Scaffolding skapar följande:

  • En filmkontroller: Controllers/MoviesController.cs
  • Razor visa filer för sidorna Skapa, Ta bort, Information, Redigera och Index : Views/Movies/*.cshtml
  • En databaskontextklass: Data/MvcMovieContext.cs

Scaffolding uppdaterar följande:

  • Infogar nödvändiga paketreferenser i MvcMovie.csproj projektfilen.
  • Registrerar databaskontexten Program.cs i filen.
  • Lägger till en databasanslutningssträng i appsettings.json filen.

Automatisk skapande av dessa filer och filuppdateringar kallas scaffolding.

Det går inte att använda de autogenererade sidorna ännu eftersom databasen inte finns. Om du kör appen och väljer länken Filmapp visas ett Felmeddelande om att det inte går att öppna databasen eller att det inte finns någon sådan tabell: Felmeddelande om film .

Skapa appen för att kontrollera att det inte finns några fel.

Inledande migrering

EF Core Använd migreringsfunktionen för att skapa databasen. Migreringar är en uppsättning verktyg som skapar och uppdaterar en databas som matchar datamodellen.

På menyn Verktyg väljer du NuGet Package Manager>Konsol.

I Package Manager Console (PMC) anger du följande kommando:

Add-Migration InitialCreate

  • Add-Migration InitialCreate: Skapar en Migrations/{timestamp}_InitialCreate.cs migreringsfil. Argumentet InitialCreate är migreringsnamnet. Valfritt namn kan användas, men enligt konventionen väljs ett namn som beskriver migreringen. Eftersom det här är den första migreringen innehåller den genererade klassen kod för att skapa databasschemat. Databasschemat baseras på den modell som anges i MvcMovieContext klassen.

Följande varning visas, som åtgärdas i ett senare steg:

Ingen butikstyp angavs för decimalegenskapen "Price" för entitetstypen "Film". Detta gör att värdena beskärs automatiskt om de inte får plats i standardprecisionen och skalan. Ange uttryckligen den SQL-serverkolumntyp som kan hantera alla värden i OnModelCreating med hjälp av "HasColumnType", ange precision och skalning med hjälp av "HasPrecision" eller konfigurera en värdekonverterare med hjälp av "HasConversion".

I PMC anger du följande kommando:

Update-Database

  • Update-Database: Uppdaterar databasen till den senaste migreringen, som föregående kommando skapade. Det här kommandot kör Up -metoden i Migrations/{time-stamp}_InitialCreate.cs filen, som skapar databasen.

Mer information om PMC-verktygen för EF Corefinns i verktygsreferensEF Core – PMC i Visual Studio.

Testa appen

Kör appen och välj länken Filmapp .

Om du får ett undantag som liknar följande kan du ha missat Update-Database kommandot i migreringssteget:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Note

Du kanske inte kan ange decimaltecken i fältet Price. För att stödja jQuery-validering för språk som inte är engelska och som använder kommatecken (",") för en decimalpunkt och för datumformat som inte är US-English måste appen globaliseras. Globaliseringsinstruktioner finns i det här GitHub-problemet.

Granska den genererade databaskontextklassen och registreringen

Med EF Coreutförs dataåtkomst med hjälp av en modell. En modell består av entitetsklasser och ett kontextobjekt som representerar en session med databasen. Med kontextobjektet kan du köra frågor mot och spara data. Databaskontexten härleds från Microsoft.EntityFrameworkCore.DbContext och anger de entiteter som ska ingå i datamodellen.

Byggnadsställningar skapar databaskontextklassen Data/MvcMovieContext.cs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

namespace MvcMovie.Data
{
    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext (DbContextOptions<MvcMovieContext> options)
            : base(options)
        {
        }

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; } = default!;
    }
}

Föregående kod skapar en DbSet<Movie-egenskap> som representerar filmerna i databasen.

Beroendeinsprutning

ASP.NET Core skapas med beroendeinmatning (DI). Tjänster, till exempel databaskontexten, registreras med DI i Program.cs. Dessa tjänster tillhandahålls till komponenter som kräver dem via konstruktorparametrar.

Controllers/MoviesController.cs I filen använder konstruktorn Dependency Injection för att injicera databaskontexten MvcMovieContext i kontrollern. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Scaffolding genererade följande markerade kod i Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext") ?? throw new InvalidOperationException("Connection string 'MvcMovieContext' not found.")));

Konfigurationssystemet ASP.NET Core läser databasanslutningssträngen "MvcMovieContext".

Granska den genererade databasanslutningssträngen

Scaffolding lade till en anslutningssträng i appsettings.json filen:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-4ebefa10-de29-4dea-b2ad-8a8dc6bcf374;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

För lokal utveckling läser konfigurationssystemet ASP.NET Core nyckeln från ConnectionString-filen.

Klassen InitialCreate

Granska migreringsfilen Migrations/{timestamp}_InitialCreate.cs :

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    /// <inheritdoc />
    public partial class InitialCreate : Migration
    {
        /// <inheritdoc />
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        /// <inheritdoc />
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

I koden ovan:

  • InitialCreate.Up skapar tabellen Film och konfigurerar Id som primär nyckel.
  • InitialCreate.Down återställer schemaändringarna som gjorts av migreringen Up .

Beroendeinmatning i kontrollanten

Controllers/MoviesController.cs Öppna filen och granska konstruktorn:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktorn använder beroendeinmatning för att mata in databaskontexten (MvcMovieContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Testa Skapa-sidan. Ange och skicka data.

Testa sidorna Redigera, Information och Ta bort .

Starkt skrivna modeller och @model direktivet

Tidigare i den här självstudien såg du hur en kontrollant kan skicka data eller objekt till en vy med hjälp av ViewData ordlistan. Ordlistan ViewData är ett dynamiskt objekt som ger ett bekvämt sent bundet sätt att skicka information till en vy.

MVC ger möjlighet att skicka starkt typerade modellobjekt till en vy. Med det här starkt typade tillvägagångssättet möjliggörs kompileringskontroll. Scaffolding-mekanismen överförde en starkt typad modell i klassen och vyerna i MoviesController.

Granska den genererade Details metoden i Controllers/MoviesController.cs filen:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametern id skickas vanligtvis som routningsdata. Till exempel https://localhost:{PORT}/movies/details/1 sätter:

  • Kontrollern till kontrollern movies, det första URL-segmentet.
  • Åtgärden för details, den andra URL-segmentet.
  • Från id till 1, det sista URL-segmentet.

id Kan skickas med en frågesträng, som i följande exempel:

https://localhost:{PORT}/movies/details?id=1

Parametern id definieras som en nullbar typ (int?) i de fall då id värdet inte anges.

Ett lambda-uttryck skickas till FirstOrDefaultAsync metoden för att välja filmentiteter som matchar routningsdata eller frågesträngsvärdet.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Om en film hittas skickas en instans av Movie modellen till Details vyn:

return View(movie);

Granska innehållet i Views/Movies/Details.cshtml filen:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instruktionen @model överst i vyfilen anger vilken typ av objekt som vyn förväntar sig. När filmkontrollanten skapades inkluderades följande @model instruktion:

@model MvcMovie.Models.Movie

Det här @model direktivet ger åtkomst till filmen som kontrollanten skickade till vyn. Objektet Model är starkt typat. I Details.cshtml-vyn skickar koden varje filmfält till DisplayNameFor och DisplayFor HTML-hjälpare med det starkt typerade Model-objektet. Metoderna Create och Edit vyerna skickar också ett Movie modellobjekt.

Granska Index.cshtml vyn och Index metoden i filmmodulens kontroll. Observera hur koden skapar ett List objekt när den anropar View metoden. Koden skickar den här Movies listan från Index åtgärdsmetoden till vyn:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Koden returnerar probleminformation om Movie egenskapen för datakontexten är null.

När filmkontrollern skapades innehöll scaffold följande @model sats överst i Index.cshtml filen.

@model IEnumerable<MvcMovie.Models.Movie>

Direktivet @model ger åtkomst till listan över filmer som kontrollanten skickade till vyn med hjälp av ett Model objekt som är starkt skrivet. I vyn loopar koden till exempel Index.cshtml igenom filmerna med en foreach instruktion över det starkt typerade Model objektet:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Eftersom objektet Model är starkt skrivet som ett IEnumerable<Movie> objekt, skrivs varje objekt i loopen som Movie. Kompilatorn validerar bland annat de typer som används i koden.

Ytterligare resurser

I den här självstudien har klasser lagts till för att hantera filmer i en databas. Dessa klasser är "Model"-delen av MVC-appen.

Dessa modellklasser används med Entity Framework Core (EF Core) för att arbeta med en databas. EF Core är ett ramverk för objektrelationsmappning (ORM) som förenklar den dataåtkomstkod som du måste skriva.

De modellklasser som skapas kallas POCO-klasser , från Plain Old CLR Objects. POCO-klasser har inget beroende av EF Core. De definierar bara egenskaperna för de data som ska lagras i databasen.

I den här självstudien skapas modellklasser först och EF Core skapar databasen.

Lägga till en datamodellklass

Högerklicka på mappen >Lägg till>klass. Ge filen namnet Movie.cs.

Uppdatera filen Models/Movie.cs med följande kod:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    public decimal Price { get; set; }
}

Klassen Movie innehåller ett Id fält som krävs av databasen för den primära nyckeln.

Attributet DataTypeReleaseDate anger typen av data (Date). Med det här attributet:

  • Användaren behöver inte ange tidsinformation i datumfältet.
  • Endast datumet visas, inte tidsinformation.

DataAnnotations behandlas i en senare handledning.

Frågetecknet efter string anger att egenskapen är null. För mer information, se nullbara referenstyper.

Lägga till NuGet-paket

Visual Studio installerar automatiskt de paket som krävs.

Skapa projektet som en kontroll av kompilatorfel.

Strukturera filmsidor

Använd verktyget scaffolding för att skapa Create, Read, Updateoch Delete (CRUD) sidor för filmmodellen.

Högerklicka på mappen Controllers i Solution Explorer och välj Lägg till > nytt autogenererat objekt.

vy över ovanstående steg

I dialogrutan Lägg till nytt scaffoldat objekt

  • I den vänstra rutan väljer du Installerad>gemensam>MVC.
  • Välj MVC-styrenhet med vyer med Entity Framework.
  • Välj Lägg till.

Lägg till stommens dialog

Slutför dialogrutan Lägg till MVC-styrenhet med vyer med hjälp av entitetsramverket :

  • I listrutan Modellklass väljer du Film (MvcMovie.Models).
  • I raden Datakontextklass väljer du tecknet + (plus).
    • I dialogrutan Lägg till datakontext genereras klassnamnet MvcMovie.Data.MvcMovieContext .
    • Välj Lägg till.
  • I listrutan Databasprovider väljer du SQL Server.
  • Vyer och kontrollantnamn: Behåll standardvärdet.
  • Välj Lägg till.

Lägg till datakontext behåll standardvärden

Om du får ett felmeddelande väljer du Lägg till en andra gång för att försöka igen.

Scaffolding lägger till följande paket:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Scaffolding skapar följande:

  • En filmkontroller: Controllers/MoviesController.cs
  • Razor visa filer för sidorna Skapa, Ta bort, Information, Redigera och Index : Views/Movies/*.cshtml
  • En databaskontextklass: Data/MvcMovieContext.cs

Scaffolding uppdaterar följande:

  • Infogar nödvändiga paketreferenser i MvcMovie.csproj projektfilen.
  • Registrerar databaskontexten Program.cs i filen.
  • Lägger till en databasanslutningssträng i appsettings.json filen.

Automatisk skapande av dessa filer och filuppdateringar kallas scaffolding.

Det går inte att använda de autogenererade sidorna ännu eftersom databasen inte finns. Om du kör appen och väljer länken Filmapp visas ett Felmeddelande om att det inte går att öppna databasen eller att det inte finns någon sådan tabell: Felmeddelande om film .

Skapa appen för att kontrollera att det inte finns några fel.

Inledande migrering

EF Core Använd migreringsfunktionen för att skapa databasen. Migreringar är en uppsättning verktyg som skapar och uppdaterar en databas som matchar datamodellen.

På menyn Verktyg väljer du NuGet Package Manager>Konsol.

I Package Manager Console (PMC) anger du följande kommandon:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Skapar en Migrations/{timestamp}_InitialCreate.cs migreringsfil. Argumentet InitialCreate är migreringsnamnet. Valfritt namn kan användas, men enligt konventionen väljs ett namn som beskriver migreringen. Eftersom det här är den första migreringen innehåller den genererade klassen kod för att skapa databasschemat. Databasschemat baseras på den modell som anges i MvcMovieContext klassen.

  • Update-Database: Uppdaterar databasen till den senaste migreringen, som föregående kommando skapade. Det här kommandot kör Up -metoden i Migrations/{time-stamp}_InitialCreate.cs filen, som skapar databasen.

Kommandot Update-Database genererar följande varning:

Ingen butikstyp angavs för decimalegenskapen "Price" för entitetstypen "Film". Detta gör att värdena beskärs automatiskt om de inte får plats i standardprecisionen och skalan. Ange uttryckligen den SQL-serverkolumntyp som kan hantera alla värden i OnModelCreating med hjälp av "HasColumnType", ange precision och skalning med hjälp av "HasPrecision" eller konfigurera en värdekonverterare med hjälp av "HasConversion".

Ignorera föregående varning, den åtgärdas i en senare handledning.

Mer information om PMC-verktygen för EF Corefinns i verktygsreferensEF Core – PMC i Visual Studio.

Testa appen

Kör appen och välj länken Filmapp .

Om du får ett undantag som liknar följande kan du ha missat Update-Database kommandot i migreringssteget:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Note

Du kanske inte kan ange decimaltecken i fältet Price. För att stödja jQuery-validering för språk som inte är engelska och som använder kommatecken (",") för en decimalpunkt och för datumformat som inte är US-English måste appen globaliseras. Globaliseringsinstruktioner finns i det här GitHub-problemet.

Granska den genererade databaskontextklassen och registreringen

Med EF Coreutförs dataåtkomst med hjälp av en modell. En modell består av entitetsklasser och ett kontextobjekt som representerar en session med databasen. Med kontextobjektet kan du köra frågor mot och spara data. Databaskontexten härleds från Microsoft.EntityFrameworkCore.DbContext och anger de entiteter som ska ingå i datamodellen.

Byggnadsställningar skapar databaskontextklassen Data/MvcMovieContext.cs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

namespace MvcMovie.Data
{
    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext (DbContextOptions<MvcMovieContext> options)
            : base(options)
        {
        }

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Föregående kod skapar en DbSet<Movie-egenskap> som representerar filmerna i databasen.

Beroendeinsprutning

ASP.NET Core skapas med beroendeinmatning (DI). Tjänster, till exempel databaskontexten, registreras med DI i Program.cs. Dessa tjänster tillhandahålls till komponenter som kräver dem via konstruktorparametrar.

Controllers/MoviesController.cs I filen använder konstruktorn Dependency Injection för att injicera databaskontexten MvcMovieContext i kontrollern. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Scaffolding genererade följande markerade kod i Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

Konfigurationssystemet ASP.NET Core läser databasanslutningssträngen "MvcMovieContext".

Granska den genererade databasanslutningssträngen

Scaffolding lade till en anslutningssträng i appsettings.json filen:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Data Source=MvcMovieContext-ea7a4069-f366-4742-bd1c-3f753a804ce1.db"
  }
}

För lokal utveckling läser konfigurationssystemet ASP.NET Core nyckeln från ConnectionString-filen.

Klassen InitialCreate

Granska migreringsfilen Migrations/{timestamp}_InitialCreate.cs :

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

I koden ovan:

  • InitialCreate.Up skapar tabellen Film och konfigurerar Id som primär nyckel.
  • InitialCreate.Down återställer schemaändringarna som gjorts av migreringen Up .

Beroendeinmatning i kontrollanten

Controllers/MoviesController.cs Öppna filen och granska konstruktorn:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktorn använder beroendeinmatning för att mata in databaskontexten (MvcMovieContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Testa Skapa-sidan. Ange och skicka data.

Testa sidorna Redigera, Information och Ta bort .

Starkt skrivna modeller och @model direktivet

Tidigare i den här självstudien såg du hur en kontrollant kan skicka data eller objekt till en vy med hjälp av ViewData ordlistan. Ordlistan ViewData är ett dynamiskt objekt som ger ett bekvämt sent bundet sätt att skicka information till en vy.

MVC ger möjlighet att skicka starkt typerade modellobjekt till en vy. Med det här starkt typade tillvägagångssättet möjliggörs kompileringskontroll. Scaffolding-mekanismen överförde en starkt typad modell i klassen och vyerna i MoviesController.

Granska den genererade Details metoden i Controllers/MoviesController.cs filen:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametern id skickas vanligtvis som routningsdata. Till exempel https://localhost:5001/movies/details/1 sätter:

  • Kontrollern till kontrollern movies, det första URL-segmentet.
  • Åtgärden för details, den andra URL-segmentet.
  • Från id till 1, det sista URL-segmentet.

id Kan skickas med en frågesträng, som i följande exempel:

https://localhost:5001/movies/details?id=1

Parametern id definieras som en nullbar typ (int?) i de fall då id värdet inte anges.

Ett lambda-uttryck skickas till FirstOrDefaultAsync metoden för att välja filmentiteter som matchar routningsdata eller frågesträngsvärdet.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Om en film hittas skickas en instans av Movie modellen till Details vyn:

return View(movie);

Granska innehållet i Views/Movies/Details.cshtml filen:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instruktionen @model överst i vyfilen anger vilken typ av objekt som vyn förväntar sig. När filmkontrollanten skapades inkluderades följande @model instruktion:

@model MvcMovie.Models.Movie

Det här @model direktivet ger åtkomst till filmen som kontrollanten skickade till vyn. Objektet Model är starkt typat. I Details.cshtml-vyn skickar koden varje filmfält till DisplayNameFor och DisplayFor HTML-hjälpare med det starkt typerade Model-objektet. Metoderna Create och Edit vyerna skickar också ett Movie modellobjekt.

Granska Index.cshtml vyn och Index metoden i filmmodulens kontroll. Observera hur koden skapar ett List objekt när den anropar View metoden. Koden skickar den här Movies listan från Index åtgärdsmetoden till vyn:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Koden returnerar probleminformation om Movie egenskapen för datakontexten är null.

När filmkontrollern skapades innehöll scaffold följande @model sats överst i Index.cshtml filen.

@model IEnumerable<MvcMovie.Models.Movie>

Direktivet @model ger åtkomst till listan över filmer som kontrollanten skickade till vyn med hjälp av ett Model objekt som är starkt skrivet. I vyn loopar koden till exempel Index.cshtml igenom filmerna med en foreach instruktion över det starkt typerade Model objektet:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Eftersom objektet Model är starkt skrivet som ett IEnumerable<Movie> objekt, skrivs varje objekt i loopen som Movie. Kompilatorn validerar bland annat de typer som används i koden.

Ytterligare resurser

I den här självstudien har klasser lagts till för att hantera filmer i en databas. Dessa klasser är "Model"-delen av MVC-appen.

Dessa modellklasser används med Entity Framework Core (EF Core) för att arbeta med en databas. EF Core är ett ramverk för objektrelationsmappning (ORM) som förenklar den dataåtkomstkod som du måste skriva.

De modellklasser som skapas kallas POCO-klasser , från Plain Old CLR Objects. POCO-klasser har inget beroende av EF Core. De definierar bara egenskaperna för de data som ska lagras i databasen.

I den här självstudien skapas modellklasser först och EF Core skapar databasen.

Lägga till en datamodellklass

Högerklicka på mappen >Lägg till>klass. Ge filen namnet Movie.cs.

Uppdatera filen Models/Movie.cs med följande kod:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    public decimal Price { get; set; }
}

Klassen Movie innehåller ett Id fält som krävs av databasen för den primära nyckeln.

Attributet DataTypeReleaseDate anger typen av data (Date). Med det här attributet:

  • Användaren behöver inte ange tidsinformation i datumfältet.
  • Endast datumet visas, inte tidsinformation.

DataAnnotations behandlas i en senare handledning.

Frågetecknet efter string anger att egenskapen är null. För mer information, se nullbara referenstyper.

Lägga till NuGet-paket

Visual Studio installerar automatiskt de paket som krävs.

Skapa projektet som en kontroll av kompilatorfel.

Strukturera filmsidor

Använd verktyget scaffolding för att skapa Create, Read, Updateoch Delete (CRUD) sidor för filmmodellen.

Högerklicka på mappen Controllers i Solution Explorer och välj Lägg till > nytt autogenererat objekt.

vy över ovanstående steg

I dialogrutan Lägg till nytt scaffoldat objekt

  • I den vänstra rutan väljer du Installerad>gemensam>MVC.
  • Välj MVC-styrenhet med vyer med Entity Framework.
  • Välj Lägg till.

Lägg till stommens dialog

Slutför dialogrutan Lägg till MVC-styrenhet med vyer med hjälp av entitetsramverket :

  • I listrutan Modellklass väljer du Film (MvcMovie.Models).
  • I raden Datakontextklass väljer du tecknet + (plus).
    • I dialogrutan Lägg till datakontext genereras klassnamnet MvcMovie.Data.MvcMovieContext .
    • Välj Lägg till.
  • I listrutan Databasprovider väljer du SQL Server.
  • Vyer och kontrollantnamn: Behåll standardvärdet.
  • Välj Lägg till.

Lägg till datakontext behåll standardvärden Om du får ett felmeddelande väljer du Lägg till en andra gång för att försöka igen.

Scaffolding lägger till följande paket:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Scaffolding skapar följande:

  • En filmkontroller: Controllers/MoviesController.cs
  • Razor visa filer för sidorna Skapa, Ta bort, Information, Redigera och Index : Views/Movies/*.cshtml
  • En databaskontextklass: Data/MvcMovieContext.cs

Scaffolding uppdaterar följande:

  • Infogar nödvändiga paketreferenser i MvcMovie.csproj projektfilen.
  • Registrerar databaskontexten Program.cs i filen.
  • Lägger till en databasanslutningssträng i appsettings.json filen.

Automatisk skapande av dessa filer och filuppdateringar kallas scaffolding.

Det går inte att använda de autogenererade sidorna ännu eftersom databasen inte finns. Om du kör appen och väljer länken Filmapp visas ett Felmeddelande om att det inte går att öppna databasen eller att det inte finns någon sådan tabell: Felmeddelande om film .

Skapa appen för att kontrollera att det inte finns några fel.

Inledande migrering

EF Core Använd migreringsfunktionen för att skapa databasen. Migreringar är en uppsättning verktyg som skapar och uppdaterar en databas som matchar datamodellen.

På menyn Verktyg väljer du NuGet Package Manager>Konsol.

I Package Manager Console (PMC) anger du följande kommandon:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Skapar en Migrations/{timestamp}_InitialCreate.cs migreringsfil. Argumentet InitialCreate är migreringsnamnet. Valfritt namn kan användas, men enligt konventionen väljs ett namn som beskriver migreringen. Eftersom det här är den första migreringen innehåller den genererade klassen kod för att skapa databasschemat. Databasschemat baseras på den modell som anges i MvcMovieContext klassen.

  • Update-Database: Uppdaterar databasen till den senaste migreringen, som föregående kommando skapade. Det här kommandot kör Up -metoden i Migrations/{time-stamp}_InitialCreate.cs filen, som skapar databasen.

Kommandot Update-Database genererar följande varning:

Ingen typ angavs för decimalkolumnen "Price" för entitetstypen "Film". Detta gör att värdena beskärs automatiskt om de inte får plats i standardprecisionen och skalan. Ange uttryckligen den SQL Server-kolumntyp som kan hantera alla värden med hjälp av "HasColumnType()".

Ignorera föregående varning, den åtgärdas i en senare handledning.

Mer information om PMC-verktygen för EF Corefinns i verktygsreferensEF Core – PMC i Visual Studio.

Testa appen

Kör appen och välj länken Filmapp .

Om du får ett undantag som liknar följande kan du ha missat Update-Database kommandot i migreringssteget:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Note

Du kanske inte kan ange decimaltecken i fältet Price. För att stödja jQuery-validering för språk som inte är engelska och som använder kommatecken (",") för en decimalpunkt och för datumformat som inte är US-English måste appen globaliseras. Globaliseringsinstruktioner finns i det här GitHub-problemet.

Granska den genererade databaskontextklassen och registreringen

Med EF Coreutförs dataåtkomst med hjälp av en modell. En modell består av entitetsklasser och ett kontextobjekt som representerar en session med databasen. Med kontextobjektet kan du köra frågor mot och spara data. Databaskontexten härleds från Microsoft.EntityFrameworkCore.DbContext och anger de entiteter som ska ingå i datamodellen.

Byggnadsställningar skapar databaskontextklassen Data/MvcMovieContext.cs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

namespace MvcMovie.Data
{
    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext (DbContextOptions<MvcMovieContext> options)
            : base(options)
        {
        }

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Föregående kod skapar en DbSet<Movie-egenskap> som representerar filmerna i databasen.

Beroendeinsprutning

ASP.NET Core skapas med beroendeinmatning (DI). Tjänster, till exempel databaskontexten, registreras med DI i Program.cs. Dessa tjänster tillhandahålls till komponenter som kräver dem via konstruktorparametrar.

Controllers/MoviesController.cs I filen använder konstruktorn Dependency Injection för att injicera databaskontexten MvcMovieContext i kontrollern. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Scaffolding genererade följande markerade kod i Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

Konfigurationssystemet ASP.NET Core läser databasanslutningssträngen "MvcMovieContext".

Granska den genererade databasanslutningssträngen

Scaffolding lade till en anslutningssträng i appsettings.json filen:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Data Source=MvcMovieContext-ea7a4069-f366-4742-bd1c-3f753a804ce1.db"
  }
}

För lokal utveckling läser konfigurationssystemet ASP.NET Core nyckeln från ConnectionString-filen.

Klassen InitialCreate

Granska migreringsfilen Migrations/{timestamp}_InitialCreate.cs :

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

I koden ovan:

  • InitialCreate.Up skapar tabellen Film och konfigurerar Id som primär nyckel.
  • InitialCreate.Down återställer schemaändringarna som gjorts av migreringen Up .

Beroendeinmatning i kontrollanten

Controllers/MoviesController.cs Öppna filen och granska konstruktorn:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktorn använder beroendeinmatning för att mata in databaskontexten (MvcMovieContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Testa Skapa-sidan. Ange och skicka data.

Testa sidorna Redigera, Information och Ta bort .

Starkt skrivna modeller och @model direktivet

Tidigare i den här självstudien såg du hur en kontrollant kan skicka data eller objekt till en vy med hjälp av ViewData ordlistan. Ordlistan ViewData är ett dynamiskt objekt som ger ett bekvämt sent bundet sätt att skicka information till en vy.

MVC ger möjlighet att skicka starkt typerade modellobjekt till en vy. Med det här starkt typade tillvägagångssättet möjliggörs kompileringskontroll. Scaffolding-mekanismen överförde en starkt typad modell i klassen och vyerna i MoviesController.

Granska den genererade Details metoden i Controllers/MoviesController.cs filen:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametern id skickas vanligtvis som routningsdata. Till exempel https://localhost:5001/movies/details/1 sätter:

  • Kontrollern till kontrollern movies, det första URL-segmentet.
  • Åtgärden för details, den andra URL-segmentet.
  • Från id till 1, det sista URL-segmentet.

id Kan skickas med en frågesträng, som i följande exempel:

https://localhost:5001/movies/details?id=1

Parametern id definieras som en nullbar typ (int?) i de fall då id värdet inte anges.

Ett lambda-uttryck skickas till FirstOrDefaultAsync metoden för att välja filmentiteter som matchar routningsdata eller frågesträngsvärdet.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Om en film hittas skickas en instans av Movie modellen till Details vyn:

return View(movie);

Granska innehållet i Views/Movies/Details.cshtml filen:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instruktionen @model överst i vyfilen anger vilken typ av objekt som vyn förväntar sig. När filmkontrollanten skapades inkluderades följande @model instruktion:

@model MvcMovie.Models.Movie

Det här @model direktivet ger åtkomst till filmen som kontrollanten skickade till vyn. Objektet Model är starkt typat. I Details.cshtml-vyn skickar koden varje filmfält till DisplayNameFor och DisplayFor HTML-hjälpare med det starkt typerade Model-objektet. Metoderna Create och Edit vyerna skickar också ett Movie modellobjekt.

Granska Index.cshtml vyn och Index metoden i filmmodulens kontroll. Observera hur koden skapar ett List objekt när den anropar View metoden. Koden skickar den här Movies listan från Index åtgärdsmetoden till vyn:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Koden returnerar probleminformation om Movie egenskapen för datakontexten är null.

När filmkontrollern skapades innehöll scaffold följande @model sats överst i Index.cshtml filen.

@model IEnumerable<MvcMovie.Models.Movie>

Direktivet @model ger åtkomst till listan över filmer som kontrollanten skickade till vyn med hjälp av ett Model objekt som är starkt skrivet. I vyn loopar koden till exempel Index.cshtml igenom filmerna med en foreach instruktion över det starkt typerade Model objektet:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Eftersom objektet Model är starkt skrivet som ett IEnumerable<Movie> objekt, skrivs varje objekt i loopen som Movie. Kompilatorn validerar bland annat de typer som används i koden.

Ytterligare resurser

I den här självstudien har klasser lagts till för att hantera filmer i en databas. Dessa klasser är "Model"-delen av MVC-appen.

Dessa modellklasser används med Entity Framework Core (EF Core) för att arbeta med en databas. EF Core är ett ramverk för objektrelationsmappning (ORM) som förenklar den dataåtkomstkod som du måste skriva.

De modellklasser som skapas kallas POCO-klasser , från Plain Old CLR Objects. POCO-klasser har inget beroende av EF Core. De definierar bara egenskaperna för de data som ska lagras i databasen.

I den här självstudien skapas modellklasser först och EF Core skapar databasen.

Lägga till en datamodellklass

Högerklicka på mappen >Lägg till>klass. Ge filen namnet Movie.cs.

Uppdatera filen Models/Movie.cs med följande kod:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string? Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string? Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Klassen Movie innehåller ett Id fält som krävs av databasen för den primära nyckeln.

Attributet DataTypeReleaseDate anger typen av data (Date). Med det här attributet:

  • Användaren behöver inte ange tidsinformation i datumfältet.
  • Endast datumet visas, inte tidsinformation.

DataAnnotations behandlas i en senare handledning.

Frågetecknet efter string anger att egenskapen är null. För mer information, se nullbara referenstyper.

Lägga till NuGet-paket

På menyn Verktyg väljer du NuGet Package Manager>Package Manager Console (PMC).

PMC-meny

Kör följande kommando i PMC:

Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.SqlServer

De föregående kommandona lägger till:

  • EF Core SQL Server-leverantören. Providerpaketet installerar EF Core paketet som ett beroende.
  • De verktyg som används av de paket som installeras automatiskt i scaffoldingssteget, senare i handledningen.

Skapa projektet som en kontroll av kompilatorfel.

Strukturera filmsidor

Använd verktyget scaffolding för att skapa Create, Read, Updateoch Delete (CRUD) sidor för filmmodellen.

Högerklicka på mappen Controllers i Solution Explorer och välj Lägg till > nytt autogenererat objekt.

vy över ovanstående steg

I dialogrutan Skapa mall väljer du MVC-kontroller med vyer och som använder Entity Framework > Lägg till.

Lägg till stommens dialog

Slutför dialogrutan Lägg till MVC-styrenhet med vyer med hjälp av entitetsramverket :

  • I listrutan Modellklass väljer du Film (MvcMovie.Models).
  • I raden Datakontextklass väljer du tecknet + (plus).
    • I dialogrutan Lägg till datakontext genereras klassnamnet MvcMovie.Data.MvcMovieContext .
    • Välj Lägg till.
  • Vyer och kontrollantnamn: Behåll standardvärdet.
  • Välj Lägg till.

Lägg till datakontext behåll standardvärden

Om du får ett felmeddelande väljer du Lägg till en andra gång för att försöka igen.

Scaffolding uppdaterar följande:

  • Infogar nödvändiga paketreferenser i MvcMovie.csproj projektfilen.
  • Registrerar databaskontexten Program.cs i filen.
  • Lägger till en databasanslutningssträng i appsettings.json filen.

Scaffolding skapar följande:

  • En filmkontroller: Controllers/MoviesController.cs
  • Razor visa filer för sidorna Skapa, Ta bort, Information, Redigera och Index : Views/Movies/*.cshtml
  • En databaskontextklass: Data/MvcMovieContext.cs

Automatisk skapande av dessa filer och filuppdateringar kallas scaffolding.

Det går inte att använda de autogenererade sidorna ännu eftersom databasen inte finns. Om du kör appen och väljer länken Filmapp visas ett Felmeddelande om att det inte går att öppna databasen eller att det inte finns någon sådan tabell: Felmeddelande om film .

Skapa appen

Skapa appen. Kompilatorn genererar flera varningar om hur null värden hanteras. Mer information finns i det här GitHub-problemet och referenstyper som kan ogiltigförklaras .

För att ta bort varningarna från nullbara referenstyper, ta bort följande rad från MvcMovie.csproj-filen:

<Nullable>enable</Nullable>

Vi hoppas kunna åtgärda problemet i nästa version.

Inledande migrering

EF Core Använd migreringsfunktionen för att skapa databasen. Migreringar är en uppsättning verktyg som skapar och uppdaterar en databas som matchar datamodellen.

På menyn Verktyg väljer du NuGet Package Manager>Konsol.

I Package Manager Console (PMC) anger du följande kommandon:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Skapar en Migrations/{timestamp}_InitialCreate.cs migreringsfil. Argumentet InitialCreate är migreringsnamnet. Valfritt namn kan användas, men enligt konventionen väljs ett namn som beskriver migreringen. Eftersom det här är den första migreringen innehåller den genererade klassen kod för att skapa databasschemat. Databasschemat baseras på den modell som anges i MvcMovieContext klassen.

  • Update-Database: Uppdaterar databasen till den senaste migreringen, som föregående kommando skapade. Det här kommandot kör Up -metoden i Migrations/{time-stamp}_InitialCreate.cs filen, som skapar databasen.

Kommandot Update-Database genererar följande varning:

Ingen typ angavs för decimalkolumnen "Price" för entitetstypen "Film". Detta gör att värdena beskärs automatiskt om de inte får plats i standardprecisionen och skalan. Ange uttryckligen den SQL Server-kolumntyp som kan hantera alla värden med hjälp av "HasColumnType()".

Ignorera föregående varning, den åtgärdas i en senare handledning.

Mer information om PMC-verktygen för EF Corefinns i verktygsreferensEF Core – PMC i Visual Studio.

Testa appen

Kör appen och välj länken Filmapp .

Om du får ett undantag som liknar följande kan du ha missat migreringssteget:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Note

Du kanske inte kan ange decimaltecken i fältet Price. För att stödja jQuery-validering för språk som inte är engelska och som använder kommatecken (",") för en decimalpunkt och för datumformat som inte är US-English måste appen globaliseras. Globaliseringsinstruktioner finns i det här GitHub-problemet.

Granska den genererade databaskontextklassen och registreringen

Med EF Coreutförs dataåtkomst med hjälp av en modell. En modell består av entitetsklasser och ett kontextobjekt som representerar en session med databasen. Med kontextobjektet kan du köra frågor mot och spara data. Databaskontexten härleds från Microsoft.EntityFrameworkCore.DbContext och anger de entiteter som ska ingå i datamodellen.

Byggnadsställningar skapar databaskontextklassen Data/MvcMovieContext.cs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

namespace MvcMovie.Data
{
    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext (DbContextOptions<MvcMovieContext> options)
            : base(options)
        {
        }

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Föregående kod skapar en DbSet<Movie-egenskap> som representerar filmerna i databasen.

Beroendeinsprutning

ASP.NET Core skapas med beroendeinmatning (DI). Tjänster, till exempel databaskontexten, registreras med DI i Program.cs. Dessa tjänster tillhandahålls till komponenter som kräver dem via konstruktorparametrar.

Controllers/MoviesController.cs I filen använder konstruktorn Dependency Injection för att injicera databaskontexten MvcMovieContext i kontrollern. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Scaffolding genererade följande markerade kod i Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

Konfigurationssystemet ASP.NET Core läser databasanslutningssträngen "MvcMovieContext".

Granska den genererade databasanslutningssträngen

Scaffolding lade till en anslutningssträng i appsettings.json filen:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-7dc5;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

För lokal utveckling läser konfigurationssystemet ASP.NET Core nyckeln från ConnectionString-filen.

Klassen InitialCreate

Granska migreringsfilen Migrations/{timestamp}_InitialCreate.cs :

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

I koden ovan:

  • InitialCreate.Up skapar tabellen Film och konfigurerar Id som primär nyckel.
  • InitialCreate.Down återställer schemaändringarna som gjorts av migreringen Up .

Beroendeinmatning i kontrollanten

Controllers/MoviesController.cs Öppna filen och granska konstruktorn:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktorn använder beroendeinmatning för att mata in databaskontexten (MvcMovieContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Testa Skapa-sidan. Ange och skicka data.

Testa sidorna Redigera, Information och Ta bort .

Starkt skrivna modeller och @model direktivet

Tidigare i den här självstudien såg du hur en kontrollant kan skicka data eller objekt till en vy med hjälp av ViewData ordlistan. Ordlistan ViewData är ett dynamiskt objekt som ger ett bekvämt sent bundet sätt att skicka information till en vy.

MVC ger möjlighet att skicka starkt typerade modellobjekt till en vy. Med det här starkt typade tillvägagångssättet möjliggörs kompileringskontroll. Scaffolding-mekanismen överförde en starkt typad modell i klassen och vyerna i MoviesController.

Granska den genererade Details metoden i Controllers/MoviesController.cs filen:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametern id skickas vanligtvis som routningsdata. Till exempel https://localhost:5001/movies/details/1 sätter:

  • Kontrollern till kontrollern movies, det första URL-segmentet.
  • Åtgärden för details, den andra URL-segmentet.
  • Från id till 1, det sista URL-segmentet.

id Kan skickas med en frågesträng, som i följande exempel:

https://localhost:5001/movies/details?id=1

Parametern id definieras som en nullbar typ (int?) i de fall då id värdet inte anges.

Ett lambda-uttryck skickas till FirstOrDefaultAsync metoden för att välja filmentiteter som matchar routningsdata eller frågesträngsvärdet.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Om en film hittas skickas en instans av Movie modellen till Details vyn:

return View(movie);

Granska innehållet i Views/Movies/Details.cshtml filen:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instruktionen @model överst i vyfilen anger vilken typ av objekt som vyn förväntar sig. När filmkontrollanten skapades inkluderades följande @model instruktion:

@model MvcMovie.Models.Movie

Det här @model direktivet ger åtkomst till filmen som kontrollanten skickade till vyn. Objektet Model är starkt typat. I Details.cshtml-vyn skickar koden varje filmfält till DisplayNameFor och DisplayFor HTML-hjälpare med det starkt typerade Model-objektet. Metoderna Create och Edit vyerna skickar också ett Movie modellobjekt.

Granska Index.cshtml vyn och Index metoden i filmmodulens kontroll. Observera hur koden skapar ett List objekt när den anropar View metoden. Koden skickar den här Movies listan från Index åtgärdsmetoden till vyn:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

När filmkontrollern skapades innehöll scaffold följande @model sats överst i Index.cshtml filen.

@model IEnumerable<MvcMovie.Models.Movie>

Direktivet @model ger åtkomst till listan över filmer som kontrollanten skickade till vyn med hjälp av ett Model objekt som är starkt skrivet. I vyn loopar koden till exempel Index.cshtml igenom filmerna med en foreach instruktion över det starkt typerade Model objektet:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Eftersom objektet Model är starkt skrivet som ett IEnumerable<Movie> objekt, skrivs varje objekt i loopen som Movie. Kompilatorn validerar bland annat de typer som används i koden.

Ytterligare resurser

I den här självstudien har klasser lagts till för att hantera filmer i en databas. Dessa klasser är "Model"-delen av MVC-appen.

Dessa modellklasser används med Entity Framework Core (EF Core) för att arbeta med en databas. EF Core är ett ramverk för objektrelationsmappning (ORM) som förenklar den dataåtkomstkod som du måste skriva.

De modellklasser som skapas kallas POCO-klasser , från Plain Old CLR Objects. POCO-klasser har inget beroende av EF Core. De definierar bara egenskaperna för de data som ska lagras i databasen.

I den här självstudien skapas modellklasser först och EF Core skapar databasen.

Lägga till en datamodellklass

Högerklicka på mappen >Lägg till>klass. Ge filen namnet Movie.cs.

Uppdatera filen Models/Movie.cs med följande kod:

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Klassen Movie innehåller ett Id fält som krävs av databasen för den primära nyckeln.

Attributet DataTypeReleaseDate anger typen av data (Date). Med det här attributet:

  • Användaren behöver inte ange tidsinformation i datumfältet.
  • Endast datumet visas, inte tidsinformation.

DataAnnotations behandlas i en senare handledning.

Lägga till NuGet-paket

På menyn Verktyg väljer du NuGet Package Manager>Package Manager Console (PMC).

PMC-meny

Kör följande kommando i PMC:

Install-Package Microsoft.EntityFrameworkCore.Design

De föregående kommandona lägger till:

  • EF Core SQL Server-leverantören. Providerpaketet installerar EF Core paketet som ett beroende.
  • De verktyg som används av de paket som installeras automatiskt i scaffoldingssteget, senare i handledningen.

Skapa projektet som en kontroll av kompilatorfel.

Strukturera filmsidor

Använd verktyget scaffolding för att skapa Create, Read, Updateoch Delete (CRUD) sidor för filmmodellen.

Högerklicka på mappen Controllers i Solution Explorer och välj Lägg till > nytt autogenererat objekt.

vy över ovanstående steg

I dialogrutan Skapa mall väljer du MVC-kontroller med vyer och som använder Entity Framework > Lägg till.

Lägg till stommens dialog

Slutför dialogrutan Lägg till MVC-styrenhet med vyer med hjälp av entitetsramverket :

  • I listrutan Modellklass väljer du Film (MvcMovie.Models).
  • I raden Datakontextklass väljer du tecknet + (plus).
    • I dialogrutan Lägg till datakontext genereras klassnamnet MvcMovie.Data.MvcMovieContext .
    • Välj Lägg till.
  • Vyer och kontrollantnamn: Behåll standardvärdet.
  • Välj Lägg till.

Lägg till datakontext behåll standardvärden

Scaffolding uppdaterar följande:

  • Infogar nödvändiga paketreferenser i MvcMovie.csproj projektfilen.
  • Registrerar databaskontexten Startup.ConfigureServices i Startup.cs filen.
  • Lägger till en databasanslutningssträng i appsettings.json filen.

Scaffolding skapar följande:

  • En filmkontroller: Controllers/MoviesController.cs
  • Razor visa filer för sidorna Skapa, Ta bort, Information, Redigera och Index : Views/Movies/*.cshtml
  • En databaskontextklass: Data/MvcMovieContext.cs

Automatisk skapande av dessa filer och filuppdateringar kallas för strukturskapande.

Det går inte att använda de autogenererade sidorna ännu eftersom databasen inte finns. Om du kör appen och väljer länken Filmapp visas ett Felmeddelande om att det inte går att öppna databasen eller att det inte finns någon sådan tabell: Felmeddelande om film .

Inledande migrering

EF Core Använd migreringsfunktionen för att skapa databasen. Migreringar är en uppsättning verktyg som skapar och uppdaterar en databas för att matcha datamodellen.

På menyn Verktyg väljer du NuGet Package Manager>Konsol.

I Package Manager Console (PMC) anger du följande kommandon:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Skapar en Migrations/{timestamp}_InitialCreate.cs migreringsfil. Argumentet InitialCreate är migreringsnamnet. Valfritt namn kan användas, men enligt konventionen väljs ett namn som beskriver migreringen. Eftersom det här är den första migreringen innehåller den genererade klassen kod för att skapa databasschemat. Databasschemat baseras på den modell som anges i MvcMovieContext klassen.

  • Update-Database: Uppdaterar databasen till den senaste migreringen, som föregående kommando skapade. Det här kommandot kör Up -metoden i Migrations/{time-stamp}_InitialCreate.cs filen, som skapar databasen.

Kommandot Update-Database genererar följande varning:

Ingen typ angavs för decimalkolumnen "Price" för entitetstypen "Film". Detta gör att värdena beskärs automatiskt om de inte får plats i standardprecisionen och skalan. Ange uttryckligen den SQL Server-kolumntyp som kan hantera alla värden med hjälp av "HasColumnType()".

Ignorera föregående varning, den åtgärdas i en senare handledning.

Mer information om PMC-verktygen för EF Corefinns i verktygsreferensEF Core – PMC i Visual Studio.

Testa appen

Kör appen och välj länken Filmapp .

Om du får ett undantag som liknar följande kan du ha missat migreringssteget:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Note

Du kanske inte kan ange decimaltecken i fältet Price. För att stödja jQuery-validering för språk som inte är engelska och som använder kommatecken (",") för en decimalpunkt och för datumformat som inte är US-English måste appen globaliseras. Globaliseringsinstruktioner finns i det här GitHub-problemet.

Granska den genererade databaskontextklassen och registreringen

Med EF Coreutförs dataåtkomst med hjälp av en modell. En modell består av entitetsklasser och ett kontextobjekt som representerar en session med databasen. Med kontextobjektet kan du köra frågor mot och spara data. Databaskontexten härleds från Microsoft.EntityFrameworkCore.DbContext och anger de entiteter som ska ingå i datamodellen.

Byggnadsställningar skapar databaskontextklassen Data/MvcMovieContext.cs :

using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

namespace MvcMovie.Data
{
    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext (DbContextOptions<MvcMovieContext> options)
            : base(options)
        {
        }

        public DbSet<Movie> Movie { get; set; }
    }
}

Föregående kod skapar en DbSet<Movie-egenskap> som representerar filmerna i databasen.

ASP.NET Core skapas med beroendeinmatning (DI). Tjänster, till exempel databaskontexten, måste registreras med DI i Startup. Komponenter som kräver dessa tjänster tillhandahålls via konstruktorparametrar.

Controllers/MoviesController.cs I filen använder konstruktorn Dependency Injection för att injicera databaskontexten MvcMovieContext i kontrollern. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Scaffolding genererade följande markerade kod i Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext")));
}

Konfigurationssystemet ASP.NET Core läser databasanslutningssträngen "MvcMovieContext".

Granska den genererade databasanslutningssträngen

Scaffolding lade till en anslutningssträng i appsettings.json filen:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

För lokal utveckling läser konfigurationssystemet ASP.NET Core nyckeln från ConnectionString-filen.

Klassen InitialCreate

Granska migreringsfilen Migrations/{timestamp}_InitialCreate.cs :

public partial class InitialCreate : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Movie",
            columns: table => new
            {
                Id = table.Column<int>(type: "int", nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Movie", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Movie");
    }
}

I koden ovan:

  • InitialCreate.Up skapar tabellen Film och konfigurerar Id som primär nyckel.
  • InitialCreate.Down återställer schemaändringarna som gjorts av migreringen Up .

Beroendeinmatning i kontrollanten

Controllers/MoviesController.cs Öppna filen och granska konstruktorn:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktorn använder beroendeinmatning för att mata in databaskontexten (MvcMovieContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Testa Skapa-sidan. Ange och skicka data.

Testa sidorna Redigera, Information och Ta bort .

Starkt skrivna modeller och @model direktivet

Tidigare i den här självstudien såg du hur en kontrollant kan skicka data eller objekt till en vy med hjälp av ViewData ordlistan. Ordlistan ViewData är ett dynamiskt objekt som ger ett bekvämt sent bundet sätt att skicka information till en vy.

MVC ger möjlighet att skicka starkt typerade modellobjekt till en vy. Med det här starkt typade tillvägagångssättet möjliggörs kompileringskontroll. Scaffolding-mekanismen överförde en starkt typad modell i klassen och vyerna i MoviesController.

Granska den genererade Details metoden i Controllers/MoviesController.cs filen:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametern id skickas vanligtvis som routningsdata. Till exempel https://localhost:5001/movies/details/1 sätter:

  • Kontrollern till kontrollern movies, det första URL-segmentet.
  • Åtgärden för details, den andra URL-segmentet.
  • Från id till 1, det sista URL-segmentet.

id Kan skickas med en frågesträng, som i följande exempel:

https://localhost:5001/movies/details?id=1

Parametern id definieras som en nullbar typ (int?) i de fall då id värdet inte anges.

Ett lambda-uttryck skickas till FirstOrDefaultAsync metoden för att välja filmentiteter som matchar routningsdata eller frågesträngsvärdet.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Om en film hittas skickas en instans av Movie modellen till Details vyn:

return View(movie);

Granska innehållet i Views/Movies/Details.cshtml filen:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instruktionen @model överst i vyfilen anger vilken typ av objekt som vyn förväntar sig. När filmkontrollanten skapades inkluderades följande @model instruktion:

@model MvcMovie.Models.Movie

Det här @model direktivet ger åtkomst till filmen som kontrollanten skickade till vyn. Objektet Model är starkt typat. I Details.cshtml-vyn skickar koden varje filmfält till DisplayNameFor och DisplayFor HTML-hjälpare med det starkt typerade Model-objektet. Metoderna Create och Edit vyerna skickar också ett Movie modellobjekt.

Granska Index.cshtml vyn och Index metoden i filmmodulens kontroll. Observera hur koden skapar ett List objekt när den anropar View metoden. Koden skickar den här Movies listan från Index åtgärdsmetoden till vyn:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

När filmkontrollern skapades innehöll scaffold följande @model sats överst i Index.cshtml filen.

@model IEnumerable<MvcMovie.Models.Movie>

Direktivet @model ger åtkomst till listan över filmer som kontrollanten skickade till vyn med hjälp av ett Model objekt som är starkt skrivet. I vyn loopar koden till exempel Index.cshtml igenom filmerna med en foreach instruktion över det starkt typerade Model objektet:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Eftersom objektet Model är starkt skrivet som ett IEnumerable<Movie> objekt, skrivs varje objekt i loopen som Movie. Kompilatorn validerar bland annat de typer som används i koden.

SQL-loggning av Entity Framework Core

Loggningskonfiguration tillhandahålls ofta av avsnittet Logging i appsettings.{Environment}.json filer. Om du vill logga SQL-instruktioner lägger du till "Microsoft.EntityFrameworkCore.Database.Command": "Information" i filen appsettings.Development.json:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDB-2;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
     ,"Microsoft.EntityFrameworkCore.Database.Command": "Information"
    }
  },
  "AllowedHosts": "*"
}

Med föregående JSON visas SQL-uttryck på kommandoraden och i Visual Studio-utdatafönstret.

Mer information finns i Loggning i .NET och ASP.NET Core och det här GitHub-problemet.

Ytterligare resurser

I den här självstudien har klasser lagts till för att hantera filmer i en databas. Dessa klasser är "Model"-delen av MVC-appen.

Dessa modellklasser används med Entity Framework Core (EF Core) för att arbeta med en databas. EF Core är ett ramverk för objektrelationsmappning (ORM) som förenklar den dataåtkomstkod som du måste skriva.

De modellklasser som skapas kallas POCO-klasser , från Plain Old CLR Objects. POCO-klasser har inget beroende av EF Core. De definierar bara egenskaperna för de data som ska lagras i databasen.

I den här självstudien skapas modellklasser först och EF Core skapar databasen.

Lägga till en datamodellklass

Högerklicka på mappen >Lägg till>klass. Ge filen namnet Movie.cs.

Uppdatera filen Movie.cs med följande kod:

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Klassen Movie innehåller ett Id fält som krävs av databasen för den primära nyckeln.

Attributet DataTypeReleaseDate anger typen av data (Date). Med det här attributet:

  • Användaren behöver inte ange tidsinformation i datumfältet.
  • Endast datumet visas, inte tidsinformation.

DataAnnotations behandlas i en senare handledning.

Lägga till NuGet-paket

På menyn Verktyg väljer du NuGet Package Manager>Package Manager Console (PMC).

PMC-meny

Kör följande kommando i PMC:

Install-Package Microsoft.EntityFrameworkCore.SqlServer

Föregående kommando lägger till EF Core SQL Server-providern. Providerpaketet installerar EF Core paketet som ett beroende. Ytterligare paket installeras automatiskt i scaffoldingssteget senare i självstudien.

Skapa en databaskontextklass

En databaskontextklass krävs för att samordna EF Core funktioner (Skapa, Läsa, Uppdatera, Ta bort) för Movie modellen. Databaskontexten härleds från Microsoft.EntityFrameworkCore.DbContext och anger de entiteter som ska ingå i datamodellen.

Skapa en datamapp.

Lägg till en Data/MvcMovieContext.cs fil med följande kod:

using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

namespace MvcMovie.Data
{
    public class MvcMovieContext : DbContext
    {
        public MvcMovieContext (DbContextOptions<MvcMovieContext> options)
            : base(options)
        {
        }

        public DbSet<Movie> Movie { get; set; }
    }
}

Föregående kod skapar egenskapen DbSet<Movie> för entitetsuppsättningen. I Entity Framework-terminologi motsvarar en entitetsuppsättning vanligtvis en databastabell. En entitet motsvarar en rad i tabellen.

Registrera databaskontexten

ASP.NET Core skapas med beroendeinmatning (DI). Tjänster (till exempel DB-kontexten EF Core ) måste registreras med DI under programstarten. Komponenter som kräver dessa tjänster (till exempel Razor Pages) tillhandahålls via konstruktorparametrar. Konstruktorkoden som hämtar en DB-kontextinstans visas senare i självstudien. I det här avsnittet registrerar du databaskontexten med DI-containern.

Lägg till följande using-instruktioner högst upp i Startup.cs:

using MvcMovie.Data;
using Microsoft.EntityFrameworkCore;

Lägg till följande markerade kod i Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext")));
}

Namnet på anslutningssträngen skickas till kontexten genom att anropa en metod för ett DbContextOptions-objekt. För lokal utveckling läser konfigurationssystemet ASP.NET Core anslutningssträngen appsettings.json från filen.

Granska databasanslutningssträngen

Lägg till en anslutningssträng i appsettings.json filen:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

Skapa projektet som en kontroll av kompilatorfel.

Strukturera filmsidor

Använd verktyget scaffolding för att skapa CRUD-sidor (Create, Read, Update och Delete) för filmmodellen.

I Solution Explorer högerklickar du på mappen Controllers och väljer >.

vy över ovanstående steg

I dialogrutan Skapa mall väljer du MVC-kontroller med vyer och som använder Entity Framework > Lägg till.

Lägg till stommens dialog

Slutför dialogrutan Lägg till kontrollant :

  • Modellklass:Film (MvcMovie.Models)
  • Datakontextklass:MvcMovieContext (MvcMovie.Data)

Lägg till datakontext

  • Visningar: Behåll standardvärdet för varje alternativ markerat
  • Kontrollernamn: Behåll MoviesController (standard)
  • Välj Lägg till

Visual Studio skapar:

  • En filmkontrollant (Controllers/MoviesController.cs)
  • Razor visa filer för Skapa, Ta bort, Detaljer, Redigera och Index-sidor (*Views/Movies/`.cshtml`)

Automatisk skapande av dessa filer kallas stomme.

Du kan inte använda de genererade sidorna ännu eftersom databasen inte finns. Om du kör appen och klickar på länken Filmapp får du ett felmeddelande om att det inte går att öppna databasen eller att det inte finns någon sådan tabell: Felmeddelande om film .

Inledande migrering

EF Core Använd migreringsfunktionen för att skapa databasen. Migreringar är en uppsättning verktyg som gör att du kan skapa och uppdatera en databas så att den matchar din datamodell.

På menyn Verktyg väljer du NuGet Package Manager>Package Manager Console (PMC).

I PMC anger du följande kommandon:

Add-Migration InitialCreate
Update-Database
  • Add-Migration InitialCreate: Skapar en Migrations/{timestamp}_InitialCreate.cs migreringsfil. Argumentet InitialCreate är migreringsnamnet. Valfritt namn kan användas, men enligt konventionen väljs ett namn som beskriver migreringen. Eftersom det här är den första migreringen innehåller den genererade klassen kod för att skapa databasschemat. Databasschemat baseras på den modell som anges i MvcMovieContext klassen.

  • Update-Database: Uppdaterar databasen till den senaste migreringen, som föregående kommando skapade. Det här kommandot kör Up -metoden i Migrations/{time-stamp}_InitialCreate.cs filen, som skapar databasen.

    Kommandot för databasuppdatering genererar följande varning:

    Ingen typ angavs för decimalkolumnen "Price" för entitetstypen "Film". Detta gör att värdena beskärs automatiskt om de inte får plats i standardprecisionen och skalan. Ange uttryckligen den SQL Server-kolumntyp som kan hantera alla värden med hjälp av "HasColumnType()".

    Du kan ignorera den varningen. Den kommer att åtgärdas i en senare handledning.

Mer information om PMC-verktygen för EF Corefinns i verktygsreferensEF Core – PMC i Visual Studio.

Klassen InitialCreate

Granska migreringsfilen Migrations/{timestamp}_InitialCreate.cs :

public partial class InitialCreate : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Movie",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", 
                                 SqlServerValueGenerationStrategy.IdentityColumn),
                Title = table.Column<string>(nullable: true),
                ReleaseDate = table.Column<DateTime>(nullable: false),
                Genre = table.Column<string>(nullable: true),
                Price = table.Column<decimal>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Movie", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Movie");
    }
}

Metoden Up skapar tabellen Film och konfigurerar Id som primärnyckel. Metoden Down återställer schemaändringarna som gjorts av migreringen Up .

Testa appen

  • Kör appen och klicka på länken Filmapp .

    Om du får ett undantag som liknar något av följande:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Du missade förmodligen migreringssteget.

  • Testa Skapa-sidan. Ange och skicka data.

    Note

    Du kanske inte kan ange decimaltecken i fältet Price. För att stödja jQuery-validering för språk som inte är engelska och som använder kommatecken (",") för en decimalpunkt och för datumformat som inte är US-English måste appen globaliseras. Globaliseringsinstruktioner finns i det här GitHub-problemet.

  • Testa sidorna Redigera, Information och Ta bort .

Beroendeinmatning i kontrollanten

Controllers/MoviesController.cs Öppna filen och granska konstruktorn:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktorn använder beroendeinmatning för att mata in databaskontexten (MvcMovieContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

Starkt skrivna modeller och nyckelordet @model

Tidigare i den här självstudien såg du hur en kontrollant kan skicka data eller objekt till en vy med hjälp av ViewData ordlistan. Ordlistan ViewData är ett dynamiskt objekt som ger ett bekvämt sent bundet sätt att skicka information till en vy.

MVC ger också möjlighet att skicka starkt typerade modellobjekt till en vy. Med det här starkt typade tillvägagångssättet möjliggörs kompileringskontroll. Scaffoldingsystemet använde den här metoden (dvs. att skicka en starkt typad modell) med MoviesController-klassen och vyerna.

Granska den genererade Details metoden i Controllers/MoviesController.cs filen:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametern id skickas vanligtvis som routningsdata. https://localhost:5001/movies/details/1 Exempeluppsättningar:

  • Kontrollern till kontroller movies (det första URL-segmentet).
  • Åtgärden för details (det andra URL-segmentet).
  • ID:t till 1 (det sista URL-segmentet).

Du kan också skicka in id med en frågesträng på följande sätt:

https://localhost:5001/movies/details?id=1

Parametern id definieras som en nullbar typ (int?) om ett ID-värde inte anges.

Ett lambda-uttryck skickas till FirstOrDefaultAsync för att välja filmentiteter som matchar routedata eller frågesträngsvärdet.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Om en film hittas skickas en instans av Movie modellen till Details vyn:

return View(movie);

Granska innehållet i Views/Movies/Details.cshtml filen:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Details";
}

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instruktionen @model överst i vyfilen anger vilken typ av objekt som vyn förväntar sig. När filmkontrollanten skapades inkluderades följande @model instruktion:

@model MvcMovie.Models.Movie

Det här @model direktivet ger åtkomst till filmen som kontrollanten skickade till vyn. Objektet Model är starkt typat. I Details.cshtml-vyn skickar koden varje filmfält till DisplayNameFor och DisplayFor HTML-hjälpare med det starkt typerade Model-objektet. Metoderna Create och Edit vyerna skickar också ett Movie modellobjekt.

Granska Index.cshtml vyn och Index metoden i filmmodulens kontroll. Observera hur koden skapar ett List objekt när den anropar View metoden. Koden skickar den här Movies listan från Index åtgärdsmetoden till vyn:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

När filmkontrollern skapades innehöll scaffold följande @model sats överst i Index.cshtml filen.

@model IEnumerable<MvcMovie.Models.Movie>

Med @model direktivet kan du komma åt listan över filmer som kontrollanten skickade till vyn med hjälp av ett Model objekt som är starkt skrivet. I vyn loopar koden till exempel Index.cshtml igenom filmerna med en foreach instruktion över det starkt typerade Model objektet:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Eftersom objektet Model är starkt typat (som ett IEnumerable<Movie>-objekt) anges varje objekt i loopen som Movie. Det innebär bland annat att du får kompileringstidskontroll av koden.

Ytterligare resurser