Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Av Tom Dykstra och Rick Anderson
I den här handledningen lär du dig ASP.NET Core MVC och Entity Framework Core med hjälp av kontrollanter och vyer. Razor Pages är en alternativ programmeringsmodell. För ny utveckling rekommenderar Razor vi Sidor över MVC med kontrollanter och vyer. Razor Se versionen Sidor av den här handledningen. Varje handledning täcker något som inte täcks av den andra.
Några saker som den här MVC-självstudien har som Pages-självstudien Razor inte har:
- Implementera arv i datamodellen
- Utföra råa SQL-frågor
- Använda dynamisk LINQ för att förenkla koden
Vissa saker som självstudiekursen Razor Sidor har som den här inte gör:
- Använda Select-metoden för att läsa in relaterade data
- Metodtips för EF.
Contoso University-exempelwebbappen visar hur du skapar en ASP.NET Core MVC-webbapp med Entity Framework (EF) Core och Visual Studio.
Exempelappen är en webbplats för ett fiktivt Contoso University. Den innehåller funktioner som studentantagning, kursskapande och läraruppgifter. Det här är den första i en serie självstudier som förklarar hur du skapar Contoso University-exempelappen.
Prerequisites
- Om du är nybörjare på ASP.NET Core MVC går du igenom självstudieserien Kom igång med ASP.NET Core MVC innan du startar den här.
- Visual Studio 2022 med arbetsuppgiften ASP.NET och webbutveckling.
- .NET 6 SDK
Den här handledningen har inte uppdaterats för ASP.NET Core i .NET 6 eller senare. Självstudiekursens instruktioner fungerar inte korrekt om du skapar ett projekt som riktar sig till ASP.NET Core i .NET 6 eller senare. Till exempel använder ASP.NET Core i .NET 6 eller senare webbmallar den minimala värdmodellen, som förenar Startup.cs och Program.cs till en enda Program.cs fil.
En annan skillnad som introduceras i .NET 6 är funktionen NRT (nullable reference types). Projektmallarna aktiverar den här funktionen som standard. Det kan uppstå problem där EF anser att en egenskap krävs i .NET 6 som är nullbar i .NET 5. Sidan Skapa student misslyckas t.ex. tyst om inte Enrollments egenskapen är nullbar eller asp-validation-summary om hjälptaggen ändras från ModelOnly till All.
Vi rekommenderar att du installerar och använder .NET 5 SDK för den här självstudien. Tills den här självstudien har uppdaterats kan du läsa Razor Sidor med Entity Framework Core i ASP.NET Core – Självstudie 1 av 8 om hur du använder Entity Framework med ASP.NET Core i .NET 6 eller senare.
Database engines
Visual Studio-instruktionerna använder SQL Server LocalDB, en version av SQL Server Express som endast körs i Windows.
Lösa problem och felsöka
Om du stöter på ett problem som du inte kan lösa kan du vanligtvis hitta lösningen genom att jämföra koden med det slutförda projektet. En lista över vanliga fel och hur du löser dem finns i avsnittet Felsökning i den senaste självstudien i serien. Om du inte hittar det du behöver där kan du ställa en fråga till StackOverflow.com för ASP.NET Core eller EF Core.
Tip
Det här är en serie med 10 självstudier, som var och en bygger på vad som görs i tidigare självstudier. Överväg att spara en kopia av projektet efter varje lyckad handledning. Om du stöter på problem kan du börja om från föregående självstudie i stället för att gå tillbaka till början av hela serien.
Contoso University webbapplikation
Appen som är inbyggd i de här självstudierna är en grundläggande webbplats för universitetet.
Användare kan visa och uppdatera information om studenter, kurs och lärare. Här är några av skärmarna i appen:
               
              
            
               
              
            
Skapa webbapp
- Starta Visual Studio och välj Skapa ett nytt projekt.
- I dialogrutan Skapa ett nytt projekt väljer du ASP.NET Core Web Application>Next.
- I dialogrutan Konfigurera det nya projektet anger du ContosoUniversitysom Projektnamn. Det är viktigt att använda exakt detta namn inklusive versaler, så att varjenamespacestämmer överens när kod kopieras.
- Select Create.
- I dialogrutan Skapa ett nytt ASP.NET Core-webbprogram väljer du: - .NET Core och ASP.NET Core 5.0 i listrutorna.
- ASP.NET Core Webbapplikation (Model-View-Controller).
- 
              Skapa 
 
Konfigurera webbplatsformatet
Några grundläggande ändringar konfigurerar webbplatsmenyn, layouten och startsidan.
Öppna Views/Shared/_Layout.cshtml och gör följande ändringar:
- Ändra varje förekomst av ContosoUniversitytillContoso University. Det finns tre förekomster.
- Lägg till menyposter för Om, Studenter, Kurser, Instruktörer och Avdelningar och ta bort Privacy menyposten.
Föregående ändringar är markerade i följande kod:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>
    <footer class="border-top footer text-muted">
        <div class="container">
            © 2020 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>
I Views/Home/Index.cshtmlersätter du innehållet i filen med följande markering:
@{
    ViewData["Title"] = "Home Page";
}
<div class="jumbotron">
    <h1>Contoso University</h1>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>Welcome to Contoso University</h2>
        <p>
            Contoso University is a sample application that
            demonstrates how to use Entity Framework Core in an
            ASP.NET Core MVC web application.
        </p>
    </div>
    <div class="col-md-4">
        <h2>Build it from scratch</h2>
        <p>You can build the application by following the steps in a series of tutorials.</p>
        <p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial »</a></p>
    </div>
    <div class="col-md-4">
        <h2>Download it</h2>
        <p>You can download the completed project from GitHub.</p>
        <p><a class="btn btn-default" href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-mvc/intro/samples/cu-final">See project source code »</a></p>
    </div>
</div>
Tryck på CTRL+F5 för att köra projektet eller välj Felsöka > Starta utan att felsöka på menyn. Startsidan visas med flikar för sidorna som skapats i den här handledningen.
               
              
            
