Compartilhar via


Cenários avançados do Entity Framework para um aplicativo Web MVC (10 de 10)

por Tom Dykstra

O aplicativo Web de exemplo da Contoso University demonstra como criar aplicativos MVC 4 ASP.NET usando o Entity Framework 5 Code First e o Visual Studio 2012. Para obter informações sobre a série de tutoriais, consulte o primeiro tutorial da série.

Observação

Se você tiver um problema que não consegue resolver, baixe o capítulo completo e tente reproduzir seu problema. Geralmente, você pode encontrar a solução para o problema comparando seu código com o código concluído. Para obter alguns erros comuns e como resolvê-los, consulte Erros e soluções alternativas.

No tutorial anterior, você implementou o repositório e a unidade de padrões de trabalho. Este tutorial abrange os seguintes tópicos:

  • Executando consultas SQL brutas.
  • Executar consultas sem rastreamento.
  • Examinar consultas enviadas ao banco de dados.
  • Trabalhando com classes proxy.
  • Desativando a detecção automática de alterações.
  • Desativando a validação ao salvar alterações.
  • Erros e soluções alternativas

Para a maioria desses tópicos, você trabalhará com páginas que já criou. Para usar o SQL bruto para fazer atualizações em massa, você criará uma nova página que atualiza o número de créditos de todos os cursos no banco de dados:

Captura de tela mostrando a página inicial Atualizar créditos do curso. O número 2 é inserido no campo de texto.

E para usar uma consulta sem rastreamento, você adicionará uma nova lógica de validação à página Editar departamento:

Captura de tela que mostra a página Editar do Departamento da Contoso University com uma mensagem de erro de administrador duplicada.

Executando consultas SQL brutas

A API do Entity Framework Code First inclui métodos que permitem passar comandos SQL diretamente para o banco de dados. Você tem as seguintes opções:

  • Use o método DbSet.SqlQuery para consultas que retornam tipos de entidade. Os objetos retornados devem ser do tipo esperado pelo DbSet objeto e são rastreados automaticamente pelo contexto do banco de dados, a menos que você desative o rastreamento. (Consulte a seção a seguir sobre o AsNoTracking método.)
  • Use o Database.SqlQuery método para consultas que retornam tipos que não são entidades. Os dados retornados não são controlados pelo contexto de banco de dados, mesmo se esse método é usado para recuperar tipos de entidade.
  • Use o Database.ExecuteSqlCommand para comandos que não são de consulta.

Uma das vantagens de usar o Entity Framework é que ele evita vincular o código de forma muito próxima a um método específico de armazenamento de dados. Ele faz isso pela geração de consultas SQL e comandos para você, que também libera você da necessidade de escrevê-los. Mas há cenários excepcionais em que você precisa executar consultas SQL específicas criadas manualmente, e esses métodos possibilitam que você lide com essas exceções.

Como é sempre verdadeiro quando você executa comandos SQL em um aplicativo Web, é necessário tomar precauções para proteger o site contra ataques de injeção de SQL. Uma maneira de fazer isso é usar consultas parametrizadas para garantir que as cadeias de caracteres enviadas por uma página da Web não possam ser interpretadas como comandos SQL. Neste tutorial, você usará consultas parametrizadas ao integrar a entrada do usuário a uma consulta.

Chamando uma consulta que retorna entidades

Suponha que você queira que a GenericRepository classe forneça filtragem adicional e Uma maneira de conseguir isso seria adicionar um método que aceite uma consulta SQL. Em seguida, você pode especificar qualquer tipo de filtragem ou classificação desejada no controlador, como uma Where cláusula que depende de uma junção ou de uma subconsulta. Nesta seção, você verá como implementar esse método.

Crie o GetWithRawSql método adicionando o seguinte código a GenericRepository.cs:

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

Em CourseController.cs, chame o novo método do Details método, conforme mostrado no exemplo a seguir:

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

Nesse caso, você poderia ter usado o GetByID método, mas está usando o GetWithRawSql método para verificar se o GetWithRawSQL método funciona.

Execute a página Detalhes para verificar se a consulta seleção funciona (selecione a guia Curso e, em seguida, Detalhes de um curso).

Captura de tela que mostra a página Detalhes da Contoso University.

Chamando uma consulta que retorna outros tipos de objetos

Anteriormente, você criou uma grade de estatísticas de alunos para a página Sobre que mostrava o número de alunos para cada data de registro. O código que faz isso no 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()
           };

