Páginas de Razor con Entity Framework Core en ASP.NET Core: Tutorial 1 de 8Razor Pages with Entity Framework Core in ASP.NET Core - Tutorial 1 of 8

Por Tom Dykstra y Rick AndersonBy Tom Dykstra and Rick Anderson

En la aplicación web de ejemplo Contoso University se muestra cómo crear una aplicación web de Razor Pages de ASP.NET Core con Entity Framework (EF) Core.The Contoso University sample web app demonstrates how to create an ASP.NET Core Razor Pages app using Entity Framework (EF) Core.

La aplicación de ejemplo es un sitio web de una universidad ficticia, Contoso University.The sample app is a web site for a fictional Contoso University. Incluye funciones como la admisión de estudiantes, la creación de cursos y asignaciones de instructores.It includes functionality such as student admission, course creation, and instructor assignments. Esta página es la primera de una serie de tutoriales en los que se explica cómo crear la aplicación de ejemplo Contoso University.This page is the first in a series of tutorials that explain how to build the Contoso University sample app.

Descargue o vea la aplicación completa.Download or view the completed app. Instrucciones de descarga.Download instructions.

Requisitos previosPrerequisites

Visual Studio 2017 versión 15.7.3 o posterior con las cargas de trabajo siguientes:Visual Studio 2017 version 15.7.3 or later with the following workloads:

  • Desarrollo de ASP.NET y webASP.NET and web development
  • Desarrollo multiplataforma de .NET Core.NET Core cross-platform development

Familiaridad con las Páginas de Razor.Familiarity with Razor Pages. Los programadores nuevos deben completar Introducción a las páginas de Razor en ASP.NET Core antes de empezar esta serie.New programmers should complete Get started with Razor Pages before starting this series.

Solución de problemasTroubleshooting

Si experimenta un problema que no puede resolver, por lo general podrá encontrar la solución si compara el código con el proyecto completado.If you run into a problem you can't resolve, you can generally find the solution by comparing your code to the completed project. Una buena forma de obtener ayuda consiste en publicar una pregunta en StackOverflow.com para ASP.NET Core o EF Core.A good way to get help is by posting a question to StackOverflow.com for ASP.NET Core or EF Core.

La aplicación web Contoso UniversityThe Contoso University web app

La aplicación compilada en estos tutoriales es un sitio web básico de una universidad.The app built in these tutorials is a basic university web site.

Los usuarios pueden ver y actualizar la información de estudiantes, cursos e instructores.Users can view and update student, course, and instructor information. Estas son algunas de las pantallas que se crean en el tutorial.Here are a few of the screens created in the tutorial.

Página de índice de Students

Página de edición de estudiantes

El estilo de la interfaz de usuario de este sitio se mantiene fiel a lo que generan las plantillas integradas.The UI style of this site is close to what's generated by the built-in templates. El tutorial se centra en EF Core con páginas de Razor, no en la interfaz de usuario.The tutorial focus is on EF Core with Razor Pages, not the UI.

Creación de la aplicación web de Razor Pages ContosoUniversityCreate the ContosoUniversity Razor Pages web app

  • En el menú Archivo de Visual Studio, seleccione Nuevo > Proyecto.From the Visual Studio File menu, select New > Project.
  • Cree una aplicación web de ASP.NET Core.Create a new ASP.NET Core Web Application. Asigne el nombre ContosoUniversity al proyecto.Name the project ContosoUniversity. Es importante que el nombre del proyecto sea ContosoUniversity para que coincidan los espacios de nombres al copiar y pegar el código.It's important to name the project ContosoUniversity so the namespaces match when code is copy/pasted.
  • Seleccione ASP.NET Core 2.1 en la lista desplegable y, luego, Aplicación web.Select ASP.NET Core 2.1 in the dropdown, and then select Web Application.

Para ver las imágenes de los pasos anteriores, consulte Creación de una aplicación web de Razor.For images of the preceding steps, see Create a Razor web app. Ejecute la aplicación.Run the app.