EF Core NuGet-paket
Den här självstudien använder SQL Server och providerpaketet är Microsoft.EntityFrameworkCore.SqlServer.
EF SQL Server-paketet och dess beroenden, Microsoft.EntityFrameworkCore och Microsoft.EntityFrameworkCore.Relational, ger stöd vid körning för EF.
Lägg till NuGet-paketet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore . I Package Manager Console (PMC) anger du följande kommandon för att lägga till NuGet-paketen:
Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer
              Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet-paketet innehåller ASP.NET Core-mellanprogram för EF Core felsidor. Det här mellanprogrammet hjälper till att identifiera och diagnostisera fel med EF Core migreringar.
Information om andra databasprovidrar som är tillgängliga för EF Corefinns i Databasprovidrar.
Skapa datamodellen
Följande entitetsklasser skapas för den här appen:
               
              
            
De föregående entiteterna har följande relationer:
- En en-till-många-relation mellan StudentochEnrollmententiteter. En student kan registreras i valfritt antal kurser.
- En en-till-många-relation mellan CourseochEnrollmententiteter. En kurs kan ha valfritt antal studenter registrerade i den.
I följande avsnitt skapas en klass för var och en av dessa entiteter.
Studententiteten
               
              
            
I mappen Modeller skapar du Student klassen med följande kod:
using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        public ICollection<Enrollment> Enrollments { get; set; }
    }
}
Egenskapen ID är den primära nyckelkolumnen (PK) i databastabellen som motsvarar den här klassen. Som standard tolkar EF en egenskap som heter ID eller classnameID som primärnyckel. PK kan till exempel döpas till StudentID i stället för ID.
Egenskapen Enrollments är en navigeringsegenskap. Navigeringsegenskaper innehåller andra entiteter som är relaterade till den här entiteten. Egenskapen Enrollments för en entitet Student :
- Innehåller alla entiteter som är relaterade till den EnrollmentStudententiteten.
- Om en viss Studentrad i databasen har två relateradeEnrollmentrader:- Den Studententitetens navigeringsegenskapEnrollmentsinnehåller dessa tvåEnrollmententiteter.
 
- Den 
              Enrollment rader innehåller en elevs PK-värde i StudentID-kolumnen extern nyckel (FK).
Om en navigeringsegenskap kan innehålla flera entiteter:
- Typen måste vara en lista, till exempel ICollection<T>,List<T>ellerHashSet<T>.
- Entiteter kan läggas till, tas bort och uppdateras.
Många-till-många- och en-till-många-navigeringsrelationer kan innehålla flera entiteter. När ICollection<T> används skapar EF en HashSet<T> samling som standard.
Registreringsentitet
               
              
            
I mappen Modeller skapar du Enrollment klassen med följande kod:
namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }
    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }
        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}
Egenskapen EnrollmentID är PK. Den här entiteten använder classnameID mönstret i stället för ID på egen hand. Entiteten Student använde ID mönstret. Vissa utvecklare föredrar att använda ett mönster i hela datamodellen. I den här handledningen illustrerar variationen att båda mönstren kan användas. En senare självstudie visar hur användning ID utan klassnamn gör det enklare att implementera arv i datamodellen.
Egenskapen Grade är en enum. Efter ? typdeklarationen Grade anger att egenskapen Grade är nullbar. Ett betyg som skiljer null sig från ett nollbetyg. 
              null innebär att ett betyg inte är känt eller inte har tilldelats ännu.
Egenskapen StudentID är en främmande nyckel (FK) och motsvarande navigeringsegenskap är Student. En entitet Enrollment är associerad med en entitet Student , så egenskapen kan bara innehålla en enda Student entitet. Detta skiljer sig från navigeringsegenskapen Student.Enrollments , som kan innehålla flera Enrollment entiteter.
Egenskapen CourseID är en FK och motsvarande navigeringsegenskap är Course. En entitet Enrollment är associerad med en entitet Course .
Entity Framework tolkar en egenskap som en FK-egenskap om den är namngiven <namnet på navigeringsegenskapen><namnet på primärnyckelsegenskapen>. Till exempel StudentID för navigeringsegenskapen Student eftersom Student-entitetens PK är ID. FK-egenskaper kan också namnges <som primärnyckelegenskapsnamn>. Till exempel CourseID eftersom entitetens Course PK är CourseID.
Kursentiteten
               
              
            
I mappen Modeller skapar du Course klassen med följande kod:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }
        public ICollection<Enrollment> Enrollments { get; set; }
    }
}
Egenskapen Enrollments är en navigeringsegenskap. En entitet Course kan vara relaterad till valfritt antal Enrollment entiteter.
Attributet DatabaseGenerated förklaras i en senare handledning. Med det här attributet kan du ange PK:t för kursen i stället för att databasen ska generera den.
Skapa databaskontexten
Huvudklassen som samordnar EF-funktioner för en viss datamodell är databaskontextklassen DbContext . Den här klassen skapas genom att härledas från klassen Microsoft.EntityFrameworkCore.DbContext. Den DbContext härledda klassen anger vilka entiteter som ingår i datamodellen. Vissa EF-beteenden kan anpassas. I det här projektet heter SchoolContextklassen .
I projektmappen skapar du en mapp med namnet Data.
I mappen Data skapar du en SchoolContext klass med följande kod:
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }
        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }
    }
}
Föregående kod skapar en DbSet egenskap för varje entitetsuppsättning. Inom EF-terminologin:
- En entitetsuppsättning motsvarar vanligtvis en databastabell.
- En entitet motsvarar en rad i tabellen.
Instruktionerna DbSet<Enrollment> och DbSet<Course> kan utelämnas och fungerar på samma sätt. EF skulle inkludera dem implicit eftersom:
- Entiteten Studentrefererar till entitetenEnrollment.
- Entiteten Enrollmentrefererar till entitetenCourse.
När databasen skapas skapar EF tabeller som har samma namn som egenskapsnamnen DbSet . Egenskapsnamn för samlingar är vanligtvis plural. Till exempel Students i stället för Student. Utvecklare är oense om huruvida tabellnamn ska vara pluraliserade eller inte. I dessa handledningar åsidosätts standardbeteendet genom att ange enskilda tabellnamn i DbContext. Det gör du genom att lägga till följande markerade kod efter den senaste DbSet-egenskapen.
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }
        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
    }
}
Registrera SchoolContext
ASP.NET Core innehåller beroendeinmatning. Tjänster, till exempel EF-databaskontexten, registreras med beroendeinmatning under appstarten. Komponenter som kräver dessa tjänster, till exempel MVC-styrenheter, tillhandahålls dessa tjänster via konstruktorparametrar. Kontrollerns konstruktorkod som hämtar en kontextinstans visas senare i den här handledningen.
För att registrera SchoolContext som en tjänst, öppna Startup.cs och lägg till de markerade raderna i ConfigureServices-metoden.
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ContosoUniversity
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<SchoolContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
            services.AddControllersWithViews();
        }
