Escenarios avanzados de Entity Framework para una aplicación web MVC (10 de 10)

Por Tom Dykstra

En la aplicación web de ejemplo Contoso University se muestra cómo crear aplicaciones de ASP.NET MVC 4 con Code First de Entity Framework 5 y Visual Studio 2012. Para obtener información sobre la serie de tutoriales, consulte el primer tutorial de la serie.

Nota:

Si se encuentra con un problema que no puede resolver, descargue el capítulo completado e intente reproducir el problema. Por lo general, puede encontrar la solución al problema si compara el código con el código completado. Para obtener algunos errores comunes y cómo resolverlos, vea Errores y soluciones alternativas.

En el tutorial anterior ha implementado el repositorio y la unidad de patrones de trabajo. En este tutorial se tratan los temas siguientes:

  • Realización de consultas SQL sin formato.
  • Realización de consultas sin seguimiento.
  • Examen de consultas enviadas a la base de datos.
  • Uso de clases de proxy.
  • Deshabilitación de la detección automática de cambios.
  • Deshabilitación de la validación al guardar los cambios.
  • Errores y soluciones alternativas

Para la mayoría de estos temas, trabajará con páginas que ya ha creado. Para usar SQL sin procesar a fin de realizar actualizaciones masivas, creará una página que actualiza el número de créditos de todos los cursos de la base de datos:

Screenshot showing the Update Course Credits initial page. The number 2 is entered in the text field.

Y para usar una consulta sin seguimiento, agregará nueva lógica de validación a la página Editar departamento:

Screenshot that shows the Contoso University Department Edit page with a duplicate administrator error message.

Realización de consultas SQL sin formato

La API Code First de Entity Framework incluye métodos que le permiten pasar comandos SQL directamente a la base de datos. Tiene las siguientes opciones:

  • Use el método DbSet.SqlQuery para las consultas que devuelven tipos de entidad. Los objetos devueltos deben ser del tipo esperado por el objeto DbSet y se realiza automáticamente su seguimiento mediante el contexto de base de datos a menos que se desactive el seguimiento. (Vea la sección siguiente sobre el método AsNoTracking).
  • Use el método Database.SqlQuery para las consultas que devuelven tipos que no son entidades. No se realiza un seguimiento de los datos devueltos por el contexto de la base de datos, incluso si usa este método para recuperar tipos de entidad.
  • Use Database.ExecuteSqlCommand para comandos que no son de consulta.

Una de las ventajas del uso de Entity Framework es que evita enlazar el código demasiado estrechamente a un método concreto de almacenamiento de datos. Lo consigue mediante la generación de consultas SQL y comandos, lo que también le evita tener que escribirlos usted mismo. Pero hay situaciones excepcionales en las que necesita ejecutar consultas específicas de SQL que ha creado manualmente y estos métodos permiten controlar estas excepciones.

Como siempre es true cuando ejecuta comandos SQL en una aplicación web, debe tomar precauciones para proteger su sitio contra los ataques por inyección de código SQL. Una manera de hacerlo es mediante consultas parametrizadas para asegurarse de que las cadenas enviadas por una página web no se pueden interpretar como comandos SQL. En este tutorial usará las consultas con parámetros al integrar la entrada de usuario en una consulta.

Llamada a una consulta que devuelve entidades

Imagine que quiere que la clase GenericRepository proporcione flexibilidad adicional de filtrado y ordenación sin necesidad de crear una clase derivada con métodos adicionales. Una manera de lograr esto sería agregar un método que acepte una consulta SQL. Después, podría especificar cualquier tipo de filtrado u ordenación que quiera en el controlador, como una cláusula Where que depende de una combinación o una subconsulta. En esta sección verá cómo implementar este tipo de método.

Para crear el método GetWithRawSql, agregue el código siguiente a GenericRepository.cs:

public virtual IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters)
{
    return dbSet.SqlQuery(query, parameters).ToList();
}

En CourseController.cs, llame al nuevo método desde el método Details, como se muestra en el ejemplo siguiente:

public ActionResult Details(int id)
{
    var query = "SELECT * FROM Course WHERE CourseID = @p0";
    return View(unitOfWork.CourseRepository.GetWithRawSql(query, id).Single());
}

En este caso, podría haber usado el método GetByID, pero utiliza el método GetWithRawSql para comprobar que el método GetWithRawSQL funciona.

Ejecute la página Detalles para comprobar que la consulta de selección funciona (seleccione la pestaña Curso y, después, Detalles de un curso).

