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:
E para usar uma consulta sem rastreamento, você adicionará uma nova lógica de validação à página Editar departamento:
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 peloDbSet
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 oAsNoTracking
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).
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.
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:
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:
Crie uma visualização na pasta Visualizações\Curso para a página Atualizar créditos do curso:
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:
Clique em Atualizar. O número de linhas afetadas é exibido:
Clique em Voltar para a Lista para ver a lista de cursos 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:
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:
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 oValidateOneAdministratorAssignmentPerInstructor
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 oModified
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]}
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:
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:
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 comoAdded
. 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 oCreate
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.