Namnet på anslutningssträngen skickas till kontexten genom att anropa en metod för ett DbContextOptionsBuilder-objekt. För lokal utveckling läser konfigurationssystemet ASP.NET Core anslutningssträngen appsettings.json från filen.
              appsettings.json Öppna filen och lägg till en anslutningssträng enligt följande markering:
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
Lägg till undantagsfiltret för databasen
Lägg till AddDatabaseDeveloperPageExceptionFilter till ConfigureServices enligt följande kod:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<SchoolContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddDatabaseDeveloperPageExceptionFilter();
    services.AddControllersWithViews();
}
              AddDatabaseDeveloperPageExceptionFilter Innehåller användbar felinformation i utvecklingsmiljön.
SQL Server Express LocalDB
Anslutningssträngen anger SQL Server LocalDB. LocalDB är en lätt version av SQL Server Express Database Engine och är avsedd för apputveckling, inte produktionsanvändning. LocalDB startar på begäran och körs i användarläge, så det finns ingen komplex konfiguration. Som standard skapar LocalDB .mdf DB-filer i C:/Users/<user> katalogen.
Initiera DB med testdata
EF skapar en tom databas. I det här avsnittet läggs en metod till som anropas efter att databasen har skapats för att fylla den med testdata.
Metoden EnsureCreated används för att automatiskt skapa databasen. I en senare handledning ser du hur du hanterar modelländringar med hjälp av Code First-migreringar för att ändra databasschemat istället för att radera och återskapa databasen.
I mappen Data skapar du en ny klass med namnet DbInitializer med följande kod:
using ContosoUniversity.Models;
using System;
using System.Linq;
namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            context.Database.EnsureCreated();
            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }
            var students = new Student[]
            {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
            new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
            new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
            };
            foreach (Student s in students)
            {
                context.Students.Add(s);
            }
            context.SaveChanges();
            var courses = new Course[]
            {
            new Course{CourseID=1050,Title="Chemistry",Credits=3},
            new Course{CourseID=4022,Title="Microeconomics",Credits=3},
            new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
            new Course{CourseID=1045,Title="Calculus",Credits=4},
            new Course{CourseID=3141,Title="Trigonometry",Credits=4},
            new Course{CourseID=2021,Title="Composition",Credits=3},
            new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Courses.Add(c);
            }
            context.SaveChanges();
            var enrollments = new Enrollment[]
            {
            new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
            new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
            new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
            new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
            new Enrollment{StudentID=3,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
            new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
            new Enrollment{StudentID=6,CourseID=1045},
            new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollments.Add(e);
            }
            context.SaveChanges();
        }
    }
}
Föregående kod kontrollerar om databasen finns:
- Om databasen inte hittas; - Den är skapad och laddad med testdata. Den läser in testdata i matriser istället för att använda samlingar för att optimera prestandan.
 
- Om databasen hittas vidtar den ingen åtgärd.
Uppdatera Program.cs med följande kod:
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            CreateDbIfNotExists(host);
            host.Run();
        }
        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}
              Program.cs gör följande vid appstart:
- Hämta en databaskontextinstans från containern för beroendeinmatning.
- Anropa DbInitializer.Initializemetoden.
- Ta bort kontexten Initializenär metoden slutförs enligt följande kod:
public static void Main(string[] args)
{
     var host = CreateWebHostBuilder(args).Build();
    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<SchoolContext>();
            DbInitializer.Initialize(context);
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred while seeding the database.");
        }
    }
    host.Run();
}
Första gången appen körs skapas databasen och laddas med testdata. När datamodellen ändras:
- Ta bort databasen.
- Uppdatera seed-metoden och starta på nytt med en ny databas.
I senare handledningar modifieras databasen när datamodellen ändras, utan att ta bort och återskapa den. Inga data går förlorade när datamodellen ändras.
Skapa kontroller och vyer
Använd byggnadsställningsmotorn i Visual Studio för att lägga till en MVC-styrenhet och vyer som använder EF för att fråga efter och spara data.
Det automatiska skapandet av CRUD-åtgärdsmetoder och vyer kallas för scaffolding.
- Högerklicka på mappen i Controllersoch välj Lägg till > nytt strukturerat objekt.
- I dialogrutan Lägg till mall: - Välj MVC-styrenhet med vyer med Entity Framework.
- Click Add. Dialogrutan Lägg till MVC-styrenhet med vyer med entity framework visas:  
- I Modellklass väljer du Student.
- I Klassen Datakontext väljer du SchoolContext.
- Acceptera standardvärdet StudentsController som namn.
- Click Add.
 