Screenshot that shows the Contoso University Details page.

Llamada a una consulta que devuelve otros tipos de objetos

Anteriormente creó una cuadrícula de estadísticas de alumno de la página About que mostraba el número de alumnos para cada fecha de inscripción. El código que hace esto en HomeController.cs usa LINQ:

var data = from student in db.Students
           group student by student.EnrollmentDate into dateGroup
           select new EnrollmentDateGroup()
           {
               EnrollmentDate = dateGroup.Key,
               StudentCount = dateGroup.Count()
           };

Imagine que quiere escribir el código que recupera estos datos directamente en SQL en lugar de usar LINQ. Para ello, debe ejecutar una consulta que devuelva algo que no sean objetos de entidad, lo que significa que debe usar el método Database.SqlQuery.

En HomeController.cs, reemplace la instrucción LINQ del método About por el código siguiente:

var query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
    + "FROM Person "
    + "WHERE EnrollmentDate IS NOT NULL "
    + "GROUP BY EnrollmentDate";
var data = db.Database.SqlQuery<EnrollmentDateGroup>(query);

Ejecute la página Acerca de. Muestra los mismos datos que anteriormente.

Screenshot that shows the Contoso University About page.

Llamada a una consulta de actualización

Imagine que los administradores de Contoso University quieren realizar cambios masivos en la base de datos, como cambiar el número de créditos de cada curso. Si la universidad tiene un gran número de cursos, sería poco eficaz recuperarlos todos como entidades y cambiarlos de forma individual. En esta sección implementará una página web que permite al usuario especificar un factor por el que cambiar el número de créditos para todos los cursos y podrá realizar el cambio mediante la ejecución de una instrucción UPDATE de SQL. La página web tendrá el mismo aspecto que la ilustración siguiente:

Screenshot that shows the Update Course Credits initial page. The number 2 is entered in the text field.

En el tutorial anterior ha usado el repositorio genérico para leer y actualizar entidades Course en el controlador Course. Para esta operación de actualización masiva, debe crear un método de repositorio que no esté en el repositorio genérico. Para ello, creará una clase CourseRepository dedicada que derive de la clase GenericRepository.

En la carpeta DAL, cree CourseRepository.cs y reemplace el código existente por el siguiente:

using System;
using ContosoUniversity.Models;

namespace ContosoUniversity.DAL
{
    public class CourseRepository : GenericRepository<Course>
    {
        public CourseRepository(SchoolContext context)
            : base(context)
        {
        }

        public int UpdateCourseCredits(int multiplier)
        {
            return context.Database.ExecuteSqlCommand("UPDATE Course SET Credits = Credits * {0}", multiplier);
        }

    }
}

En UnitOfWork.cs, cambie el tipo de repositorio Course de GenericRepository<Course> a CourseRepository:

private CourseRepository courseRepository;
public CourseRepository CourseRepository
{
    get
    {

        if (this.courseRepository == null)
        {
            this.courseRepository = new CourseRepository(context);
        }
        return courseRepository;
    }
}

En CourseController.cs, agregue un método UpdateCourseCredits:

public ActionResult UpdateCourseCredits(int? multiplier)
{
    if (multiplier != null)
    {
        ViewBag.RowsAffected = unitOfWork.CourseRepository.UpdateCourseCredits(multiplier.Value);
    }
    return View();
}

Este método se usará para HttpGet y HttpPost. Cuando se ejecuta el métodoHttpGetUpdateCourseCredits, la variable multiplier será null y en la vista se mostrará un cuadro de texto vacío y un botón enviar, como se muestra en la ilustración anterior.

Cuando se hace clic en el botón Actualizar y se ejecuta el método HttpPost, en multiplier se muestra el valor escrito en el cuadro de texto. Después, el código llama al método de repositorio UpdateCourseCredits, que devuelve el número de filas afectadas y ese valor se almacena en el objeto ViewBag. Cuando la vista recibe el número de filas afectadas en el objeto ViewBag, muestra ese número en lugar del cuadro de texto y el botón Enviar, como se muestra en la ilustración siguiente:

Screenshot that shows the Contoso University Update Course Credits rows affected page.

Cree una vista en la carpeta Views\Course de la página Actualizar créditos del curso:

Screenshot that shows the Add View dialog box. Update Course Credits is entered in the View name text field.

En Views\Course\UpdateCourseCredits.cshtml, reemplace el código de plantilla con el código siguiente:

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "UpdateCourseCredits";
}