Configurar el estilo del sitioSet up the site style

Con algunos cambios se configura el menú del sitio, el diseño y la página principal.A few changes set up the site menu, layout, and home page. Actualice Pages/Shared/_Layout.cshtml con los cambios siguientes:Update Pages/Shared/_Layout.cshtml with the following changes:

  • Cambie todas las repeticiones de "ContosoUniversity" por "Contoso University".Change each occurrence of "ContosoUniversity" to "Contoso University". Hay tres repeticiones.There are three occurrences.

  • Agregue entradas de menú para Students, Courses, Instructors y Departments, y elimine la entrada de menú Contact.Add menu entries for Students, Courses, Instructors, and Departments, and delete the Contact menu entry.

Los cambios aparecen resaltados.The changes are highlighted. (No se muestra todo el marcado).(All the markup is not displayed.)

<!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" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a asp-page="/Index" class="navbar-brand">Contoso University</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-page="/Index">Home</a></li>
                    <li><a asp-page="/About">About</a></li>
                    <li><a asp-page="/Students/Index">Students</a></li>
                    <li><a asp-page="/Courses/Index">Courses</a></li>
                    <li><a asp-page="/Instructors/Index">Instructors</a></li>
                    <li><a asp-page="/Departments/Index">Departments</a></li>
                </ul>
            </div>
        </div>
    </nav>

    <partial name="_CookieConsentPartial" />

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 : Contoso University</p>
        </footer>
    </div>

    @*Remaining markup not shown for brevity.*@

En Pages/Index.cshtml, reemplace el contenido del archivo con el código siguiente para reemplazar el texto sobre ASP.NET y MVC con texto sobre esta aplicación:In Pages/Index.cshtml, replace the contents of the file with the following code to replace the text about ASP.NET and MVC with text about this app:

@page
@model IndexModel
@{
    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 Razor Pages web app.
        </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.microsoft.com/aspnet/core/data/ef-rp/intro">
                See the tutorial &raquo;
            </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/aspnet/AspNetCore.Docs/tree/master/aspnetcore/data/ef-rp/intro/samples/cu-final">
                See project source code &raquo;
            </a>
        </p>
    </div>
</div>

Crear el modelo de datosCreate the data model

Cree las clases de entidad para la aplicación Contoso University.Create entity classes for the Contoso University app. Comience con las tres entidades siguientes:Start with the following three entities:

Diagrama del modelo de datos Course-Enrollment-Student

Hay una relación uno a varios entre las entidades Student y Enrollment.There's a one-to-many relationship between Student and Enrollment entities. Hay una relación uno a varios entre las entidades Course y Enrollment.There's a one-to-many relationship between Course and Enrollment entities. Un estudiante se puede inscribir en cualquier número de cursos.A student can enroll in any number of courses. Un curso puede tener cualquier número de alumnos inscritos.A course can have any number of students enrolled in it.

En las secciones siguientes, se crea una clase para cada una de estas entidades.In the following sections, a class for each one of these entities is created.

La entidad StudentThe Student entity

Diagrama de la entidad Student

Cree una carpeta Models.Create a Models folder. En la carpeta Models, cree un archivo de clase denominado Student.cs con el código siguiente:In the Models folder, create a class file named Student.cs with the following code:

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; }
    }
}

La propiedad ID se convierte en la columna de clave principal de la tabla de base de datos (DB) que corresponde a esta clase.The ID property becomes the primary key column of the database (DB) table that corresponds to this class. De forma predeterminada, EF Core interpreta como la clave principal una propiedad que se denomine ID o classnameID.By default, EF Core interprets a property that's named ID or classnameID as the primary key. En classnameID, classname es el nombre de la clase.In classnameID, classname is the name of the class. En el ejemplo anterior, la clave principal alternativa que se reconoce de forma automática es StudentID.The alternative automatically recognized primary key is StudentID in the preceding example.