Visual Studio-byggnadsställningsmotorn skapar en StudentsController.cs fil och en uppsättning vyer (*.cshtml filer) som fungerar med styrenheten.
Observera att kontrollanten tar en SchoolContext som konstruktorparameter.
namespace ContosoUniversity.Controllers
{
    public class StudentsController : Controller
    {
        private readonly SchoolContext _context;
        public StudentsController(SchoolContext context)
        {
            _context = context;
        }
ASP.NET Core-beroendeinmatningen tar hand om att skicka en instans av SchoolContext till kontrollanten. Du har konfigurerat det i Startup klassen.
Kontrollanten innehåller en Index åtgärdsmetod som visar alla elever i databasen. Metoden hämtar en lista över studenter från entiteten Studenter som angetts genom att läsa Students egenskapen för databaskontextinstansen:
public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
De asynkrona programmeringselementen i den här koden beskrivs senare i självstudien.
Vyn Views/Students/Index.cshtml visar den här listan i en tabell:
@model IEnumerable<ContosoUniversity.Models.Student>
@{
    ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
                <th>
                    @Html.DisplayNameFor(model => model.LastName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.FirstMidName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.EnrollmentDate)
                </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </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>
Tryck på CTRL+F5 för att köra projektet eller välj Felsöka > Starta utan att felsöka på menyn.
Klicka på fliken Studenter för att se testdata som DbInitializer.Initialize metoden infogade. Beroende på hur smalt webbläsarfönstret är ser du fliklänken Students överst på sidan eller så måste du klicka på navigeringsikonen i det övre högra hörnet för att se länken.
               
              
            
               
              
            
Visa databasen
När appen startas DbInitializer.Initialize anropar EnsureCreatedmetoden . EF såg att det inte fanns någon databas:
- Så den skapade en databas.
- Metodkoden Initializefyllde databasen med data.
Använd SQL Server Object Explorer (SSOX) för att visa databasen i Visual Studio:
- Välj SQL Server Object Explorer på menyn Visa i Visual Studio.
- I SSOX väljer du (localdb)\MSSQLLocalDB-databaser>.
- Välj ContosoUniversity1, posten för databasnamnet som finns i anslutningssträngen iappsettings.json-filen.
- Expandera noden Tabeller för att se tabellerna i databasen.
               
              
            
Högerklicka på tabellen Student och klicka på Visa data för att se data i tabellen.
               
              
            
Databasfilerna *.mdf och *.ldf finns i mappen C:\Users\<username> .
Eftersom EnsureCreated anropas i initieringsmetoden som körs vid appstart kan du:
- Gör en ändring i Studentklassen.
- Ta bort databasen.
- Stoppa och starta sedan appen. Databasen återskapas automatiskt för att matcha ändringen.
Om en EmailAddress egenskap till exempel läggs till i Student klassen, en ny EmailAddress kolumn i tabellen som skapats på nytt. Vyn visar inte den nya EmailAddress egenskapen.
Conventions
Mängden kod som skrivs för att EF ska kunna skapa en fullständig databas är minimal på grund av användningen av de konventioner som EF använder:
- Namnen på DbSetegenskaperna används som tabellnamn. För entiteter som inte refereras till av enDbSetegenskap används entitetsklassnamn som tabellnamn.
- Entitetsegenskapsnamn används för kolumnnamn.
- Entitetsegenskaper som namnges IDellerclassnameIDidentifieras som PK-egenskaper.
- En egenskap tolkas som en FK-egenskap om den heter <PK-egenskapsnamn för navigeringsegenskap><>. Till exempelStudentIDför navigeringsegenskapenStudenteftersomStudent-entitetens PK ärID. FK-egenskaper kan också namnges<som primärnyckelegenskapsnamn>. Till exempel eftersomEnrollmentIDentitetensEnrollmentPK ärEnrollmentID.
Konventionellt beteende kan åsidosättas. Du kan till exempel uttryckligen ange tabellnamn, som du ser tidigare i den här självstudien. Kolumnnamn och valfri egenskap kan anges som PK eller FK.
Asynchronous code
Asynkron programmering är standardläget för ASP.NET Core och EF Core.
En webbserver har ett begränsat antal tillgängliga trådar och i situationer med hög belastning kan alla tillgängliga trådar användas. När det händer kan servern inte bearbeta nya begäranden förrän trådarna har frigjorts. Med synkron kod kan många trådar vara bundna medan de faktiskt inte utför något arbete eftersom de väntar på att I/O ska slutföras. När en process väntar på att I/O ska slutföras med asynkron kod frigörs dess tråd så att servern kan använda för bearbetning av andra begäranden. Därför gör asynkron kod att serverresurser kan användas mer effektivt, och servern är aktiverad för att hantera mer trafik utan fördröjningar.
Asynkron kod medför en liten mängd omkostnader vid körning, men för situationer med låg trafik är prestandaträffen försumbar, medan den potentiella prestandaförbättringen är betydande för situationer med hög trafik.
I följande kod gör async, Task<T>, await, och ToListAsync att koden utförs asynkront.
public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
- Nyckelordet asyncinstruerar kompilatorn att generera återanrop för delar av metodtexten och att automatiskt skapa objektetTask<IActionResult>som returneras.
- Returtypen Task<IActionResult>representerar pågående arbete med ett resultat av typenIActionResult.
- Nyckelordet awaitgör att kompilatorn delar upp metoden i två delar. Den första delen avslutas med åtgärden som startas asynkront. Den andra delen placeras i en callback-metod som anropas när åtgärden slutförs.
- 
              ToListAsyncär den asynkrona versionen avToListtilläggsmetoden.
Några saker att vara medveten om när du skriver asynkron kod som använder EF:
- Endast instruktioner som gör att frågor eller kommandon skickas till databasen körs asynkront. Det inkluderar till exempel ToListAsync,SingleOrDefaultAsyncochSaveChangesAsync. Den innehåller till exempel inte instruktioner som bara ändrar enIQueryable, till exempelvar students = context.Students.Where(s => s.LastName == "Davolio").
- En EF-kontext är inte trådsäker: försök inte utföra flera åtgärder parallellt. När du anropar någon asynkron EF-metod använder du alltid nyckelordet await.
- Om du vill dra nytta av prestandafördelarna med asynkron kod kontrollerar du att alla bibliotekspaket som används även använder asynkronisering om de anropar ef-metoder som gör att frågor skickas till databasen.
Mer information om asynkron programmering i .NET finns i Översikt över Async.
Begränsa entiteter som hämtats
Mer information om hur du begränsar antalet entiteter som returneras från en fråga finns i Prestandaöverväganden .
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.
Gå vidare till nästa handledning för att lära dig hur du utför grundläggande CRUD-operationer (skapa, läsa, uppdatera, ta bort).
I den här handledningen lär du dig ASP.NET Core MVC och Entity Framework Core med hjälp av kontrollanter och vyer. Razor Pages är en alternativ programmeringsmodell. För ny utveckling rekommenderar Razor vi Sidor över MVC med kontrollanter och vyer. Razor Se versionen Sidor av den här handledningen. Varje handledning täcker något som inte täcks av den andra.
Några saker som den här MVC-självstudien har som Pages-självstudien Razor inte har:
- Implementera arv i datamodellen
- Utföra råa SQL-frågor
- Använda dynamisk LINQ för att förenkla koden
Vissa saker som självstudiekursen Razor Sidor har som den här inte gör:
- Använda Select-metoden för att läsa in relaterade data
- Metodtips för EF.
Contoso University-exempelwebbprogrammet visar hur du skapar ASP.NET Core 2.2 MVC-webbprogram med Entity Framework (EF) Core 2.2 och Visual Studio 2019.
Den här handledningen har inte uppdaterats för ASP.NET Core 3.1. Den har uppdaterats för ASP.NET Core i .NET 5.
Exempelapplikationen är en webbplats för det fiktiva Contoso University. Den innehåller funktioner som studentantagning, kursskapande och läraruppgifter. Det här är den första i en serie självstudier som förklarar hur du skapar Contoso University-exempelprogrammet från grunden.
Prerequisites
- .NET Core SDK 2.2
- 
              Visual Studio 2019 med följande arbetsbelastningar: - Arbetsbelastning för ASP.NET och webbutveckling
- .NET Core plattformsoberoende utvecklingsarbetsbelastning
 
Troubleshooting
Om du stöter på ett problem som du inte kan lösa kan du vanligtvis hitta lösningen genom att jämföra koden med det slutförda projektet. En lista över vanliga fel och hur du löser dem finns i avsnittet Felsökning i den senaste självstudien i serien. Om du inte hittar det du behöver där kan du ställa en fråga till StackOverflow.com för ASP.NET Core eller EF Core.
Tip
Det här är en serie med 10 självstudier, som var och en bygger på vad som görs i tidigare självstudier. Överväg att spara en kopia av projektet efter varje lyckad handledning. Om du stöter på problem kan du börja om från föregående självstudie i stället för att gå tillbaka till början av hela serien.
Contoso University webbapplikation
Programmet som du kommer att skapa i dessa självstudier är en enkel universitetswebbplats.
Användare kan visa och uppdatera information om studenter, kurs och lärare. Här är några av de skärmar som du skapar.
               
              
            
               
              
            
Skapa webbapp
- Öppna Visual Studio. 
- På menyn Arkiv väljer du Nytt > projekt. 
- I den vänstra rutan väljer du Installerad > Visual C# > Web. 
- Välj projektmallen ASP.NET Core Web Application . 
- Ange ContosoUniversity som namn och klicka på OK. - dialogrutan  
- Vänta tills dialogrutan Nytt ASP.NET Core-webbprogram visas. 
- Välj .NET Core, ASP.NET Core 2.2 och mallen Webbprogram (modell-View-Controller). 
- Kontrollera att autentiseringen är inställd på Ingen autentisering. 
- Select OK   
Konfigurera webbplatsformatet
Några enkla ändringar konfigurerar webbplatsmenyn, layouten och startsidan.
Öppna Views/Shared/_Layout.cshtml och gör följande ändringar:
- Ändra varje förekomst av "ContosoUniversity" till "Contoso University". Det finns tre förekomster. 
- Lägg till menyposter för Om, Studenter, Kurser, Instruktörer och Avdelningar och ta bort Privacy menyposten. 
Ändringarna är markerade.
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>
    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
              crossorigin="anonymous"
              integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
    </environment>
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <partial name="_CookieConsentPartial" />
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>
    <footer class="border-top footer text-muted">
        <div class="container">
            © 2019 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
        </script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
        </script>
    </environment>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
</body>
</html>
I Views/Home/Index.cshtmlersätter du innehållet i filen med följande kod för att ersätta texten om ASP.NET och MVC med text om det här programmet:
@{
    ViewData["Title"] = "Home Page";
}
<div class="jumbotron">
    <h1>Contoso University</h1>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>Welcome to Contoso University</h2>
        <p>
            Contoso University is a sample application that
            demonstrates how to use Entity Framework Core in an
            ASP.NET Core MVC web application.
        </p>
    </div>
    <div class="col-md-4">
        <h2>Build it from scratch</h2>
        <p>You can build the application by following the steps in a series of tutorials.</p>
        <p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial »</a></p>
    </div>
    <div class="col-md-4">
        <h2>Download it</h2>
        <p>You can download the completed project from GitHub.</p>
        <p><a class="btn btn-default" href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-mvc/intro/samples/cu-final">See project source code »</a></p>
    </div>
</div>
Tryck på CTRL+F5 för att köra projektet eller välj Felsöka > Starta utan att felsöka på menyn. Du ser startsidan med flikar för de sidor som du skapar i de här självstudierna.
               
              
            
Om EF Core NuGet-paket
Om du vill lägga till EF Core stöd för ett projekt installerar du den databasprovider som du vill rikta in dig på. Den här självstudien använder SQL Server och providerpaketet är Microsoft.EntityFrameworkCore.SqlServer. Det här paketet ingår i Microsoft.AspNetCore.App metapaket, så du behöver inte referera till paketet.
EF SQL Server-paketet och dess beroenden (Microsoft.EntityFrameworkCore och Microsoft.EntityFrameworkCore.Relational) ger körtidsstöd för EF. Du lägger till ett verktygspaket senare i Migrations-tutorialen.
Information om andra databasprovidrar som är tillgängliga för Entity Framework Core finns i Databasprovidrar.
Skapa datamodellen
Därefter skapar du entitetsklasser för Contoso University-programmet. Du börjar med följande tre entiteter.
               
              
            
Det finns en en-till-många-relation mellan Student och Enrollment entiteter, och det finns en en-till-många-relation mellan Course och Enrollment entiteter. Med andra ord kan en student registreras i valfritt antal kurser, och en kurs kan ha valfritt antal studenter registrerade i den.
I följande avsnitt skapar du en klass för var och en av dessa entiteter.
Studententiteten
               
              
            
I mappen Modeller skapar du en klassfil med namnet Student.cs och ersätter mallkoden med följande kod.
using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        public ICollection<Enrollment> Enrollments { get; set; }
    }
}
Egenskapen ID blir den primära nyckelkolumnen i databastabellen som motsvarar den här klassen. Som standard tolkar Entity Framework en egenskap som heter ID eller classnameID som primärnyckel.
Egenskapen Enrollments är en navigeringsegenskap. Navigeringsegenskaper innehåller andra entiteter som är relaterade till den här entiteten. I det här fallet kommer Enrollments-egenskapen för en Student entity att innehålla alla Enrollment-entiteter som är relaterade till den Student-entiteten. Om en Student rad i databasen med andra ord har två relaterade Enrollment rader (rader som innehåller den elevens primära nyckelvärde i kolumnen StudentID-sekundärnyckel) innehåller den Student entitetens navigeringsegenskap Enrollments dessa två Enrollment entiteter.
Om en navigeringsegenskap kan innehålla flera entiteter (som i många-till-många- eller en-till-många-relationer) måste dess typ vara en lista där poster kan läggas till, tas bort och uppdateras, till exempel ICollection<T>. Du kan ange ICollection<T> eller en typ som List<T> eller HashSet<T>. Om du anger ICollection<T>skapar EF en HashSet<T> samling som standard.
Registreringsentitet
               
              
            
I mappen Modeller skapar Enrollment.cs och ersätter du den befintliga koden med följande kod:
namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }
    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }
        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}