<h2>Update Course Credits</h2>

@if (ViewBag.RowsAffected == null)
{
    using (Html.BeginForm())
    {
        <p>
            Enter a number to multiply every course's credits by: @Html.TextBox("multiplier")
        </p>
        <p>
            <input type="submit" value="Update" />
        </p>
    }
}
@if (ViewBag.RowsAffected != null)
{
    <p>
        Number of rows updated: @ViewBag.RowsAffected
    </p>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Ejecute el método UpdateCourseCredits seleccionando la pestaña Courses, después, agregue "/UpdateCourseCredits" al final de la dirección URL en la barra de direcciones del explorador (por ejemplo: http://localhost:50205/Course/UpdateCourseCredits). Escriba un número en el cuadro de texto:

Screenshot showing the Update Course Credits initial page with the number 2 entered in the text field.

Haga clic en Actualizar. Verá el número de filas afectadas:

Screenshot that shows the Update Course Credits page with the number of rows updated.

Haga clic en Volver a la lista para ver la lista de cursos con el número de créditos revisado.

Screenshot that shows the Courses Index page. A list of courses is shown with the revised number of credits.

Para más información sobre consultas SQL básicas, vea Consultas SQL básicas en el blog del equipo de Entity Framework.

Consultas de no seguimiento

Cuando un contexto de base de datos recupera las filas de tabla y crea objetos de entidad que las representan, de forma predeterminada realiza el seguimiento de si las entidades en memoria están sincronizadas con el contenido de la base de datos. Los datos en memoria actúan como una caché y se usan cuando se actualiza una entidad. Este almacenamiento en caché suele ser necesario en una aplicación web porque las instancias de contexto normalmente son de corta duración (para cada solicitud se crea una y se elimina) y el contexto que lee una entidad normalmente se elimina antes de volver a usar esa entidad.

Puede especificar si el contexto realiza el seguimiento de los objetos de entidad de una consulta con el método AsNoTracking. Los siguientes son escenarios típicos en los que es posible que quiera hacer esto:

  • Una consulta recupera un volumen de datos tan grande que desactivar el seguimiento podría mejorar notablemente el rendimiento.
  • Quiere adjuntar una entidad para actualizarla, pero anteriormente ha recuperado la misma entidad para un propósito diferente. Como el contexto de base de datos ya está realizando el seguimiento de la entidad, no se puede adjuntar la entidad que se quiere cambiar. Una manera de evitar que esto suceda es usar la opción AsNoTracking con la consulta anterior.

En esta sección, implementará la lógica de negocios que ilustra el segundo de estos escenarios. En concreto, aplicará una regla de negocios que indique que un instructor no puede ser el administrador de más de un departamento.

En DepartmentController.cs, agregue un nuevo método al que puede llamar desde los métodosEdit y Create para asegurarse de que no hay dos departamentos con el mismo administrador:

private void ValidateOneAdministratorAssignmentPerInstructor(Department department)
{
    if (department.PersonID != null)
    {
        var duplicateDepartment = db.Departments
            .Include("Administrator")
            .Where(d => d.PersonID == department.PersonID)
            .FirstOrDefault();
        if (duplicateDepartment != null && duplicateDepartment.DepartmentID != department.DepartmentID)
        {
            var errorMessage = String.Format(
                "Instructor {0} {1} is already administrator of the {2} department.",
                duplicateDepartment.Administrator.FirstMidName,
                duplicateDepartment.Administrator.LastName,
                duplicateDepartment.Name);
            ModelState.AddModelError(string.Empty, errorMessage);
        }
    }
}

Agregue código en el bloque try del método HttpPostEdit para llamar a este nuevo método si no hay errores de validación. El bloque try ahora es similar al del ejemplo siguiente:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
   [Bind(Include = "DepartmentID, Name, Budget, StartDate, RowVersion, PersonID")]
    Department department)
{
   try
   {
      if (ModelState.IsValid)
      {
         ValidateOneAdministratorAssignmentPerInstructor(department);
      }

      if (ModelState.IsValid)
      {
         db.Entry(department).State = EntityState.Modified;
         db.SaveChanges();
         return RedirectToAction("Index");
      }
   }
   catch (DbUpdateConcurrencyException ex)
   {
      var entry = ex.Entries.Single();
      var clientValues = (Department)entry.Entity;

Ejecute la página Editar departamento e intente cambiar el administrador de un departamento a un instructor que ya sea el administrador de otro departamento. Se produce el mensaje de error esperado:

Screenshot showing the Department Edit page with a duplicate administrator error message.

Ahora vuelva a ejecutar la página Editar departamento y esta vez cambie el importe de Presupuesto. Al hacer clic en Guardar, verá una página de error:

Screenshot that shows the Department Edit page with an object state manager error message.

El mensaje de error de excepción es "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." Esto se debe a la siguiente secuencia de eventos:

  • El método Edit llama al método ValidateOneAdministratorAssignmentPerInstructor, que recupera todos los departamentos que tienen Kim Abercrombie como administrador. Esto hace que se lea el departamento de inglés. Como es el departamento que se modifica, no se notifica ningún error. Pero como resultado de esta operación de lectura, ahora el contexto de la base de datos realiza el seguimiento de la entidad del departamento de inglés que se ha leído de la base de datos.
  • El método Edit intenta establecer la marca Modified en la entidad Departamento de inglés creada por el enlazador de modelos de MVC, pero eso genera un error porque el contexto ya realiza el seguimiento de una entidad para el Departamento de inglés.

Una solución a este problema consiste en evitar que el contexto realice el seguimiento de las entidades de departamento en memoria recuperadas por la consulta de validación. Hacerlo no supone ninguna desventaja, ya que no va a actualizar esta entidad ni volver a leerla de una forma que se beneficie por almacenarse en caché en la memoria.

En DepartmentController.cs, en el método ValidateOneAdministratorAssignmentPerInstructor, especifique que no hay seguimiento, como se muestra a continuación:

var duplicateDepartment = db.Departments
   .Include("Administrator")
   .Where(d => d.PersonID == department.PersonID)
   .AsNoTracking()
   .FirstOrDefault();

Repita el intento de editar el importe de Presupuesto de un departamento. Esta vez la operación se realiza correctamente y el sitio devuelve como se esperaba en la página Índice de departamentos, y muestra el valor de presupuesto revisado.

Examen de consultas enviadas a la base de datos

A veces resulta útil poder ver las consultas SQL reales que se envían a la base de datos. Para ello, puede examinar una variable de consulta en el depurador o llamar al método ToString de la consulta. Para probar esto, verá una consulta sencilla y, después, verá lo que le sucede a medida que agrega opciones como las de carga diligente, filtrado y ordenación.

En Controllers\CourseController, reemplace el método Index por el código siguiente:

public ViewResult Index()
{
    var courses = unitOfWork.CourseRepository.Get();
    return View(courses.ToList());
}

Ahora establezca un punto de interrupción en GenericRepository.cs en las instrucciones return query.ToList();y return orderBy(query).ToList(); del método Get. Ejecute el proyecto en modo de depuración y seleccione la página Índice de cursos. Cuando el código alcance el punto de interrupción, examine la variable query. Verá la consulta que se envía a SQL Server. Es una instrucción Select sencilla:

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID]
FROM [Course] AS [Extent1]}

Screenshot that shows the sample web application Generic Repository tab. The query variable is selected.

Las consultas pueden ser demasiado largas para mostrarse en las ventanas de depuración de Visual Studio. Para ver toda la consulta, puede copiar el valor de la variable y pegarlo en un editor de texto:

Screenshot that shows the variable value with a dropdown menu displayed when it is selected. The Copy Value option is highlighted.

Ahora agregará una lista desplegable a la página Índice de cursos para que los usuarios puedan filtrar por un departamento determinado. Ordenará los cursos por título y especificará la carga diligente de la propiedad de navegación Department. En CourseController.cs, reemplace el método Index por el siguiente código:

public ActionResult Index(int? SelectedDepartment)
{
    var departments = unitOfWork.DepartmentRepository.Get(
        orderBy: q => q.OrderBy(d => d.Name));
    ViewBag.SelectedDepartment = new SelectList(departments, "DepartmentID", "Name", SelectedDepartment);

    int departmentID = SelectedDepartment.GetValueOrDefault(); 
    return View(unitOfWork.CourseRepository.Get(
        filter: d => !SelectedDepartment.HasValue || d.DepartmentID == departmentID,
        orderBy: q => q.OrderBy(d => d.CourseID),
        includeProperties: "Department"));
}

El método recibe el valor seleccionado de la lista desplegable en el parámetro SelectedDepartment. Si no se selecciona nada, este parámetro será null.

Se pasa una colección SelectList que contiene todos los departamentos a la vista de la lista desplegable. Los parámetros pasados al constructor SelectList especifican el nombre del campo de valor, el nombre del campo de texto y el elemento seleccionado.

Para el método Get del repositorio Course, el código especifica una expresión de filtro, un criterio de ordenación y una carga diligente para la propiedad de navegación Department. La expresión de filtro siempre devuelve true si no se selecciona nada en la lista desplegable (es decir, SelectedDepartment es null).

En Views\Course\Index.cshtml, inmediatamente antes de la etiqueta table de apertura, agregue el siguiente código para crear la lista desplegable y un botón enviar:

@using (Html.BeginForm())
{
    <p>Select Department: @Html.DropDownList("SelectedDepartment","All")   
    <input type="submit" value="Filter" /></p>
}

Con los puntos de interrupción aún establecidos en la clase GenericRepository, ejecute la página Índice de cursos. Continúe por las dos primeras veces que el código alcanza un punto de interrupción, de modo que la página se muestre en el explorador. Seleccione un departamento en la lista desplegable y haga clic en Filtrar:

Screenshot that shows the Course Index page with the Economics Department selected.

Esta vez el primer punto de interrupción será para la consulta de departamentos para la lista desplegable. Omita eso y vea la variable query la siguiente vez que el código alcance el punto de interrupción para ver el aspecto de la consulta Course. Verá algo parecido a lo siguiente:

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID], 
[Extent2].[DepartmentID] AS [DepartmentID1], 
[Extent2].[Name] AS [Name], 
[Extent2].[Budget] AS [Budget], 
[Extent2].[StartDate] AS [StartDate], 
[Extent2].[PersonID] AS [PersonID], 
[Extent2].[Timestamp] AS [Timestamp]
FROM  [Course] AS [Extent1]
INNER JOIN [Department] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID]
WHERE (@p__linq__0 IS NULL) OR ([Extent1].[DepartmentID] = @p__linq__1)}