La propiedad Enrollments es una propiedad de navegación.The Enrollments property is a navigation property. Las propiedades de navegación se vinculan a otras entidades relacionadas con esta entidad.Navigation properties link to other entities that are related to this entity. En este caso, la propiedad Enrollments de una Student entity contiene todas las entidades Enrollment que están relacionadas con esa entidad Student.In this case, the Enrollments property of a Student entity holds all of the Enrollment entities that are related to that Student. Por ejemplo, si una fila Student de la base de datos tiene dos filas Enrollment relacionadas, la propiedad de navegación Enrollments contiene esas dos entidades Enrollment.For example, if a Student row in the DB has two related Enrollment rows, the Enrollments navigation property contains those two Enrollment entities. Una fila Enrollment relacionada es la que contiene el valor de clave principal de ese estudiante en la columna StudentID.A related Enrollment row is a row that contains that student's primary key value in the StudentID column. Por ejemplo, suponga que el estudiante con ID=1 tiene dos filas en la tabla Enrollment.For example, suppose the student with ID=1 has two rows in the Enrollment table. La tabla Enrollment tiene dos filas con StudentID = 1.The Enrollment table has two rows with StudentID = 1. StudentID es una clave externa en la tabla Enrollment que especifica el estudiante en la tabla Student.StudentID is a foreign key in the Enrollment table that specifies the student in the Student table.

Si una propiedad de navegación puede contener varias entidades, la propiedad de navegación debe ser un tipo de lista, como ICollection<T>.If a navigation property can hold multiple entities, the navigation property must be a list type, such as ICollection<T>. Se puede especificar ICollection<T>, o bien un tipo como List<T> o HashSet<T>.ICollection<T> can be specified, or a type such as List<T> or HashSet<T>. Cuando se usa ICollection<T>, EF Core crea una colección HashSet<T> de forma predeterminada.When ICollection<T> is used, EF Core creates a HashSet<T> collection by default. Las propiedades de navegación que contienen varias entidades proceden de relaciones de varios a varios y uno a varios.Navigation properties that hold multiple entities come from many-to-many and one-to-many relationships.

La entidad EnrollmentThe Enrollment entity

Diagrama de la entidad Enrollment

En la carpeta Models, cree Enrollment.cs con el código siguiente:In the Models folder, create Enrollment.cs with the following code:

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; }
    }
}

La propiedad EnrollmentID es la clave principal.The EnrollmentID property is the primary key. En esta entidad se usa el patrón classnameID en lugar de ID como en la entidad Student.This entity uses the classnameID pattern instead of ID like the Student entity. Normalmente, los desarrolladores eligen un patrón y lo usan en todo el modelo de datos.Typically developers choose one pattern and use it throughout the data model. En un tutorial posterior, se muestra el uso de ID sin un nombre de clase para facilitar la implementación de la herencia en el modelo de datos.In a later tutorial, using ID without classname is shown to make it easier to implement inheritance in the data model.

La propiedad Grade es una enum.The Grade property is an enum. El signo de interrogación después de la declaración de tipo Grade indica que la propiedad Grade acepta valores NULL.The question mark after the Grade type declaration indicates that the Grade property is nullable. Una calificación que sea NULL es diferente de una calificación que sea cero; NULL significa que no se conoce una calificación o que todavía no se ha asignado.A grade that's null is different from a zero grade -- null means a grade isn't known or hasn't been assigned yet.

La propiedad StudentID es una clave externa y la propiedad de navegación correspondiente es Student.The StudentID property is a foreign key, and the corresponding navigation property is Student. Una entidad Enrollment está asociada con una entidad Student, por lo que la propiedad contiene una única entidad Student.An Enrollment entity is associated with one Student entity, so the property contains a single Student entity. La entidad Student difiere de la propiedad de navegación Student.Enrollments, que contiene varias entidades Enrollment.The Student entity differs from the Student.Enrollments navigation property, which contains multiple Enrollment entities.