Suponha que você queira escrever o código que recupera esses dados diretamente no SQL, em vez de usar o LINQ. Para fazer isso, você precisa executar uma consulta que retorne algo diferente de objetos de entidade, o que significa que você precisa usar o Database.SqlQuery método.

Em HomeController.cs, substitua a instrução LINQ no About método pelo seguinte código:

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

Execute a página Sobre. Ela exibe os mesmos dados que antes.

Captura de tela que mostra a página Sobre da Contoso University.

Chamando uma consulta de atualização

Suponha que os administradores da Contoso University queiram executar alterações em massa no banco de dados, como alterar o número de créditos para cada curso. Se a universidade tiver uma grande quantidade de cursos, poderá ser ineficiente recuperá-los como entidades e alterá-los individualmente. Nesta seção, você implementará uma página da Web que permite ao usuário especificar um fator pelo qual alterar o número de créditos para todos os cursos e fará a alteração executando uma instrução SQL UPDATE . A página da Web será semelhante à seguinte ilustração:

Captura de tela que mostra a página inicial Atualizar créditos do curso. O número 2 é inserido no campo de texto.

No tutorial anterior, você usou o repositório genérico para ler e atualizar Course entidades no Course controlador. Para essa operação de atualização em massa, você precisa criar um novo método de repositório que não esteja no repositório genérico. Para fazer isso, você criará uma classe dedicada CourseRepository que deriva da GenericRepository classe.

Na pasta DAL, crie CourseRepository.cs e substitua o código existente pelo seguinte código:

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

    }
}

Em UnitOfWork.cs, altere o Course tipo de repositório de GenericRepository<Course> para CourseRepository:

private CourseRepository courseRepository;
public CourseRepository CourseRepository
{
    get
    {

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

Em CourseController.cs, adicione um UpdateCourseCredits método:

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

Este método será usado para ambos e HttpGet HttpPost. Quando o HttpGet UpdateCourseCredits método for executado, a multiplier variável será nula e o modo de exibição exibirá uma caixa de texto vazia e um botão de envio, conforme mostrado na ilustração anterior.

Quando o botão Atualizar for clicado e o HttpPost método for executado, multiplier terá o valor inserido na caixa de texto. Em seguida, o código chama o método repository UpdateCourseCredits , que retorna o número de linhas afetadas, e esse valor é armazenado no ViewBag objeto. Quando o modo de exibição recebe o número de linhas afetadas no ViewBag objeto, ele exibe esse número em vez da caixa de texto e do botão enviar, conforme mostrado na ilustração a seguir:

Captura de tela que mostra a página afetada das linhas de Créditos do Curso de Atualização da Contoso University.

Crie uma visualização na pasta Visualizações\Curso para a página Atualizar créditos do curso:

Captura de tela que mostra a caixa de diálogo Adicionar Exibição. Atualizar créditos do curso é inserido no campo de texto Nome da exibição.

Em Views\Course\UpdateCourseCredits.cshtml, substitua o código do modelo pelo seguinte código:

@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>

Execute o método UpdateCourseCredits selecionando a guia Cursos, adicionando, em seguida, "/UpdateCourseCredits" ao final da URL na barra de endereços do navegador (por exemplo: http://localhost:50205/Course/UpdateCourseCredits). Insira um número na caixa de texto:

Captura de tela mostrando a página inicial Atualizar créditos do curso com o número 2 inserido no campo de texto.

Clique em Atualizar. O número de linhas afetadas é exibido:

Captura de tela que mostra a página Atualizar créditos do curso com o número de linhas atualizadas.

Clique em Voltar para a Lista para ver a lista de cursos com o número revisado de créditos.

Captura de tela que mostra a página Índice de cursos. Uma lista de cursos é mostrada com o número revisado de créditos.

Para obter mais informações sobre consultas SQL brutas, consulte Consultas SQL brutas no blog da equipe do Entity Framework.

Consultas sem acompanhamento

Quando um contexto de banco de dados recupera linhas de banco de dados e cria objetos de entidade que as representam, por padrão, ele controla se as entidades na memória estão sincronizadas com o que está no banco de dados. Os dados em memória atuam como um cache e são usados quando uma entidade é atualizada. Esse cache costuma ser desnecessário em um aplicativo Web porque as instâncias de contexto são normalmente de curta duração (uma nova é criada e descartada para cada solicitação) e o contexto que lê uma entidade normalmente é descartado antes que essa entidade seja usada novamente.

Você pode especificar se o contexto rastreia objetos de entidade para uma consulta usando o AsNoTracking método. Os cenários típicos em que talvez você deseje fazer isso incluem os seguintes:

  • A consulta recupera um volume tão grande de dados que desativar o rastreamento pode melhorar visivelmente o desempenho.
  • Você deseja anexar uma entidade para atualizá-la, mas anteriormente recuperou a mesma entidade para uma finalidade diferente. Como a entidade já está sendo controlada pelo contexto de banco de dados, não é possível anexar a entidade que você deseja alterar. Uma maneira de evitar que isso aconteça é usar a AsNoTracking opção com a consulta anterior.

Nesta seção, você implementará a lógica de negócios que ilustra o segundo desses cenários. Especificamente, você aplicará uma regra de negócios que diz que um instrutor não pode ser o administrador de mais de um departamento.

Em DepartmentController.cs, adicione um novo método que você pode chamar dos Edit métodos and Create para garantir que dois departamentos não tenham o mesmo 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);
        }
    }
}