Egenskapen EnrollmentID är den primära nyckeln. Den här entiteten använder classnameID mönstret i stället för ID av sig själv som du såg i entiteten Student . Normalt skulle du välja ett mönster och använda det i hela datamodellen. Här visar varianten att du kan använda endera mönstret. I en senare självstudie får du se hur användning av ID utan klassnamn gör det enklare att implementera arv i datamodellen.
Egenskapen Grade är en enum. Frågetecknet efter typdeklarationen Grade anger att egenskapen Grade är null. Ett betyg som är null skiljer sig från ett nollbetyg – null innebär att ett betyg inte är känt eller inte har tilldelats ännu.
Egenskapen StudentID är en främmande nyckel och den motsvarande navigeringsegenskapen är Student. En entitet Enrollment är associerad med en entitet Student , så egenskapen kan bara innehålla en enda Student entitet (till skillnad från den Student.Enrollments navigeringsegenskap som du såg tidigare, som kan innehålla flera Enrollment entiteter).
Egenskapen CourseID är en främmande nyckel och den motsvarande navigeringsegenskapen är Course. En entitet Enrollment är associerad med en entitet Course .
Entity Framework tolkar en egenskap som en sekundärnyckelegenskap om den heter <navigation property name><primary key property name> (till exempel StudentID för navigeringsegenskapen StudentStudent eftersom entitetens primära nyckel är ID). Egenskaper för sekundärnyckel kan också namnges helt enkelt <primary key property name> (till exempel CourseID eftersom entitetens Course primära nyckel är CourseID).
Kursentiteten
               
              
            