La propiedad CourseID es una clave externa y la propiedad de navegación correspondiente es Course.The CourseID property is a foreign key, and the corresponding navigation property is Course. Una entidad Enrollment está asociada con una entidad Course.An Enrollment entity is associated with one Course entity.

EF Core interpreta una propiedad como una clave externa si se denomina <navigation property name><primary key property name>.EF Core interprets a property as a foreign key if it's named <navigation property name><primary key property name>. Por ejemplo, StudentID para la propiedad de navegación Student, puesto que la clave principal de la entidad Student es ID.For example,StudentID for the Student navigation property, since the Student entity's primary key is ID. Las propiedades de clave externa también se pueden denominar <primary key property name>.Foreign key properties can also be named <primary key property name>. Por ejemplo CourseID, dado que la clave principal de la entidad Course es CourseID.For example, CourseID since the Course entity's primary key is CourseID.

La entidad CourseThe Course entity

Diagrama de la entidad Course

En la carpeta Models, cree Course.cs con el código siguiente:In the Models folder, create Course.cs with the following code:

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; }
    }
}

La propiedad Enrollments es una propiedad de navegación.The Enrollments property is a navigation property. Una entidad Course puede estar relacionada con cualquier número de entidades Enrollment.A Course entity can be related to any number of Enrollment entities.

El atributo DatabaseGenerated permite que la aplicación especifique la clave principal en lugar de hacer que la base de datos la genere.The DatabaseGenerated attribute allows the app to specify the primary key rather than having the DB generate it.

Aplicación de scaffolding al modelo de alumnosScaffold the student model

En esta sección, se aplica scaffolding al modelo de alumnos.In this section, the student model is scaffolded. Es decir, la herramienta de scaffolding genera páginas para las operaciones de creación, lectura, actualización y eliminación (CRUD) del modelo de alumnos.That is, the scaffolding tool produces pages for Create, Read, Update, and Delete (CRUD) operations for the student model.

  • Compile el proyecto.Build the project.
  • Cree la carpeta Pages/Students.Create the Pages/Students folder.
  • En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Pages/Students > Agregar > Nuevo elemento con scaffold.In Solution Explorer, right click on the Pages/Students folder > Add > New Scaffolded Item.
  • En el cuadro de diálogo Agregar scaffold, seleccione Páginas de Razor que usan Entity Framework (CRUD) > Agregar.In the Add Scaffold dialog, select Razor Pages using Entity Framework (CRUD) > ADD.

Complete el cuadro de diálogo para agregar páginas de Razor Pages que usan Entity Framework (CRUD):Complete the Add Razor Pages using Entity Framework (CRUD) dialog:

  • En la lista desplegable Clase de modelo, seleccione Student (ContosoUniversity.Models).In the Model class drop-down, select Student (ContosoUniversity.Models).
  • En la fila Clase de contexto de datos, haga clic en el signo + (más) y cambie el nombre generado por ContosoUniversity.Models.SchoolContext.In the Data context class row, select the + (plus) sign and change the generated name to ContosoUniversity.Models.SchoolContext.
  • En la lista desplegable Clase de contexto de datos, seleccione ContosoUniversity.Models.SchoolContextIn the Data context class drop-down, select ContosoUniversity.Models.SchoolContext
  • Seleccione Agregar.Select Add.

Cuadro de diálogo CRUD

Si tiene algún problema con el paso anterior, consulte Aplicar scaffolding al modelo de película.See Scaffold the movie model if you have a problem with the preceding step.

El proceso de scaffolding ha creado y cambiado los archivos siguientes:The scaffold process created and changed the following files:

Archivos creadosFiles created

  • Pages/Students Create, Delete, Details, Edit, Index.Pages/Students Create, Delete, Details, Edit, Index.
  • Data/SchoolContext.csData/SchoolContext.cs