Adicione código no try bloco do HttpPost Edit método para chamar esse novo método se não houver erros de validação. O try bloco agora se parece com o seguinte exemplo:

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

Execute a página Editar departamento e tente alterar o administrador de um departamento para um instrutor que já seja o administrador de um departamento diferente. Você recebe a mensagem de erro esperada:

Captura de tela mostrando a página Editar Departamento com uma mensagem de erro de administrador duplicada.

Agora execute a página Editar Departamento novamente e, desta vez, altere o valor do orçamento . Ao clicar em Salvar, você verá uma página de erro:

Captura de tela que mostra a página Editar Departamento com uma mensagem de erro do gerenciador de estado do objeto.

A mensagem de erro de exceção é "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." Isso aconteceu devido à seguinte sequência de eventos:

  • O Edit método chama o ValidateOneAdministratorAssignmentPerInstructor método, que recupera todos os departamentos que têm Kim Abercrombie como administrador. Isso faz com que o departamento de inglês seja lido. Como esse é o departamento que está sendo editado, nenhum erro é relatado. Como resultado dessa operação de leitura, no entanto, a entidade do departamento de inglês que foi lida do banco de dados agora está sendo rastreada pelo contexto do banco de dados.
  • O Edit método tenta definir o Modified sinalizador na entidade do departamento de inglês criada pelo associador de modelos MVC, mas isso falha porque o contexto já está rastreando uma entidade para o departamento de inglês.

Uma solução para esse problema é impedir que o contexto rastreie entidades de departamento na memória recuperadas pela consulta de validação. Não há desvantagem em fazer isso, porque você não atualizará essa entidade ou a lerá novamente de uma forma que se beneficiaria de ela ser armazenada em cache na memória.

Em DepartmentController.cs, no ValidateOneAdministratorAssignmentPerInstructor método, não especifique nenhum rastreamento, conforme mostrado a seguir:

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

Repita sua tentativa de editar o valor do orçamento de um departamento. Desta vez, a operação é bem-sucedida e o site retorna conforme o esperado para a página Índice de Departamentos, mostrando o valor do orçamento revisado.

Examinando consultas enviadas ao banco de dados

Às vezes, é útil poder ver as consultas SQL reais que são enviadas ao banco de dados. Para fazer isso, você pode examinar uma variável de consulta no depurador ou chamar o método da ToString consulta. Para experimentar isso, você examinará uma consulta simples e, em seguida, verá o que acontece com ela à medida que adiciona opções como carregamento, filtragem e classificação ansiosos.

Em Controllers/CourseController, substitua o Index método pelo seguinte código:

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

Agora defina um ponto de interrupção em GenericRepository.cs nas return query.ToList(); instruções e nas return orderBy(query).ToList(); instruções do Get método. Execute o projeto no modo de depuração e selecione a página Índice do curso. Quando o código atingir o ponto de interrupção, examine a query variável. Você verá a consulta enviada ao SQL Server. É uma declaração simples Select :

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

Captura de tela que mostra a guia Repositório Genérico do aplicativo Web de exemplo. A variável de consulta é selecionada.

As consultas podem ser muito longas para serem exibidas nas janelas de depuração no Visual Studio. Para ver toda a consulta, você pode copiar o valor da variável e colá-lo em um editor de texto:

Captura de tela que mostra o valor da variável com um menu suspenso exibido quando ela é selecionada. A opção Copiar valor é realçada.

Agora você adicionará uma lista suspensa à página Índice do curso para que os usuários possam filtrar por um departamento específico. Você classificará os cursos por título e especificará o carregamento ansioso para a Department propriedade de navegação. Em CourseController.cs, substitua o Index método pelo seguinte 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"));
}

O método recebe o valor selecionado da lista suspensa no SelectedDepartment parâmetro. Se nada for selecionado, esse parâmetro será nulo.

Uma SelectList coleção contendo todos os departamentos é passada para a exibição da lista suspensa. Os parâmetros passados para o SelectList construtor especificam o nome do campo de valor, o nome do campo de texto e o item selecionado.

Para o Get método do repositório, o código especifica uma expressão de Course filtro, uma ordem de classificação e um carregamento ansioso para a Department propriedade de navegação. A expressão de filtro sempre retorna true se nada for selecionado na lista suspensa (ou seja, SelectedDepartment for nulo).

Em Views\Course\Index.cshtml, imediatamente antes da marca de abertura table , adicione o seguinte código para criar a lista suspensa e um botão enviar:

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

Com os pontos de interrupção ainda definidos na GenericRepository classe, execute a página Índice do curso. Continue nas duas primeiras vezes em que o código atinge um ponto de interrupção, para que a página seja exibida no navegador. Selecione um departamento na lista suspensa e clique em Filtrar:

Captura de tela que mostra a página Índice do Curso com o Departamento de Economia selecionado.

Desta vez, o primeiro ponto de interrupção será para a consulta de departamentos para a lista suspensa. Ignore isso e exiba a query variável na próxima vez que o código atingir o ponto de interrupção para ver como a Course consulta agora se parece. Você verá algo como o seguinte:

{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)}

Você pode ver que a consulta agora é uma JOIN consulta que carrega Department dados junto com os Course dados e que inclui uma WHERE cláusula.

Trabalhando com classes proxy

Quando o Entity Framework cria instâncias de entidade (por exemplo, quando você executa uma consulta), ele geralmente as cria como instâncias de um tipo derivado gerado dinamicamente que atua como um proxy para a entidade. Esse proxy substitui algumas propriedades virtuais da entidade para inserir ganchos para executar ações automaticamente quando a propriedade é acessada. Por exemplo, esse mecanismo é usado para suportar o carregamento lento de relacionamentos.

Na maioria das vezes, você não precisa estar ciente desse uso de proxies, mas há exceções:

  • Em alguns cenários, talvez você queira impedir que o Entity Framework crie instâncias de proxy. Por exemplo, a serialização de instâncias não proxy pode ser mais eficiente do que a serialização de instâncias proxy.
  • Ao instanciar uma classe de entidade usando o new operador, você não obtém uma instância de proxy. Isso significa que você não obtém funcionalidades como carregamento lento e controle automático de alterações. Isso normalmente é bom; Geralmente, você não precisa de carregamento lento, porque está criando uma nova entidade que não está no banco de dados e geralmente não precisa do controle de alterações se estiver marcando explicitamente a entidade como Added. No entanto, se você precisar de carregamento lento e precisar de controle de alterações, poderá criar novas instâncias de entidade com proxies usando o Create DbSet método da classe.
  • Talvez você queira obter um tipo de entidade real de um tipo de proxy. Você pode usar o GetObjectType ObjectContext método da classe para obter o tipo de entidade real de uma instância do tipo proxy.

Para obter mais informações, consulte Trabalhando com proxies no blog da equipe do Entity Framework.

Desativando a detecção automática de alterações

O Entity Framework determina como uma entidade foi alterada (e, portanto, quais atualizações precisam ser enviadas ao banco de dados), comparando os valores atuais de uma entidade com os valores originais. Os valores originais são armazenados quando a entidade foi consultada ou anexada. Alguns dos métodos que causam a detecção automática de alterações são os seguintes:

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

Se você estiver rastreando um grande número de entidades e chamar um desses métodos muitas vezes em um loop, poderá obter melhorias significativas de desempenho desativando temporariamente a detecção automática de alterações usando a propriedade AutoDetectChangesEnabled . Para obter mais informações, consulte Detectando alterações automaticamente.

Desativando a validação ao salvar alterações