I mappen Modeller skapar Course.cs och ersätter du den befintliga koden med följande kod:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }
        public ICollection<Enrollment> Enrollments { get; set; }
    }
}
Egenskapen Enrollments är en navigeringsegenskap. En entitet Course kan vara relaterad till valfritt antal Enrollment entiteter.
Vi kommer att säga mer om attributet DatabaseGenerated i en senare lektion i den här serien. Med det här attributet kan du i princip ange primärnyckeln för kursen i stället för att låta databasen generera den.
Skapa databaskontexten
Huvudklassen som samordnar Entity Framework-funktioner för en viss datamodell är databaskontextklassen. Du skapar den här klassen genom att härleda från Microsoft.EntityFrameworkCore.DbContext klassen. I koden anger du vilka entiteter som ingår i datamodellen. Du kan också anpassa vissa Entity Framework-beteenden. I det här projektet heter SchoolContextklassen .
Skapa en mapp med namnet Data i projektmappen.
I mappen Data skapar du en ny klassfil med namnet SchoolContext.csoch ersätter mallkoden med följande kod:
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }
        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }
    }
}
Den här koden skapar en DbSet egenskap för varje entitetsuppsättning. I Entity Framework-terminologi motsvarar en entitetsuppsättning vanligtvis en databastabell och en entitet motsvarar en rad i tabellen.
Du kunde ha utelämnat DbSet<Enrollment> och DbSet<Course>-instruktionerna och det skulle fungera på samma sätt. Entity Framework skulle inkludera dem implicit eftersom entiteten Student refererar till Enrollment entiteten och entiteten Enrollment refererar till entiteten Course .
När databasen skapas skapar EF tabeller som har samma namn som egenskapsnamnen DbSet . Egenskapsnamn för samlingar är vanligtvis plural (Studenter snarare än Student), men utvecklare är oense om huruvida tabellnamn ska vara pluraliserade eller inte. För de här självstudierna åsidosätter du standardbeteendet genom att ange enskilda tabellnamn i DbContext. Det gör du genom att lägga till följande markerade kod efter den senaste DbSet-egenskapen.
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }
        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
    }
}
Skapa projektet som en kontroll av kompilatorfel.
Registrera skolkontext
ASP.NET Core implementerar beroendeinmatning som standard. Tjänster (till exempel EF-databaskontexten) registreras med beroendeinmatning under programstarten. Komponenter som kräver dessa tjänster (till exempel MVC-styrenheter) tillhandahålls dessa tjänster via konstruktorparametrar. Du kommer att se koden för styrenhetskonstruktorn som hämtar en kontextinstans senare i detta steg-för-steg-program.
För att registrera SchoolContext som en tjänst, öppna Startup.cs och lägg till de markerade raderna i ConfigureServices-metoden.
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });
    services.AddDbContext<SchoolContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddMvc();
}
Namnet på anslutningssträngen skickas till kontexten genom att anropa en metod för ett DbContextOptionsBuilder-objekt. För lokal utveckling läser konfigurationssystemet ASP.NET Core anslutningssträngen appsettings.json från filen.
Lägg till using instruktioner för ContosoUniversity.Data och Microsoft.EntityFrameworkCore namnområden och skapa sedan projektet.
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;
              appsettings.json Öppna filen och lägg till en anslutningssträng enligt följande exempel.
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  }
}
SQL Server Express LocalDB
Anslutningssträngen anger en SQL Server LocalDB-databas. LocalDB är en lätt version av SQL Server Express Database Engine och är avsedd för programutveckling, inte produktionsanvändning. LocalDB startar på begäran och körs i användarläge, så det finns ingen komplex konfiguration. Som standard skapar LocalDB .mdf databasfiler i C:/Users/<user> katalogen.
Initiera DB med testdata
Entity Framework skapar en tom databas åt dig. I det här avsnittet skriver du en metod som anropas efter att databasen har skapats för att fylla den med testdata.
Här använder EnsureCreated du metoden för att automatiskt skapa databasen. I en senare självstudie får du se hur du hanterar modelländringar med hjälp av Code First Migrations för att ändra databasschemat i stället för att släppa och återskapa databasen.
I mappen Data skapar du en ny klassfil med namnet DbInitializer.cs och ersätter mallkoden med följande kod, vilket gör att en databas skapas när det behövs och läser in testdata i den nya databasen.
using ContosoUniversity.Models;
using System;
using System.Linq;
namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            context.Database.EnsureCreated();
            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }
            var students = new Student[]
            {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
            new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
            new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
            };
            foreach (Student s in students)
            {
                context.Students.Add(s);
            }
            context.SaveChanges();
            var courses = new Course[]
            {
            new Course{CourseID=1050,Title="Chemistry",Credits=3},
            new Course{CourseID=4022,Title="Microeconomics",Credits=3},
            new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
            new Course{CourseID=1045,Title="Calculus",Credits=4},
            new Course{CourseID=3141,Title="Trigonometry",Credits=4},
            new Course{CourseID=2021,Title="Composition",Credits=3},
            new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Courses.Add(c);
            }
            context.SaveChanges();
            var enrollments = new Enrollment[]
            {
            new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
            new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
            new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
            new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
            new Enrollment{StudentID=3,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
            new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
            new Enrollment{StudentID=6,CourseID=1045},
            new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollments.Add(e);
            }
            context.SaveChanges();
        }
    }
}
Koden kontrollerar om det finns några elever i databasen, och om inte, förutsätter den att databasen är ny och måste seedas med testdata. Den läser in testdata i matriser istället för att använda samlingar för att optimera prestandan.
I Program.csändrar du Main metoden så att den gör följande vid programstart:
- Hämta en databaskontextinstans från containern för beroendeinmatning.
- Anropa seed-metoden och skicka kontexten till den.
- Ta bort kontexten när frö-metoden är klar.
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            CreateDbIfNotExists(host);
            host.Run();
        }
        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}