Actualizaciones de archivosFile updates

  • Startup.cs: en la sección siguiente se detallan los cambios realizados en este archivo.Startup.cs : Changes to this file are detailed in the next section.
  • appsettings.json: se agrega la cadena de conexión que se usa para conectarse a una base de datos local.appsettings.json : The connection string used to connect to a local database is added.

Examinar el contexto registrado con la inserción de dependenciasExamine the context registered with dependency injection

ASP.NET Core integra la inserción de dependencias.ASP.NET Core is built with dependency injection. Los servicios (como el contexto de base de datos de EF Core) se registran con inserción de dependencias durante el inicio de la aplicación.Services (such as the EF Core DB context) are registered with dependency injection during application startup. Estos servicios se proporcionan a los componentes que los necesitan (como las páginas de Razor) a través de parámetros de constructor.Components that require these services (such as Razor Pages) are provided these services via constructor parameters. El código de constructor que obtiene una instancia de contexto de base de datos se muestra más adelante en el tutorial.The constructor code that gets a db context instance is shown later in the tutorial.

La herramienta de scaffolding creó de forma automática un contexto de base de datos y lo registró con el contenedor de inserción de dependencias.The scaffolding tool automatically created a DB Context and registered it with the dependency injection container.

Examine el método ConfigureServices de Startup.cs.Examine the ConfigureServices method in Startup.cs. El proveedor de scaffolding ha agregado la línea resaltada:The highlighted line was added by the scaffolder:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for 
        //non -essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

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

El nombre de la cadena de conexión se pasa al contexto mediante una llamada a un método en un objeto DbContextOptions.The name of the connection string is passed in to the context by calling a method on a DbContextOptions object. Para el desarrollo local, el sistema de configuración de ASP.NET Core lee la cadena de conexión desde el archivo appsettings.json.For local development, the ASP.NET Core configuration system reads the connection string from the appsettings.json file.

Actualización de mainUpdate main

En Program.cs, modifique el método Main para que haga lo siguiente:In Program.cs, modify the Main method to do the following:

  • Obtener una instancia del contexto de base de datos desde el contenedor de inserción de dependencias.Get a DB context instance from the dependency injection container.
  • Llame a EnsureCreated.Call the EnsureCreated.
  • Elimine el contexto cuando finalice el método EnsureCreated.Dispose the context when the EnsureCreated method completes.

En el código siguiente se muestra el archivo Program.cs actualizado.The following code shows the updated Program.cs file.

using ContosoUniversity.Models;                   // SchoolContext
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;   // CreateScope
using Microsoft.Extensions.Logging;
using System;

namespace ContosoUniversity
{
    public class Program
    {
        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>();
                    context.Database.EnsureCreated();
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }

            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

EnsureCreated garantiza la existencia de la base de datos para el contexto.EnsureCreated ensures that the database for the context exists. Si existe, no se realiza ninguna acción.If it exists, no action is taken. Si no existe, se crean la base de datos y todo su esquema.If it does not exist, then the database and all its schema are created. En EnsureCreated no se usan migraciones para crear la base de datos.EnsureCreated does not use migrations to create the database. Una base de datos que se cree con EnsureCreated no se podrá actualizar más adelante mediante las migraciones.A database that is created with EnsureCreated cannot be later updated using migrations.

EnsureCreated se llama durante el inicio de la aplicación, lo que permite el flujo de trabajo siguiente:EnsureCreated is called on app start, which allows the following work flow:

  • Se elimina la base de datos.Delete the DB.
  • Se cambia el esquema de base de datos (por ejemplo, se agrega un campo EmailAddress).Change the DB schema (for example, add an EmailAddress field).
  • Ejecute la aplicación.Run the app.
  • EnsureCreated crea una base de datos con la columna EmailAddress.EnsureCreated creates a DB with theEmailAddress column.

EnsureCreated es útil al principio del desarrollo, cuando el esquema evoluciona rápidamente.EnsureCreated is convenient early in development when the schema is rapidly evolving. Más adelante, en el tutorial se elimina la base de datos y se usan las migraciones.Later in the tutorial the DB is deleted and migrations are used.

Prueba de la aplicaciónTest the app

Ejecute la aplicación y acepte la directiva de cookies.Run the app and accept the cookie policy. Esta aplicación no conserva información de carácter personal.This app doesn't keep personal information. Puede obtener más información sobre la directiva de cookies en Compatibilidad con el Reglamento general de protección de datos (RGPD) de la UE.You can read about the cookie policy at EU General Data Protection Regulation (GDPR) support.

  • Haga clic en el vínculo Students y, después, en Crear nuevo.Select the Students link and then Create New.
  • Pruebe los vínculos Edit, Details y Delete.Test the Edit, Details, and Delete links.

Examinar el contexto de base de datos SchoolContextExamine the SchoolContext DB context

La clase principal que coordina la funcionalidad de EF Core para un modelo de datos determinado es la clase de contexto de base de datos.The main class that coordinates EF Core functionality for a given data model is the DB context class. El contexto de datos se deriva de Microsoft.EntityFrameworkCore.DbContext.The data context is derived from Microsoft.EntityFrameworkCore.DbContext. En el contexto de datos se especifica qué entidades se incluyen en el modelo de datos.The data context specifies which entities are included in the data model. En este proyecto, la clase se denomina SchoolContext.In this project, the class is named SchoolContext.

Actualice SchoolContext.cs con el código siguiente:Update SchoolContext.cs with the following code:

using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Models
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options)
            : base(options)
        {
        }

        public DbSet<Student> Student { get; set; }
        public DbSet<Enrollment> Enrollment { get; set; }
        public DbSet<Course> Course { get; set; }
    }
}

El código resaltado crea una propiedad DbSet<TEntity > para cada conjunto de entidades.The highlighted code creates a DbSet<TEntity> property for each entity set. En la terminología de EF Core:In EF Core terminology:

  • Un conjunto de entidades normalmente se corresponde a una tabla de base de datos.An entity set typically corresponds to a DB table.
  • Una entidad se corresponde con una fila de la tabla.An entity corresponds to a row in the table.

DbSet<Enrollment> y DbSet<Course> se pueden omitir.DbSet<Enrollment> and DbSet<Course> could be omitted. EF Core las incluye implícitamente porque la entidad Student hace referencia a la entidad Enrollment y la entidad Enrollment hace referencia a la entidad Course.EF Core includes them implicitly because the Student entity references the Enrollment entity, and the Enrollment entity references the Course entity. Para este tutorial, conserve DbSet<Enrollment> y DbSet<Course> en el SchoolContext.For this tutorial, keep DbSet<Enrollment> and DbSet<Course> in the SchoolContext.

SQL Server Express LocalDBSQL Server Express LocalDB

La cadena de conexión especifica SQL Server LocalDB.The connection string specifies SQL Server LocalDB. LocalDB es una versión ligera del motor de base de datos de SQL Server Express y está dirigida al desarrollo de aplicaciones, no al uso en producción.LocalDB is a lightweight version of the SQL Server Express Database Engine and is intended for app development, not production use. LocalDB se inicia a petición y se ejecuta en modo de usuario, sin necesidad de una configuración compleja.LocalDB starts on demand and runs in user mode, so there's no complex configuration. De forma predeterminada, LocalDB crea archivos de base de datos .mdf en el directorio C:/Users/<user>.By default, LocalDB creates .mdf DB files in the C:/Users/<user> directory.

Agregar código para inicializar la base de datos con datos de pruebaAdd code to initialize the DB with test data

EF Core crea una base de datos vacía.EF Core creates an empty DB. En esta sección, se escribe un método Initialize para rellenarlo con datos de prueba.In this section, an Initialize method is written to populate it with test data.