Puede ver que la consulta es ahora una consulta JOIN que carga datos Department junto con los datos Course y que incluye una cláusula WHERE.

Uso de clases de proxy

Cuando Entity Framework crea instancias de entidad (por ejemplo, al ejecutar una consulta) a menudo las crea como instancias de un tipo derivado generado dinámicamente que actúa como proxy para la entidad. Este proxy invalida algunas propiedades virtuales de la entidad para insertar enlaces para realizar acciones automáticamente cuando se accede a la propiedad. Por ejemplo, este mecanismo se usa para admitir la carga diferida de relaciones.

La mayoría de las veces no es necesario tener en cuenta este uso de servidores proxy, pero hay excepciones:

  • En algunos escenarios, es posible que quiera impedir que Entity Framework cree instancias de proxy. Por ejemplo, la serialización de instancias que no son de proxy es considerablemente más fácil que la de instancias de proxy.
  • Al crear una instancia de una clase de entidad mediante el operador new, no se obtiene una instancia de proxy. Esto significa que no obtiene funcionalidad como la de carga diferida y seguimiento automático de cambios. Esto suele ser correcto; por lo general, no necesita carga diferida, ya que va a crear una entidad que no está en la base de datos y, por lo general, no necesita seguimiento de cambios si va a marcar explícitamente la entidad como Added. Pero si necesita carga diferida y seguimiento de cambios, puede crear instancias de entidad con servidores proxy mediante el método Create de la clase DbSet.
  • Es posible que quiera obtener un tipo de entidad real de un tipo de proxy. Puede usar el método GetObjectType de la clase ObjectContext para obtener el tipo de entidad real de una instancia de tipo proxy.