Första gången du kör programmet skapas och seedas databasen med testdata. När du ändrar datamodellen:
- Ta bort databasen.
- Uppdatera seed-metoden och starta på nytt med en ny databas på samma sätt.
I senare självstudier får du se hur du ändrar databasen när datamodellen ändras, utan att ta bort och återskapa den.
Skapa kontroller och vyer
I det här avsnittet används byggnadsställningsmotorn i Visual Studio för att lägga till en MVC-styrenhet och vyer som använder EF för att fråga efter och spara data.
Det automatiska skapandet av CRUD-åtgärdsmetoder och vyer kallas för scaffolding. Scaffolding skiljer sig från kodgenerering eftersom den scaffolded koden är en startpunkt som du kan ändra för att passa dina egna krav, medan du vanligtvis inte ändrar genererad kod. När du behöver anpassa genererad kod använder du partiella klasser eller återskapar koden när saker ändras.
- Högerklicka på mappen Controllers i Solution Explorer och välj Lägg till > nytt Scaffolded Item.
- I dialogrutan Lägg till mall: - Välj MVC-styrenhet med vyer med Entity Framework.
- Click Add. Dialogrutan Lägg till MVC-styrenhet med vyer med entity framework visas:  
- I Modellklass väljer du Student.
- I Klassen Datakontext väljer du SchoolContext.
- Acceptera standardvärdet StudentsController som namn.
- Click Add.
 