En la carpeta Data, cree un archivo de clase denominado DbInitializer.cs y agregue el código siguiente:In the Data folder, create a new class file named DbInitializer.cs and add the following code:

using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Models
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            // context.Database.EnsureCreated();

            // Look for any students.
            if (context.Student.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.Student.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.Course.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.Enrollment.Add(e);
            }
            context.SaveChanges();
        }
    }
}

Nota: El código anterior usa Models para el espacio de nombres (namespace ContosoUniversity.Models) en lugar de Data.Note: The preceding code uses Models for the namespace (namespace ContosoUniversity.Models) rather than Data. Models es coherente con el código generado por el proveedor de scaffolding.Models is consistent with the scaffolder-generated code. Para obtener más información, consulte este problema de scaffolding de GitHub.For more information, see this GitHub scaffolding issue.

El código comprueba si hay estudiantes en la base de datos.The code checks if there are any students in the DB. Si no hay alumnos en la base de datos, se inicializa con datos de prueba.If there are no students in the DB, the DB is initialized with test data. Carga los datos de prueba en matrices en lugar de colecciones List<T> para optimizar el rendimiento.It loads test data into arrays rather than List<T> collections to optimize performance.

El método EnsureCreated crea automáticamente la base de datos para el contexto de base de datos.The EnsureCreated method automatically creates the DB for the DB context. Si la base de datos existe, EnsureCreated vuelve sin modificarla.If the DB exists, EnsureCreated returns without modifying the DB.

En Program.cs, modifique el método Main para que llame a Initialize:In Program.cs, modify the Main method to call Initialize:

public class Program
{
    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>();
                // using ContosoUniversity.Data; 
                DbInitializer.Initialize(context);
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred creating the DB.");
            }
        }

        host.Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

Elimine los registros de los alumnos y reinicie la aplicación.Delete any student records and restart the app. Si la base de datos no se ha inicializado, establezca un punto de interrupción en Initialize para diagnosticar el problema.If the DB is not initialized, set a break point in Initialize to diagnose the problem.

Ver la base de datosView the DB

El nombre de la base de datos se genera a partir del nombre de contexto proporcionado anteriormente, más un guión y un GUID.The database name is generated from the context name you provided earlier plus a dash and a GUID. Por lo tanto, el nombre de la base de datos será "SchoolContext-{GUID}".Thus, the database name will be "SchoolContext-{GUID}". El GUID será diferente para cada usuario.The GUID will be different for each user. Abra el Explorador de objetos de SQL Server (SSOX) desde el menú Vista en Visual Studio.Open SQL Server Object Explorer (SSOX) from the View menu in Visual Studio. En SSOX, haga clic en (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}.In SSOX, click (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}.

Expanda el nodo Tablas.Expand the Tables node.

Haga clic con el botón derecho en la tabla Student y haga clic en Ver datos para ver las columnas que se crearon y las filas que se insertaron en la tabla.Right-click the Student table and click View Data to see the columns created and the rows inserted into the table.

Código asincrónicoAsynchronous code

La programación asincrónica es el modo predeterminado de ASP.NET Core y EF Core.Asynchronous programming is the default mode for ASP.NET Core and EF Core.

Un servidor web tiene un número limitado de subprocesos disponibles y, en situaciones de carga alta, es posible que todos los subprocesos disponibles estén en uso.A web server has a limited number of threads available, and in high load situations all of the available threads might be in use. Cuando esto ocurre, el servidor no puede procesar nuevas solicitudes hasta que los subprocesos se liberen.When that happens, the server can't process new requests until the threads are freed up. Con el código sincrónico, se pueden acumular muchos subprocesos mientras no estén realizando ningún trabajo porque están a la espera de que finalice la E/S.With synchronous code, many threads may be tied up while they aren't actually doing any work because they're waiting for I/O to complete. Con el código asincrónico, cuando un proceso está a la espera de que finalice la E/S, se libera su subproceso para el que el servidor lo use para el procesamiento de otras solicitudes.With asynchronous code, when a process is waiting for I/O to complete, its thread is freed up for the server to use for processing other requests. Como resultado, el código asincrónico permite que los recursos de servidor se usen de forma más eficaz, y el servidor está habilitado para administrar más tráfico sin retrasos.As a result, asynchronous code enables server resources to be used more efficiently, and the server is enabled to handle more traffic without delays.