Para más información, vea Trabajo con proxies en el blog del equipo de Entity Framework.

Deshabilitación de la detección automática de cambios

Entity Framework determina cómo ha cambiado una entidad (y, por tanto, las actualizaciones que hay que enviar a la base de datos) comparando los valores actuales de una entidad con los valores originales. Cuando se consulta o se adjunta la entidad, se almacenan los valores originales. Algunos de los métodos que provocan la detección de cambios automática son los siguientes:

  • DbSet.Find
  • DbSet.Local
  • DbSet.Remove
  • DbSet.Add
  • DbSet.Attach
  • DbContext.SaveChanges
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries

Si va realizar el seguimiento de un gran número de entidades y llama a uno de estos métodos muchas veces en un bucle, podría obtener mejoras de rendimiento significativas si desactiva temporalmente la detección de cambios automática mediante la propiedad AutoDetectChangesEnabled. Para más información, vea Detección automática de cambios.

Deshabilitación de la validación al guardar los cambios

Cuando se llama al método SaveChanges, de forma predeterminada, Entity Framework valida los datos en todas las propiedades de todas las entidades modificadas antes de actualizar la base de datos. Si ha actualizado un gran número de entidades y ya ha validado los datos, este trabajo no es necesario y podría hacer que el proceso de guardar los cambios tarde menos tiempo si desactiva temporalmente la validación. Puede hacerlo mediante la propiedad ValidateOnSaveEnabled. Para obtener más información, vea Validación.