Visual Studio-byggnadsställningsmotorn skapar en StudentsController.cs fil och en uppsättning vyer (.cshtml filer) som fungerar med styrenheten.
Observera att kontrollanten tar en SchoolContext som konstruktorparameter.
namespace ContosoUniversity.Controllers
{
    public class StudentsController : Controller
    {
        private readonly SchoolContext _context;
        public StudentsController(SchoolContext context)
        {
            _context = context;
        }
ASP.NET Core-beroendeinmatningen tar hand om att skicka en instans av SchoolContext till kontrollanten. Det konfigurerades i Startup.cs filen.
Kontrollanten innehåller en Index åtgärdsmetod som visar alla elever i databasen. Metoden hämtar en lista över studenter från entiteten Studenter som angetts genom att läsa Students egenskapen för databaskontextinstansen:
public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
Du lär dig mer om de asynkrona programmeringselementen i den här koden senare i självstudien.
Vyn Views/Students/Index.cshtml visar den här listan i en tabell:
@model IEnumerable<ContosoUniversity.Models.Student>
@{
    ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
                <th>
                    @Html.DisplayNameFor(model => model.LastName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.FirstMidName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.EnrollmentDate)
                </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </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>
Tryck på CTRL+F5 för att köra projektet eller välj Felsöka > Starta utan att felsöka på menyn.
Klicka på fliken Studenter för att se testdata som DbInitializer.Initialize metoden infogade. Beroende på hur smalt webbläsarfönstret är ser du fliklänken Students överst på sidan eller så måste du klicka på navigeringsikonen i det övre högra hörnet för att se länken.
               
              
            
               
              
            
Visa databasen
När du startade programmet DbInitializer.Initialize anropar EnsureCreatedmetoden . EF såg att det inte fanns någon databas, så den skapade en och sedan fyllde resten av Initialize metodkoden databasen med data. Du kan använda SQL Server Object Explorer (SSOX) för att visa databasen i Visual Studio.
Stäng webbläsaren.
Om SSOX-fönstret inte redan är öppet väljer du det på menyn Visa i Visual Studio.
I SSOX klickar du på > Databaser, och klickar sedan på posten för det databasnamn som finns i anslutningssträngen i appsettings.json-filen.
Expandera noden Tabeller för att se tabellerna i databasen.
               
              
            
Högerklicka på tabellen Student och klicka på Visa data för att se kolumnerna som skapades och de rader som infogades i tabellen.
               
              
            
Databasfilerna .mdf och .ldf finns i mappen C:\Users\<username>.
Eftersom du anropar EnsureCreated i initieringsmetoden som körs vid appstart kan du nu göra en ändring i Student klassen, ta bort databasen, köra programmet igen och databasen skapas automatiskt igen för att matcha ändringen. Om du till exempel lägger till en EmailAddress egenskap i Student klassen visas en ny EmailAddress kolumn i tabellen som skapats på nytt.
Conventions
Mängden kod som du var tvungen att skriva för att Entity Framework ska kunna skapa en fullständig databas åt dig är minimal på grund av användningen av konventioner eller antaganden som Entity Framework gör.
- Namnen på DbSetegenskaperna används som tabellnamn. För entiteter som inte refereras till av enDbSetegenskap används entitetsklassnamn som tabellnamn.
- Entitetsegenskapsnamn används för kolumnnamn.
- Entitetsegenskaper med namnet ID eller classnameID identifieras som primärnyckelegenskaper.
- En egenskap tolkas som en utländsk nyckelegenskap om den heter <navigeringsegenskapens namn><primärnyckelegenskap> (till exempel StudentIDför navigeringsegenskapenStudenteftersom entitetens primärnyckel ärStudent). Främmande nyckelegenskaper kan också vara namngivna enbart efter primärnyckelns egenskapsnamn (till exempel < eftersom primärnyckeln för entiteten är >).
Konventionellt beteende kan åsidosättas. Du kan till exempel uttryckligen ange tabellnamn, som du såg tidigare i den här självstudien. Och du kan ange kolumnnamn och använda valfri egenskap som primärnyckel eller främmande nyckel, som du kommer att se i en senare handledning i den här serien.
Asynchronous code
Asynkron programmering är standardläget för ASP.NET Core och EF Core.
En webbserver har ett begränsat antal tillgängliga trådar och i situationer med hög belastning kan alla tillgängliga trådar användas. När det händer kan servern inte bearbeta nya begäranden förrän trådarna har frigjorts. Med synkron kod kan många trådar vara bundna medan de faktiskt inte utför något arbete eftersom de väntar på att I/O ska slutföras. När en process väntar på att I/O ska slutföras med asynkron kod frigörs dess tråd så att servern kan använda för bearbetning av andra begäranden. Därför gör asynkron kod att serverresurser kan användas mer effektivt, och servern är aktiverad för att hantera mer trafik utan fördröjningar.
Asynkron kod medför en liten mängd omkostnader vid körning, men för situationer med låg trafik är prestandaträffen försumbar, medan den potentiella prestandaförbättringen är betydande för situationer med hög trafik.
I följande kod får nyckelordet async , Task<T> returvärdet, await nyckelordet och ToListAsync metoden koden att köras asynkront.
public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
- Nyckelordet asyncinstruerar kompilatorn att generera återanrop för delar av metodtexten och att automatiskt skapa objektetTask<IActionResult>som returneras.
- Returtypen Task<IActionResult>representerar pågående arbete med ett resultat av typenIActionResult.
- Nyckelordet awaitgör att kompilatorn delar upp metoden i två delar. Den första delen avslutas med åtgärden som startas asynkront. Den andra delen placeras i en callback-metod som anropas när åtgärden slutförs.
- 
              ToListAsyncär den asynkrona versionen avToListtilläggsmetoden.
Några saker att vara medveten om när du skriver asynkron kod som använder Entity Framework:
- Endast instruktioner som gör att frågor eller kommandon skickas till databasen körs asynkront. Det inkluderar till exempel ToListAsync,SingleOrDefaultAsyncochSaveChangesAsync. Den innehåller till exempel inte instruktioner som bara ändrar enIQueryable, till exempelvar students = context.Students.Where(s => s.LastName == "Davolio").
- En EF-kontext är inte trådsäker: försök inte utföra flera åtgärder parallellt. När du anropar någon asynkron EF-metod använder du alltid nyckelordet await.
- Om du vill dra nytta av prestandafördelarna med asynkron kod, se till att alla bibliotekspaket du använder, till exempel för paginering, också använder asynkron om de anropar några Entity Framework-metoder som gör att frågor skickas till databasen.
Mer information om asynkron programmering i .NET finns i Översikt över Async.
Next steps
Gå vidare till nästa handledning för att lära dig hur du utför grundläggande CRUD-operationer (skapa, läsa, uppdatera, ta bort).
ASP.NET Core