El código asincrónico introduce una pequeña cantidad de sobrecarga en tiempo de ejecución.Asynchronous code does introduce a small amount of overhead at run time. En situaciones de poco tráfico, la disminución del rendimiento es insignificante, mientras que en situaciones de tráfico elevado, la posible mejora del rendimiento es importante.For low traffic situations, the performance hit is negligible, while for high traffic situations, the potential performance improvement is substantial.

En el código siguiente, la palabra clave async, el valor devuelto Task<T>, la palabra clave await y el método ToListAsync hacen que el código se ejecute de forma asincrónica.In the following code, the async keyword, Task<T> return value, await keyword, and ToListAsync method make the code execute asynchronously.

public async Task OnGetAsync()
{
    Student = await _context.Student.ToListAsync();
}
  • La palabra clave async indica al compilador que:The async keyword tells the compiler to:

    • Genere devoluciones de llamada para partes del cuerpo del método.Generate callbacks for parts of the method body.
    • Cree automáticamente el objeto Task que se devuelve.Automatically create the Task object that's returned. Para más información, vea Tipo de valor devuelto Task.For more information, see Task Return Type.
  • El tipo devuelto implícito Task representa el trabajo en curso.The implicit return type Task represents ongoing work.

  • La palabra clave await hace que el compilador divida el método en dos partes.The await keyword causes the compiler to split the method into two parts. La primera parte termina con la operación que se inició de forma asincrónica.The first part ends with the operation that's started asynchronously. La segunda parte se coloca en un método de devolución de llamada que se llama cuando finaliza la operación.The second part is put into a callback method that's called when the operation completes.

  • ToListAsync es la versión asincrónica del método de extensión ToList.ToListAsync is the asynchronous version of the ToList extension method.

Algunos aspectos que tener en cuenta al escribir código asincrónico en el que se usa EF Core son los siguientes:Some things to be aware of when writing asynchronous code that uses EF Core:

  • Solo se ejecutan de forma asincrónica las instrucciones que hacen que las consultas o los comandos se envíen a la base de datos.Only statements that cause queries or commands to be sent to the DB are executed asynchronously. Esto incluye ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync y SaveChangesAsync.That includes, ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync, and SaveChangesAsync. No incluye las instrucciones que solo cambian una IQueryable, como var students = context.Students.Where(s => s.LastName == "Davolio").It doesn't include statements that just change an IQueryable, such as var students = context.Students.Where(s => s.LastName == "Davolio").
  • Un contexto de EF Core no es seguro para subprocesos: no intente realizar varias operaciones en paralelo.An EF Core context isn't thread safe: don't try to do multiple operations in parallel.
  • Para aprovechar las ventajas de rendimiento del código asincrónico, compruebe que en los paquetes de biblioteca (por ejemplo para paginación) se usa async si llaman a métodos de EF Core que envían consultas a la base de datos.To take advantage of the performance benefits of async code, verify that library packages (such as for paging) use async if they call EF Core methods that send queries to the DB.

Para obtener más información sobre la programación asincrónica en .NET, vea Programación asincrónica y Programación asincrónica con async y await.For more information about asynchronous programming in .NET, see Async Overview and Asynchronous programming with async and await.

En el siguiente tutorial, se examinan las operaciones CRUD (crear, leer, actualizar y eliminar) básicas.In the next tutorial, basic CRUD (create, read, update, delete) operations are examined.

Recursos adicionalesAdditional resources