Quando você chama o SaveChanges método, por padrão, o Entity Framework valida os dados em todas as propriedades de todas as entidades alteradas antes de atualizar o banco de dados. Se você atualizou um grande número de entidades e já validou os dados, esse trabalho é desnecessário e você pode fazer com que o processo de salvar as alterações leve menos tempo desativando temporariamente a validação. Você pode fazer isso usando a propriedade ValidateOnSaveEnabled . Para obter mais informações, confira Validação.

Resumo

Isso conclui esta série de tutoriais sobre como usar o Entity Framework em um aplicativo MVC ASP.NET. Links para outros recursos do Entity Framework podem ser encontrados no Mapa de Conteúdo de Acesso a Dados do ASP.NET.

Para obter mais informações sobre como implantar seu aplicativo Web depois de criá-lo, consulte ASP.NET Mapa de Conteúdo de Implantação na Biblioteca MSDN.

Para obter informações sobre outros tópicos relacionados ao MVC, como autenticação e autorização, consulte os Recursos recomendados do MVC.

Agradecimentos

  • Tom Dykstra escreveu a versão original deste tutorial e é redator sênior de programação na Equipe de Conteúdo de Ferramentas e Plataforma Web da Microsoft.
  • Rick Anderson (twitter @RickAndMSFT) foi coautor deste tutorial e fez a maior parte do trabalho atualizando-o para EF 5 e MVC 4. Rick é um escritor de programação sênior da Microsoft com foco no Azure e no MVC.
  • Rowan Miller e outros membros da equipe do Entity Framework ajudaram nas revisões de código e ajudaram a depurar muitos problemas com migrações que surgiram enquanto atualizávamos o tutorial do EF 5.

VB

Quando o tutorial foi produzido originalmente, fornecemos as versões C# e VB do projeto de download concluído. Com esta atualização, estamos fornecendo um projeto para download em C# para cada capítulo para facilitar o início em qualquer lugar da série, mas devido a limitações de tempo e outras prioridades, não fizemos isso para o VB. Se você criar um projeto VB usando esses tutoriais e estiver disposto a compartilhá-lo com outras pessoas, informe-nos.

Erros e soluções alternativas

Não é possível criar/cópia de sombra

Mensagem de erro:

Não é possível criar/copiar 'DotNetOpenAuth.OpenId' quando esse arquivo já existe.

Solução:

Aguarde alguns segundos e atualize a página.

Update-Database não reconhecido

Mensagem de erro:

O termo 'Update-Database' não é reconhecido como o nome de um cmdlet, função, arquivo de script ou programa operável. Verifique a ortografia do nome ou se um caminho foi incluído, verifique se ele está correto e tente novamente.(Do Update-Database comando no PMC.)

Solução:

Saia do Visual Studio. Reabra o projeto e tente novamente.

Falha na validação

Mensagem de erro:

Falha na validação para uma ou mais entidades. Consulte a propriedade 'EntityValidationErrors' para obter mais detalhes. (Do Update-Database comando no PMC.)

Solução:

Uma causa desse problema são erros de validação quando o Seed método é executado. Consulte Propagação e depuração de bancos de dados do EF (Entity Framework) para obter dicas sobre como depurar o Seed método.

Erro HTTP 500.19

Mensagem de erro:

Erro HTTP 500.19 - Erro interno do servidor
A página solicitada não pode ser acessada porque os dados de configuração relacionados à página são inválidos.

Solução:

Uma maneira de obter esse erro é ter várias cópias da solução, cada uma delas usando o mesmo número de porta. Normalmente, você pode resolver esse problema saindo de todas as instâncias do Visual Studio e reiniciando o projeto em que está trabalhando. Se isso não funcionar, tente alterar o número da porta. Clique com o botão direito do mouse no arquivo de projeto e clique em propriedades. Selecione a guia Web e altere o número da porta na caixa de texto URL do Projeto .

Erro ao localizar a instância do SQL Server

Mensagem de erro:

Ocorreu um erro relacionado à rede ou específico da instância ao estabelecer uma conexão com o SQL Server. O servidor não foi encontrado ou não estava acessível. Verifique se o nome de instância está correto e se o SQL Server está configurado para permitir conexões remotas. (provedor: Adaptadores de Rede do SQL, erro: 26 – Erro ao Localizar Servidor/Instância Especificada)

Solução:

Verifique a cadeia de conexão. Se você tiver excluído manualmente o banco de dados, altere o nome do banco de dados na cadeia de caracteres de construção.