Maximizando o desempenho com o Entity Framework 4.0 em um aplicativo Web ASP.NET 4
por Tom Dykstra
Esta série de tutoriais se baseia no aplicativo Web da Contoso University criado pelo Introdução com a série de tutoriais do Entity Framework 4.0. Se você não concluiu os tutoriais anteriores, como ponto de partida para este tutorial, poderá baixar o aplicativo que teria criado. Você também pode baixar o aplicativo criado pela série de tutoriais completa. Se você tiver dúvidas sobre os tutoriais, poderá postá-los no fórum ASP.NET Entity Framework.
No tutorial anterior, você viu como lidar com conflitos de simultaneidade. Este tutorial mostra opções para melhorar o desempenho de um aplicativo Web ASP.NET que usa o Entity Framework. Você aprenderá vários métodos para maximizar o desempenho ou diagnosticar problemas de desempenho.
As informações apresentadas nas seções a seguir provavelmente serão úteis em uma ampla variedade de cenários:
- Carregue dados relacionados com eficiência.
- Gerenciar o estado de exibição.
As informações apresentadas nas seções a seguir podem ser úteis se você tiver consultas individuais que apresentam problemas de desempenho:
- Use a opção
NoTracking
de mesclagem. - Pré-compilar consultas LINQ.
- Examine os comandos de consulta enviados para o banco de dados.
As informações apresentadas na seção a seguir são potencialmente úteis para aplicativos que têm modelos de dados extremamente grandes:
- Pré-gerar exibições.
Observação
O desempenho do aplicativo Web é afetado por muitos fatores, incluindo coisas como o tamanho dos dados de solicitação e resposta, a velocidade das consultas de banco de dados, quantas solicitações o servidor pode enfileirar e a rapidez com que ele pode a service-los e até mesmo a eficiência de qualquer biblioteca cliente-script que você possa estar usando. Se o desempenho for crítico em seu aplicativo ou se o teste ou a experiência mostrar que o desempenho do aplicativo não é satisfatório, você deverá seguir o protocolo normal para ajuste de desempenho. Medida para determinar onde os gargalos de desempenho estão ocorrendo e, em seguida, abordar as áreas que terão maior impacto no desempenho geral do aplicativo.
Este tópico se concentra principalmente em maneiras pelas quais você pode potencialmente melhorar o desempenho especificamente do Entity Framework em ASP.NET. As sugestões aqui serão úteis se você determinar que o acesso a dados é um dos gargalos de desempenho em seu aplicativo. Exceto como observado, os métodos explicados aqui não devem ser considerados "práticas recomendadas" em geral — muitas delas são apropriadas apenas em situações excepcionais ou para lidar com tipos muito específicos de gargalos de desempenho.
Para iniciar o tutorial, inicie o Visual Studio e abra o aplicativo Web da Contoso University com o qual você estava trabalhando no tutorial anterior.
Carregando dados relacionados com eficiência
Há várias maneiras pelas quais o Entity Framework pode carregar dados relacionados nas propriedades de navegação de uma entidade:
Carregamento lento. Quando a entidade é lida pela primeira vez, os dados relacionados não são recuperados. No entanto, na primeira vez que você tenta acessar uma propriedade de navegação, os dados necessários para essa propriedade de navegação são recuperados automaticamente. Isso resulta em várias consultas enviadas para o banco de dados — uma para a própria entidade e outra para cada vez que os dados relacionados para a entidade devem ser recuperados.
Carregamento adiantado. Quando a entidade é lida, os dados relacionados são recuperados com ela. Normalmente, isso resulta em uma única consulta de junção que recupera todos os dados necessários. Especifique o carregamento ansioso usando o Include
método , como já viu nestes tutoriais.
Carregamento explícito. Isso é semelhante ao carregamento lento, exceto que você recupera explicitamente os dados relacionados no código; isso não acontece automaticamente quando você acessa uma propriedade de navegação. Você carrega dados relacionados manualmente usando o
Load
método da propriedade de navegação para coleções ou usa oLoad
método da propriedade de referência para propriedades que contêm um único objeto. (Por exemplo, você chama oPersonReference.Load
método para carregar aPerson
propriedade de navegação de umaDepartment
entidade.)
Como eles não recuperam imediatamente os valores de propriedade, o carregamento lento e o carregamento explícito também são conhecidos como carregamento adiado.
Carregamento lento é o comportamento padrão para um contexto de objeto que foi gerado pelo designer. Se você abrir o SchoolModel.Designer. arquivo cs que define a classe de contexto de objeto, você encontrará três métodos de construtor e cada um deles inclui a seguinte instrução:
this.ContextOptions.LazyLoadingEnabled = true;
Em geral, se você souber que precisa de dados relacionados para cada entidade recuperada, o carregamento ansioso oferece o melhor desempenho, pois uma única consulta enviada ao banco de dados normalmente é mais eficiente do que consultas separadas para cada entidade recuperada. Por outro lado, se você precisar acessar as propriedades de navegação de uma entidade apenas com pouca frequência ou apenas para um pequeno conjunto de entidades, o carregamento lento ou explícito pode ser mais eficiente, pois o carregamento ansioso recuperaria mais dados do que você precisa.
Em um aplicativo Web, o carregamento lento pode ter um valor relativamente pequeno de qualquer maneira, pois as ações do usuário que afetam a necessidade de dados relacionados ocorrem no navegador, que não tem nenhuma conexão com o contexto do objeto que renderizou a página. Por outro lado, ao associar dados a um controle, você normalmente sabe quais dados precisa e, portanto, geralmente é melhor escolher carregamento ansioso ou carregamento adiado com base no que é apropriado em cada cenário.
Além disso, um controle de entrada de dados pode usar um objeto de entidade após o contexto do objeto ser descartado. Nesse caso, uma tentativa de carregar uma propriedade de navegação lenta falharia. A mensagem de erro recebida é clara: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
"
O EntityDataSource
controle desabilita o carregamento lento por padrão. Para o ObjectDataSource
controle que você está usando para o tutorial atual (ou se você acessar o contexto do objeto do código da página), há várias maneiras de tornar o carregamento lento desabilitado por padrão. Você pode desabilitá-lo ao instanciar um contexto de objeto. Por exemplo, você pode adicionar a seguinte linha ao método de construtor da SchoolRepository
classe :
context.ContextOptions.LazyLoadingEnabled = false;
Para o aplicativo da Contoso University, você fará com que o contexto do objeto desabilite automaticamente o carregamento lento para que essa propriedade não precise ser definida sempre que um contexto for instanciado.
Abra o modelo de dados SchoolModel.edmx , clique na superfície de design e, no painel de propriedades, defina a propriedade Lazy Loading Enabled comoFalse
. Salve e feche o modelo de dados.
Gerenciando o estado de exibição
Para fornecer a funcionalidade de atualização, uma página da Web ASP.NET deve armazenar os valores de propriedade originais de uma entidade quando uma página é renderizada. Durante o processamento de postback, o controle pode recriar o estado original da entidade e chamar o método da Attach
entidade antes de aplicar alterações e chamar o SaveChanges
método . Por padrão, ASP.NET Web Forms controles de dados usam o estado de exibição para armazenar os valores originais. No entanto, o estado de exibição pode afetar o desempenho, pois ele é armazenado em campos ocultos que podem aumentar substancialmente o tamanho da página enviada de e para o navegador.
As técnicas para gerenciar o estado de exibição ou alternativas, como o estado da sessão, não são exclusivas do Entity Framework, portanto, este tutorial não entra neste tópico em detalhes. Para obter mais informações, consulte os links no final do tutorial.
No entanto, a versão 4 do ASP.NET fornece uma nova maneira de trabalhar com o estado de exibição que cada desenvolvedor ASP.NET de aplicativos Web Forms deve estar ciente: a ViewStateMode
propriedade . Essa nova propriedade pode ser definida no nível de página ou controle e permite desabilitar o estado de exibição por padrão para uma página e habilitá-la somente para controles que precisam dela.
Para aplicativos em que o desempenho é crítico, uma boa prática é sempre desabilitar o estado de exibição no nível da página e habilitá-lo apenas para controles que o exigem. O tamanho do estado de exibição nas páginas da Contoso University não seria substancialmente reduzido por esse método, mas para ver como ele funciona, você o fará para a página Instructors.aspx . Essa página contém muitos controles, incluindo um Label
controle que tem o estado de exibição desabilitado. Nenhum dos controles nesta página realmente precisa ter o estado de exibição habilitado. (A DataKeyNames
propriedade do controle especifica o GridView
estado que deve ser mantido entre postbacks, mas esses valores são mantidos no estado de controle, que não é afetado pela ViewStateMode
propriedade .)
A Page
diretiva e Label
a marcação de controle atualmente se assemelham ao seguinte exemplo:
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
CodeBehind="Instructors.aspx.cs" Inherits="ContosoUniversity.Instructors" %>
...
<asp:Label ID="ErrorMessageLabel" runat="server" Text="" Visible="false" ViewStateMode="Disabled"></asp:Label>
...
Faça as seguintes alterações:
- Adicione
ViewStateMode="Disabled"
àPage
diretiva . - Remova
ViewStateMode="Disabled"
doLabel
controle.
A marcação agora se assemelha ao seguinte exemplo:
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
CodeBehind="Instructors.aspx.cs" Inherits="ContosoUniversity.Instructors"
ViewStateMode="Disabled" %>
...
<asp:Label ID="ErrorMessageLabel" runat="server" Text="" Visible="false"></asp:Label>
...
O estado de exibição agora está desabilitado para todos os controles. Se você adicionar mais tarde um controle que precisa usar o estado de exibição, tudo o que você precisa fazer é incluir o ViewStateMode="Enabled"
atributo para esse controle.
Usando a opção de mesclagem NoTracking
Quando um contexto de objeto recupera linhas de banco de dados e cria objetos de entidade que as representam, por padrão, ele também rastreia esses objetos de entidade usando seu gerenciador de estado de objeto. Esses dados de acompanhamento atuam como um cache e são usados quando você atualiza uma entidade. Como um aplicativo Web normalmente tem instâncias de contexto de objeto de curta duração, as consultas geralmente retornam dados que não precisam ser rastreados, pois o contexto de objeto que as lê será descartado antes que qualquer uma das entidades que ele lê seja usada novamente ou atualizada.
No Entity Framework, você pode especificar se o contexto do objeto rastreia objetos de entidade definindo uma opção de mesclagem. Você pode definir a opção de mesclagem para consultas individuais ou para conjuntos de entidades. Se você defini-lo para um conjunto de entidades, isso significa que você está definindo a opção de mesclagem padrão para todas as consultas criadas para esse conjunto de entidades.
Para o aplicativo da Contoso University, o acompanhamento não é necessário para nenhum dos conjuntos de entidades que você acessa do repositório, para que você possa definir a opção de mesclagem para NoTracking
esses conjuntos de entidades ao instanciar o contexto de objeto na classe de repositório. (Observe que, neste tutorial, definir a opção de mesclagem não terá um efeito perceptível no desempenho do aplicativo. É NoTracking
provável que a opção faça uma melhoria de desempenho observável apenas em determinados cenários de alto volume de dados.)
Na pasta DAL, abra o arquivo SchoolRepository.cs e adicione um método de construtor que define a opção de mesclagem para os conjuntos de entidades que o repositório acessa:
public SchoolRepository()
{
context.Departments.MergeOption = MergeOption.NoTracking;
context.InstructorNames.MergeOption = MergeOption.NoTracking;
context.OfficeAssignments.MergeOption = MergeOption.NoTracking;
}
Pré-compilando consultas LINQ
Na primeira vez que o Entity Framework executa uma consulta Entity SQL na vida útil de uma determinada ObjectContext
instância, leva algum tempo para compilar a consulta. O resultado da compilação é armazenado em cache, o que significa que as execuções subsequentes da consulta são muito mais rápidas. As consultas LINQ seguem um padrão semelhante, exceto que parte do trabalho necessário para compilar a consulta é feito sempre que a consulta é executada. Em outras palavras, para consultas LINQ, por padrão nem todos os resultados da compilação são armazenados em cache.
Se você tiver uma consulta LINQ que espera executar repetidamente na vida útil de um contexto de objeto, poderá escrever um código que faça com que todos os resultados da compilação sejam armazenados em cache na primeira vez que a consulta LINQ for executada.
Como ilustração, você fará isso para dois Get
métodos na SchoolRepository
classe , um dos quais não usa parâmetros (o GetInstructorNames
método ) e um que requer um parâmetro (o GetDepartmentsByAdministrator
método ). Esses métodos como estão agora, na verdade, não precisam ser compilados porque não são consultas LINQ:
public IEnumerable<InstructorName> GetInstructorNames()
{
return context.InstructorNames.OrderBy("it.FullName").ToList();
}
public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
return new ObjectQuery<Department>("SELECT VALUE d FROM Departments as d", context, MergeOption.NoTracking).Include("Person").Where(d => d.Administrator == administrator).ToList();
}
No entanto, para que você possa experimentar consultas compiladas, prossiga como se elas tivessem sido escritas como as seguintes consultas LINQ:
public IEnumerable<InstructorName> GetInstructorNames()
{
return (from i in context.InstructorNames orderby i.FullName select i).ToList();
}
public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
context.Departments.MergeOption = MergeOption.NoTracking;
return (from d in context.Departments where d.Administrator == administrator select d).ToList();
}
Você pode alterar o código nesses métodos para o que é mostrado acima e executar o aplicativo para verificar se ele funciona antes de continuar. No entanto, as instruções a seguir entram diretamente na criação de versões pré-compiladas delas.
Crie um arquivo de classe na pasta DAL , nomeie-o SchoolEntities.cs e substitua o código existente pelo seguinte código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Objects;
namespace ContosoUniversity.DAL
{
public partial class SchoolEntities
{
private static readonly Func<SchoolEntities, IQueryable<InstructorName>> compiledInstructorNamesQuery =
CompiledQuery.Compile((SchoolEntities context) => from i in context.InstructorNames orderby i.FullName select i);
public IEnumerable<InstructorName> CompiledInstructorNamesQuery()
{
return compiledInstructorNamesQuery(this).ToList();
}
private static readonly Func<SchoolEntities, Int32, IQueryable<Department>> compiledDepartmentsByAdministratorQuery =
CompiledQuery.Compile((SchoolEntities context, Int32 administrator) => from d in context.Departments.Include("Person") where d.Administrator == administrator select d);
public IEnumerable<Department> CompiledDepartmentsByAdministratorQuery(Int32 administrator)
{
return compiledDepartmentsByAdministratorQuery(this, administrator).ToList();
}
}
}
Esse código cria uma classe parcial que estende a classe de contexto de objeto gerada automaticamente. A classe parcial inclui duas consultas LINQ compiladas usando o Compile
método da CompiledQuery
classe . Ele também cria métodos que você pode usar para chamar as consultas. Salve e feche este arquivo.
Em seguida, em SchoolRepository.cs, altere os métodos e GetDepartmentsByAdministrator
existentes GetInstructorNames
na classe do repositório para que eles chamem as consultas compiladas:
public IEnumerable<InstructorName> GetInstructorNames()
{
return context.CompiledInstructorNamesQuery();
}
public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
return context.CompiledDepartmentsByAdministratorQuery(administrator);
}
Execute a página Departments.aspx para verificar se ela funciona como antes. O GetInstructorNames
método é chamado para preencher a lista suspensa de administradores e o GetDepartmentsByAdministrator
método é chamado quando você clica em Atualizar para verificar se nenhum instrutor é um administrador de mais de um departamento.
Você compilou previamente consultas no aplicativo da Contoso University apenas para ver como fazer isso, não porque isso melhoraria o desempenho mensuravelmente. A pré-compilação de consultas LINQ adiciona um nível de complexidade ao seu código, portanto, certifique-se de fazê-lo apenas para consultas que realmente representam gargalos de desempenho em seu aplicativo.
Examinando consultas enviadas para o banco de dados
Quando você está investigando problemas de desempenho, às vezes é útil saber os comandos SQL exatos que o Entity Framework está enviando para o banco de dados. Se você estiver trabalhando com um IQueryable
objeto , uma maneira de fazer isso é usar o ToTraceString
método .
Em SchoolRepository.cs, altere o código no GetDepartmentsByName
método para corresponder ao seguinte exemplo:
public IEnumerable<Department> GetDepartmentsByName(string sortExpression, string nameSearchString)
{
...
var departments = new ObjectQuery<Department>("SELECT VALUE d FROM Departments AS d", context).OrderBy("it." + sortExpression).Include("Person").Include("Courses").Where(d => d.Name.Contains(nameSearchString));
string commandText = ((ObjectQuery)departments).ToTraceString();
return departments.ToList();
}
A departments
variável deve ser convertida em um ObjectQuery
tipo somente porque o Where
método no final da linha anterior cria um IQueryable
objeto ; sem o Where
método , a conversão não seria necessária.
Defina um ponto de interrupção na return
linha e execute a página Departments.aspx no depurador. Ao atingir o ponto de interrupção, examine a commandText
variável na janela Locais e use o visualizador de texto (a lupa na coluna Valor ) para exibir seu valor na janela Visualizador de Texto . Você pode ver todo o comando SQL resultante deste código:
Como alternativa, o recurso IntelliTrace no Visual Studio Ultimate fornece uma maneira de exibir comandos SQL gerados pelo Entity Framework que não exigem que você altere seu código ou até mesmo defina um ponto de interrupção.
Observação
Você só poderá executar os procedimentos a seguir se tiver Visual Studio Ultimate.
Restaure o código original no GetDepartmentsByName
método e execute a página Departments.aspx no depurador.
No Visual Studio, selecione o menu Depurar , IntelliTrace e, em seguida, Eventos do IntelliTrace.
Na janela do IntelliTrace , clique em Quebrar Tudo.
A janela do IntelliTrace exibe uma lista de eventos recentes:
Clique na linha ADO.NET . Ele se expande para mostrar o texto do comando:
Você pode copiar toda a cadeia de caracteres de texto do comando para a área de transferência da janela Locais.
Suponha que você estava trabalhando com um banco de dados com mais tabelas, relações e colunas do que o banco de dados simples School
. Você pode descobrir que uma consulta que coleta todas as informações necessárias em uma única Select
instrução que contém várias Join
cláusulas se torna muito complexa para funcionar com eficiência. Nesse caso, você pode alternar do carregamento adiantado para o carregamento explícito para simplificar a consulta.
Por exemplo, tente alterar o código no GetDepartmentsByName
método em SchoolRepository.cs. Atualmente, nesse método, você tem uma consulta de objeto que tem Include
métodos para as Person
propriedades de navegação e Courses
. Substitua a instrução return
pelo código que executa o carregamento explícito, conforme mostrado no exemplo a seguir:
public IEnumerable<Department> GetDepartmentsByName(string sortExpression, string nameSearchString)
{
...
var departments = new ObjectQuery<Department>("SELECT VALUE d FROM Departments AS d", context).OrderBy("it." + sortExpression).Where(d => d.Name.Contains(nameSearchString)).ToList();
foreach (Department d in departments)
{
d.Courses.Load();
d.PersonReference.Load();
}
return departments;
}
Execute a página Departments.aspx no depurador e marcar a janela do IntelliTrace novamente como você fez antes. Agora, onde havia uma única consulta antes, você vê uma longa sequência delas.
Clique na primeira linha ADO.NET para ver o que aconteceu com a consulta complexa exibida anteriormente.
A consulta de Departamentos tornou-se uma consulta simples Select
sem Join
cláusula, mas é seguida por consultas separadas que recuperam cursos relacionados e um administrador, usando um conjunto de duas consultas para cada departamento retornado pela consulta original.
Observação
Se você deixar o carregamento lento habilitado, o padrão que você vê aqui, com a mesma consulta repetida várias vezes, poderá resultar do carregamento lento. Um padrão que você normalmente deseja evitar é o carregamento lento de dados relacionados para cada linha da tabela primária. A menos que você tenha verificado que uma única consulta de junção é muito complexa para ser eficiente, você normalmente poderá melhorar o desempenho nesses casos alterando a consulta primária para usar o carregamento adiantado.
Pré-geração de exibições
Quando um ObjectContext
objeto é criado pela primeira vez em um novo domínio de aplicativo, o Entity Framework gera um conjunto de classes que ele usa para acessar o banco de dados. Essas classes são chamadas de exibições e, se você tiver um modelo de dados muito grande, gerar essas exibições poderá atrasar a resposta do site à primeira solicitação de uma página depois que um novo domínio de aplicativo for inicializado. Você pode reduzir esse atraso de primeira solicitação criando as exibições em tempo de compilação em vez de em tempo de execução.
Observação
Se o aplicativo não tiver um modelo de dados extremamente grande ou se ele tiver um modelo de dados grande, mas você não estiver preocupado com um problema de desempenho que afete apenas a primeira solicitação de página depois que o IIS for reciclado, você poderá ignorar esta seção. A criação da exibição não acontece toda vez que você cria uma instância de um ObjectContext
objeto, pois as exibições são armazenadas em cache no domínio do aplicativo. Portanto, a menos que você esteja reciclando frequentemente seu aplicativo no IIS, pouquíssimas solicitações de página se beneficiariam de exibições pré-geradas.
Você pode pré-gerar exibições usando a ferramenta de linha de comando EdmGen.exe ou usando um modelo T4 ( Text Template Transformation Toolkit ). Neste tutorial, você usará um modelo T4.
Na pasta DAL , adicione um arquivo usando o modelo Modelo de Texto (ele está sob o nó Geral na lista Modelos Instalados ) e nomeie-o como SchoolModel.Views.tt. Substitua o código existente no arquivo pelo seguinte código:
<#
/***************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
***************************************************************************/
#>
<#
//
// TITLE: T4 template to generate views for an EDMX file in a C# project
//
// DESCRIPTION:
// This is a T4 template to generate views in C# for an EDMX file in C# projects.
// The generated views are automatically compiled into the project's output assembly.
//
// This template follows a simple file naming convention to determine the EDMX file to process:
// - It assumes that [edmx-file-name].Views.tt will process and generate views for [edmx-file-name].EDMX
// - The views are generated in the code behind file [edmx-file-name].Views.cs
//
// USAGE:
// Do the following to generate views for an EDMX file (e.g. Model1.edmx) in a C# project
// 1. In Solution Explorer, right-click the project node and choose "Add...Existing...Item" from the context menu
// 2. Browse to and choose this .tt file to include it in the project
// 3. Ensure this .tt file is in the same directory as the EDMX file to process
// 4. In Solution Explorer, rename this .tt file to the form [edmx-file-name].Views.tt (e.g. Model1.Views.tt)
// 5. In Solution Explorer, right-click Model1.Views.tt and choose "Run Custom Tool" to generate the views
// 6. The views are generated in the code behind file Model1.Views.cs
//
// TIPS:
// If you have multiple EDMX files in your project then make as many copies of this .tt file and rename appropriately
// to pair each with each EDMX file.
//
// To generate views for all EDMX files in the solution, click the "Transform All Templates" button in the Solution Explorer toolbar
// (its the rightmost button in the toolbar)
//
#>
<#
//
// T4 template code follows
//
#>
<#@ template language="C#" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs" #>
<#
// Find EDMX file to process: Model1.Views.tt generates views for Model1.EDMX
string edmxFileName = Path.GetFileNameWithoutExtension(this.Host.TemplateFile).ToLowerInvariant().Replace(".views", "") + ".edmx";
string edmxFilePath = Path.Combine(Path.GetDirectoryName(this.Host.TemplateFile), edmxFileName);
if (File.Exists(edmxFilePath))
{
// Call helper class to generate pre-compiled views and write to output
this.WriteLine(GenerateViews(edmxFilePath));
}
else
{
this.Error(String.Format("No views were generated. Cannot find file {0}. Ensure the project has an EDMX file and the file name of the .tt file is of the form [edmx-file-name].Views.tt", edmxFilePath));
}
// All done!
#>
<#+
private String GenerateViews(string edmxFilePath)
{
MetadataLoader loader = new MetadataLoader(this);
MetadataWorkspace workspace;
if(!loader.TryLoadAllMetadata(edmxFilePath, out workspace))
{
this.Error("Error in the metadata");
return String.Empty;
}
String generatedViews = String.Empty;
try
{
using (StreamWriter writer = new StreamWriter(new MemoryStream()))
{
StorageMappingItemCollection mappingItems = (StorageMappingItemCollection)workspace.GetItemCollection(DataSpace.CSSpace);
// Initialize the view generator to generate views in C#
EntityViewGenerator viewGenerator = new EntityViewGenerator();
viewGenerator.LanguageOption = LanguageOption.GenerateCSharpCode;
IList<EdmSchemaError> errors = viewGenerator.GenerateViews(mappingItems, writer);
foreach (EdmSchemaError e in errors)
{
// log error
this.Error(e.Message);
}
MemoryStream memStream = writer.BaseStream as MemoryStream;
generatedViews = Encoding.UTF8.GetString(memStream.ToArray());
}
}
catch (Exception ex)
{
// log error
this.Error(ex.ToString());
}
return generatedViews;
}
#>
Esse código gera exibições para um arquivo .edmx localizado na mesma pasta que o modelo e que tem o mesmo nome que o arquivo de modelo. Por exemplo, se o arquivo de modelo for nomeado SchoolModel.Views.tt, ele procurará um arquivo de modelo de dados chamado SchoolModel.edmx.
Salve o arquivo e clique com o botão direito do mouse no arquivo no Gerenciador de Soluções e selecione Executar Ferramenta Personalizada.
O Visual Studio gera um arquivo de código que cria as exibições, que é denominada SchoolModel.Views.cs com base no modelo. (Talvez você tenha notado que o arquivo de código é gerado antes mesmo de selecionar Executar Ferramenta Personalizada, assim que salvar o arquivo de modelo.)
Agora você pode executar o aplicativo e verificar se ele funciona como antes.
Para obter mais informações sobre exibições pré-geradas, consulte os seguintes recursos:
- Como pré-gerar exibições para melhorar o desempenho da consulta no site do MSDN. Explica como usar a
EdmGen.exe
ferramenta de linha de comando para pré-gerar exibições. - Isolando o desempenho com exibições pré-compiladas/pré-geradas no Entity Framework 4 no blog da Equipe de Consultoria do Cliente do Windows Server AppFabric.
Isso conclui a introdução à melhoria do desempenho em um aplicativo Web ASP.NET que usa o Entity Framework. Para saber mais, consulte os recursos a seguir:
- Considerações de desempenho (Entity Framework) no site do MSDN.
- Postagens relacionadas ao desempenho no blog da Equipe do Entity Framework.
- Opções de mesclagem e consultas compiladas do EF. Postagem no blog que explica comportamentos inesperados de consultas compiladas e opções de mesclagem, como
NoTracking
. Se você planeja usar consultas compiladas ou manipular configurações de opção de mesclagem em seu aplicativo, leia isso primeiro. - Postagens relacionadas ao Entity Framework no blog equipe de consultoria do cliente de dados e modelagem. Inclui postagens em consultas compiladas e usando o Criador de Perfil do Visual Studio 2010 para descobrir problemas de desempenho.
- ASP.NET Recomendações de Gerenciamento de Estado.
- Usando o Entity Framework e o ObjectDataSource: paginação personalizada. Postagem de blog que se baseia no aplicativo ContosoUniversity criado nestes tutoriais para explicar como implementar a paginação na página Departments.aspx .
O próximo tutorial examina alguns dos aprimoramentos importantes para o Entity Framework que são novos na versão 4.