Resumen

Con esto finaliza esta serie de tutoriales sobre cómo usar Entity Framework en una aplicación ASP.NET MVC. En el mapa de contenido de acceso a datos de ASP.NET pueden encontrar vínculos a otros recursos de Entity Framework.

Para más información sobre cómo implementar la aplicación web después de compilarla, vea Mapa de contenido de implementación de ASP.NET en la biblioteca de MSDN.

Para obtener información sobre otros temas relacionados con MVC, como los de autenticación y autorización, vea Recursos recomendados de MVC.

Agradecimientos

  • Tom Dykstra escribió la versión original de este tutorial y es un escritor de programación sénior en el equipo de contenido de plataforma web y herramientas de Microsoft.
  • Rick Anderson (twitter @RickAndMSFT) es el otro creador de este tutorial y se encargó de la mayor parte del trabajo de actualización de EF 5 y MVC 4. Rick es escritor de programación sénior para Microsoft, especializado en Azure y MVC.
  • Rowan Miller y otros miembros del equipo de Entity Framework ayudaron a revisar el código y a depurar muchos problemas con las migraciones que se produjeron mientras se actualizaba el tutorial para EF 5 y EF 6.

VB

Cuando se creó originalmente el tutorial, proporcionamos versiones de C# y VB del proyecto de descarga completado. En esta actualización, se proporciona un proyecto descargable de C# para cada capítulo a fin de facilitar la introducción en cualquier parte de la serie, pero debido a limitaciones de tiempo y otras prioridades no se hizo para VB. Si compila un proyecto de VB con estos tutoriales y le gustaría compartirlo con otros usuarios, háganoslo saber.

Errores y soluciones alternativas

No se puede crear ni crear una propiedad reemplazada

Mensaje de error:

No se puede crear ni crear una propiedad reemplazada de "DotNetOpenAuth.OpenId" cuando ese archivo ya existe.

Solución:

Espere unos segundos y actualice la página.

No se reconoce Update-Database

Mensaje de error:

El término "Update-Database" no se reconoce como nombre de un cmdlet, función, archivo de script o programa ejecutable. Compruebe si escribió correctamente el nombre o, si incluyó una ruta de acceso, compruebe que dicha ruta es correcta e inténtelo de nuevo.(Desde el comando Update-Database de PMC).

Solución:

Salga de Visual Studio. Vuelva a abrir el proyecto e inténtelo de nuevo.

Error de validación

Mensaje de error:

Error de validación para una o varias entidades. Vea la propiedad "EntityValidationErrors" para más información. (Desde el comando Update-Database de PMC).

Solución:

Una causa de este problema son los errores de validación cuando se ejecuta el método Seed. VeaInicialización y depuración de bases de datos de Entity Framework (EF) para obtener sugerencias sobre cómo depurar el método Seed.

Error HTTP 500.19

Mensaje de error:

Error HTTP 500.19: error interno del servidor
No se puede acceder a la página solicitada porque los datos de configuración relacionados de la página no son válidos.

Solución:

Este error se puede producir por tener varias copias de la solución, cada una con el mismo número de puerto. Normalmente puede resolver este problema si sale de todas las instancias de Visual Studio y, después, reinicia el proyecto en el que trabaja. Si eso no funciona, intente cambiar el número de puerto. Haga clic con el botón derecho en el archivo del proyecto y, después, haga clic en Propiedades. Seleccione la pestaña Web y, después, cambie el número de puerto en el cuadro de texto Dirección URL del proyecto.

Error al buscar la instancia de SQL Server

Mensaje de error:

Error relacionado con la red o específico de la instancia mientras se establecía una conexión con el servidor SQL Server. No se encontró el servidor o no era accesible. Compruebe que el nombre de la instancia es correcto y que SQL Server está configurado para admitir conexiones remotas. (proveedor: Interfaces de red SQL, error: 26: error al buscar el servidor o la instancia especificados)

Solución:

Compruebe la cadena de conexión. Si ha eliminado manualmente la base de datos, cambie el nombre de la base de datos en la cadena de construcción.