Maximalizace výkonu pomocí Entity Framework 4.0 ve webové aplikaci ASP.NET 4
Tato série kurzů vychází z webové aplikace Contoso University vytvořené Začínáme s využitím série kurzů Entity Framework 4.0. Pokud jste nedokončí předchozí kurzy, jako výchozí bod pro tento kurz si můžete stáhnout aplikaci , kterou jste vytvořili. Můžete si také stáhnout aplikaci vytvořenou v rámci celé série kurzů. Pokud máte dotazy ke kurzům, můžete je publikovat na fóru ASP.NET Entity Framework.
V předchozím kurzu jste viděli, jak řešit konflikty souběžnosti. Tento kurz ukazuje možnosti pro zlepšení výkonu ASP.NET webové aplikace, která používá Entity Framework. Naučíte se několik metod pro maximalizaci výkonu nebo pro diagnostiku problémů s výkonem.
Informace uvedené v následujících částech budou pravděpodobně užitečné v nejrůznějších scénářích:
- Efektivní načítání souvisejících dat
- Spravovat stav zobrazení.
Informace uvedené v následujících částech můžou být užitečné, pokud máte jednotlivé dotazy, které představují problémy s výkonem:
NoTracking
Použijte možnost sloučení.- Předkompilujte dotazy LINQ.
- Prozkoumejte příkazy dotazu odeslané do databáze.
Informace uvedené v následující části jsou potenciálně užitečné pro aplikace, které mají extrémně velké datové modely:
- Předem vygenerovaná zobrazení
Poznámka
Na výkon webové aplikace má vliv mnoho faktorů, například velikost dat požadavků a odpovědí, rychlost databázových dotazů, počet požadavků, které může server zařadit do fronty a jak rychle je dokáže obsluhovat, a dokonce i efektivita knihoven klientských skriptů, které možná používáte. Pokud je výkon vaší aplikace kritický nebo pokud testování nebo zkušenosti ukazují, že výkon aplikace není uspokojivý, měli byste při ladění výkonu postupovat podle normálního protokolu. Měřením určíte, kde dochází k kritickým bodům výkonu, a pak vyřešte oblasti, které budou mít největší vliv na celkový výkon aplikace.
Toto téma se zaměřuje hlavně na způsoby, jak potenciálně zlepšit výkon entity frameworku v ASP.NET. Uvedené návrhy jsou užitečné, pokud zjistíte, že jedním z kritických bodů výkonu aplikace je přístup k datům. Kromě toho, jak je uvedeno, by zde popsané metody neměly být obecně považovány za "osvědčené postupy" – mnohé z nich jsou vhodné pouze ve výjimečných situacích nebo k řešení velmi specifických druhů kritických bodů výkonu.
Kurz zahájíte tak, že spustíte Visual Studio a otevřete webovou aplikaci Contoso University, se kterou jste pracovali v předchozím kurzu.
Efektivní načítání souvisejících dat
Existuje několik způsobů, jak může Entity Framework načíst související data do navigačních vlastností entity:
Opožděné načítání. Při prvním čtení entity se související data nenačtou. Při prvním pokusu o přístup k navigační vlastnosti se však automaticky načtou data potřebná pro tuto navigační vlastnost. Výsledkem je několik dotazů odeslaných do databáze – jeden pro samotnou entitu a druhý pokaždé, když se musí načíst související data entity.
Dychtivé načítání. Když se entita načte, načtou se spolu s ní i související data. Výsledkem je obvykle jeden dotaz spojení, který načte všechna potřebná data. K určení dychtivého načítání použijete metodu Include
, jak jste už viděli v těchto kurzech.
Explicitní načítání To se podobá opožděné načítání, s výjimkou toho, že explicitně načtete související data v kódu; nedojde k tomu automaticky při přístupu k vlastnosti navigace. Související data můžete načíst ručně pomocí
Load
metody navigační vlastnosti pro kolekce nebo pomocíLoad
metody referenční vlastnosti pro vlastnosti, které obsahují jeden objekt. (Voláním metody můžete napříkladPersonReference.Load
načístPerson
navigační vlastnostDepartment
entity.)
Vzhledem k tomu, že nenačítají hodnoty vlastností okamžitě, líné načítání i explicitní načítání se také označuje jako odložené načítání.
Opožděné načítání je výchozí chování pro kontext objektu, který byl generován návrhářem. Pokud otevřete soubor SchoolModel.Designer. cs souboru, který definuje třídu kontextu objektu, najdete tři metody konstruktoru a každá z nich obsahuje následující příkaz:
this.ContextOptions.LazyLoadingEnabled = true;
Obecně platí, že pokud víte, že potřebujete související data pro každou načtenou entitu, nabízí dychtivé načítání nejlepší výkon, protože jeden dotaz odeslaný do databáze je obvykle efektivnější než samostatné dotazy pro každou načtenou entitu. Na druhou stranu, pokud potřebujete přistupovat k navigačním vlastnostem entity jen zřídka nebo jen pro malou sadu entit, může být opožděné nebo explicitní načítání efektivnější, protože dychtivé načítání by načetlo více dat, než potřebujete.
Ve webové aplikaci může opožděné načítání mít i tak relativně malou hodnotu, protože akce uživatele, které ovlivňují potřebu souvisejících dat, probíhají v prohlížeči, který nemá připojení ke kontextu objektu, který vykresloval stránku. Na druhou stranu, když databindujete ovládací prvek, obvykle víte, jaká data potřebujete, a proto je obecně nejlepší zvolit nedočkavé nebo odložené načítání na základě toho, co je v každém scénáři vhodné.
Kromě toho může ovládací prvek pro přenos dat používat objekt entity po odstranění kontextu objektu. V takovém případě by pokus o opožděné načtení navigační vlastnosti selhal. Chybová zpráva, která se zobrazí, je jasná: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
"
Ovládací EntityDataSource
prvek ve výchozím nastavení zakáže opožděné načítání. ObjectDataSource
U ovládacího prvku, který používáte v aktuálním kurzu (nebo pokud přistupujete ke kontextu objektu z kódu stránky), můžete ve výchozím nastavení opožděné načítání zakázat několika způsoby. Můžete ho zakázat při vytváření instance kontextu objektu. Do metody SchoolRepository
konstruktoru třídy můžete například přidat následující řádek:
context.ContextOptions.LazyLoadingEnabled = false;
V aplikaci Contoso University nastavíte kontext objektu automaticky na zákaz opožděného načítání, aby se tato vlastnost nemusela nastavovat při každé instanci kontextu.
Otevřete datový model SchoolModel.edmx , klikněte na návrhovou plochu a potom v podokně vlastností nastavte vlastnost Opožděné načítání povoleno na False
hodnotu . Uložte a zavřete datový model.
Správa stavu zobrazení
Aby bylo možné zajistit funkci aktualizace, musí webová stránka ASP.NET při vykreslení stránky ukládat hodnoty původních vlastností entity. Během zpracování zpětného volání může ovládací prvek znovu vytvořit původní stav entity a volat metodu entity Attach
před použitím změn a voláním SaveChanges
metody . Ve výchozím nastavení ASP.NET Web Forms ovládací prvky dat používají k uložení původních hodnot stav zobrazení. Stav zobrazení ale může mít vliv na výkon, protože je uložený ve skrytých polích, která můžou podstatně zvětšit velikost stránky odesílané do prohlížeče a z prohlížeče.
Techniky správy stavu zobrazení nebo alternativy, jako je stav relace, nejsou pro Entity Framework jedinečné, takže tento kurz nezabředá do tohoto tématu podrobně. Další informace najdete na odkazech na konci kurzu.
Verze 4 ASP.NET ale nabízí nový způsob práce se stavem zobrazení, o které by měl vědět každý ASP.NET vývojář Web Forms aplikací: ViewStateMode
vlastnost . Tuto novou vlastnost lze nastavit na úrovni stránky nebo ovládacího prvku a umožňuje zakázat stav zobrazení ve výchozím nastavení stránky a povolit ho pouze pro ovládací prvky, které to potřebují.
U aplikací, kde je výkon kritický, je dobrým postupem vždy zakázat stav zobrazení na úrovni stránky a povolit ho pouze pro ovládací prvky, které to vyžadují. Velikost zobrazení na stránkách Contoso University by se touto metodou výrazně nezmenšila, ale abyste viděli, jak to funguje, uděláte to pro stránku Instructors.aspx . Tato stránka obsahuje mnoho ovládacích prvků, včetně ovládacího prvku se zakázaným Label
stavem zobrazení. Žádný z ovládacích prvků na této stránce ve skutečnosti nemusí mít povolený stav zobrazení. (Vlastnost DataKeyNames
GridView
ovládacího prvku určuje stav, který se musí udržovat mezi zpětnými operacemi, ale tyto hodnoty se zachovají ve stavu ovládacího prvku, na který tato vlastnost nemá vliv ViewStateMode
.)
Direktiva Page
a Label
značky ovládacích prvků se v současné době podobají následujícímu příkladu:
<%@ 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>
...
Proveďte následující změny:
- Přidejte
ViewStateMode="Disabled"
do direktivyPage
. - Odeberte
ViewStateMode="Disabled"
zLabel
ovládacího prvku.
Kód teď vypadá podobně jako v následujícím příkladu:
<%@ 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>
...
Stav zobrazení je teď pro všechny ovládací prvky zakázaný. Pokud později přidáte ovládací prvek, který potřebuje použít stav zobrazení, stačí zahrnout ViewStateMode="Enabled"
atribut tohoto ovládacího prvku.
Použití možnosti sloučení NoTracking
Když kontext objektu načte řádky databáze a vytvoří objekty entity, které je představují, ve výchozím nastavení tyto objekty entit také sleduje pomocí svého správce stavu objektů. Tato sledovací data fungují jako mezipaměť a používají se při aktualizaci entity. Vzhledem k tomu, že webová aplikace má obvykle krátkodobé instance kontextu objektu, dotazy často vrací data, která není potřeba sledovat, protože kontext objektu, který je čte, bude odstraněn předtím, než se libovolná entita, kterou načte, znovu použije nebo aktualizuje.
V Entity Frameworku můžete nastavením možnosti sloučení určit, jestli kontext objektu sleduje objekty entity. Možnost sloučení můžete nastavit pro jednotlivé dotazy nebo pro sady entit. Pokud ho nastavíte pro sadu entit, znamená to, že nastavujete výchozí možnost sloučení pro všechny dotazy vytvořené pro tuto sadu entit.
Pro aplikaci Contoso University není sledování potřeba pro žádnou ze sad entit, ke kterým přistupujete z úložiště, takže můžete při vytváření instance kontextu objektu ve třídě úložiště nastavit možnost NoTracking
sloučení na na . (Všimněte si, že v tomto kurzu nebude mít nastavení možnosti sloučení znatelný vliv na výkon aplikace. Možnost NoTracking
pravděpodobně provede pozorovatelné zlepšení výkonu pouze v určitých scénářích s vysokým objemem dat.)
Ve složce DAL otevřete soubor SchoolRepository.cs a přidejte metodu konstruktoru, která nastaví možnost sloučení pro sady entit, ke kterým úložiště přistupuje:
public SchoolRepository()
{
context.Departments.MergeOption = MergeOption.NoTracking;
context.InstructorNames.MergeOption = MergeOption.NoTracking;
context.OfficeAssignments.MergeOption = MergeOption.NoTracking;
}
Předběžné kompilace dotazů LINQ
Když Entity Framework poprvé spustí dotaz Entity SQL v rámci životnosti dané ObjectContext
instance, kompilace dotazu nějakou dobu trvá. Výsledek kompilace se ukládá do mezipaměti, což znamená, že následné provádění dotazu je mnohem rychlejší. Dotazy LINQ se řídí podobným vzorem s tím rozdílem, že část práce potřebné ke kompilaci dotazu se provádí při každém spuštění dotazu. Jinými slovy, u dotazů LINQ se ve výchozím nastavení neukládají do mezipaměti všechny výsledky kompilace.
Pokud máte dotaz LINQ, který očekáváte opakované spuštění v kontextu objektu, můžete napsat kód, který způsobí, že všechny výsledky kompilace budou uloženy do mezipaměti při prvním spuštění dotazu LINQ.
Pro ilustraci to uděláte pro dvě Get
metody ve SchoolRepository
třídě, z nichž jedna nepřebírají žádné parametry ( GetInstructorNames
metoda) a jedna, která vyžaduje parametr (metodu GetDepartmentsByAdministrator
). Tyto metody, jak jsou nyní, ve skutečnosti nemusí být kompilovány, protože nejsou dotazy 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();
}
Abyste ale mohli zkompilované dotazy vyzkoušet, budete postupovat, jako by byly napsány jako následující dotazy 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();
}
Kód v těchto metodách můžete změnit na výše uvedený kód a spustit aplikaci, abyste ověřili, že funguje, než budete pokračovat. Následující pokyny ale rovnou přeskočí do vytváření předkompilovaných verzí těchto verzí.
Ve složce DAL vytvořte soubor třídy, pojmenujte ho SchoolEntities.cs a nahraďte existující kód následujícím kódem:
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();
}
}
}
Tento kód vytvoří částečnou třídu, která rozšiřuje automaticky vygenerovanou třídu kontextu objektu. Částečná třída zahrnuje dva kompilované dotazy LINQ pomocí Compile
metody CompiledQuery
třídy . Vytvoří také metody, které můžete použít k volání dotazů. Uložte a zavřete tento soubor.
Dále v souboru SchoolRepository.cs změňte existující GetInstructorNames
metody a GetDepartmentsByAdministrator
metody ve třídě úložiště tak, aby volaly zkompilované dotazy:
public IEnumerable<InstructorName> GetInstructorNames()
{
return context.CompiledInstructorNamesQuery();
}
public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
return context.CompiledDepartmentsByAdministratorQuery(administrator);
}
Spusťte stránku Departments.aspx a ověřte, že funguje stejně jako předtím. Metoda GetInstructorNames
je volána, aby se naplnit rozevírací seznam správce, a GetDepartmentsByAdministrator
metoda je volána, když kliknete na Aktualizovat , aby se ověřilo, že žádný instruktor není správcem více než jednoho oddělení.
V aplikaci Contoso University jste předem zkompilovali dotazy, abyste viděli, jak na to, ne proto, že by to měřitelně zlepšilo výkon. Předkompilováním dotazů LINQ se do kódu přidá úroveň složitosti, proto se ujistěte, že to uděláte jenom pro dotazy, které ve skutečnosti představují kritické body výkonu ve vaší aplikaci.
Zkoumání dotazů odeslaných do databáze
Při zkoumání problémů s výkonem je někdy užitečné znát přesné příkazy SQL, které Entity Framework odesílá do databáze. Pokud pracujete s objektem IQueryable
, jedním ze způsobů, jak to udělat, je použít metodu ToTraceString
.
V souboru SchoolRepository.cs změňte kód v GetDepartmentsByName
metodě tak, aby odpovídal následujícímu příkladu:
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();
}
Proměnnou departments
musí být přetypován na ObjectQuery
typ pouze proto, že Where
metoda na konci předchozího řádku vytvoří IQueryable
objekt; bez Where
metody by přetypování nebylo nutné.
Nastavte na return
řádku zarážku a pak v ladicím programu spusťte stránku Departments.aspx . Když se dostanete na zarážku, prozkoumejte commandText
proměnnou v okně Místní a pomocí vizualizéru textu (lupa ve sloupci Hodnota ) zobrazte její hodnotu v okně Vizualizéru textu . Můžete vidět celý příkaz SQL, který je výsledkem tohoto kódu:
Alternativně funkce IntelliTrace v Visual Studio Ultimate poskytuje způsob, jak zobrazit příkazy SQL vygenerované rozhraním Entity Framework, které nevyžadují změnu kódu nebo dokonce nastavení zarážky.
Poznámka
Následující postupy můžete provést pouze v případě, že máte Visual Studio Ultimate.
Obnovte původní kód v GetDepartmentsByName
metodě a pak v ladicím programu spusťte stránku Departments.aspx .
V sadě Visual Studio vyberte nabídku Ladit , pak IntelliTrace a pak Události IntelliTrace.
V okně IntelliTrace klikněte na Přerušit vše.
V okně IntelliTrace se zobrazí seznam posledních událostí:
Klikněte na řádek ADO.NET . Rozbalí se a zobrazí text příkazu:
Celý textový řetězec příkazu můžete zkopírovat do schránky z okna Místní .
Předpokládejme, že pracujete s databází s více tabulkami, relacemi a sloupci, než je jednoduchá School
databáze. Možná zjistíte, že dotaz, který shromažďuje všechny potřebné informace v jednom Select
příkazu obsahujícím více Join
klauzulí, bude příliš složitý na to, aby fungoval efektivně. V takovém případě můžete přepnout z dychtivého načítání na explicitní načítání, aby se dotaz zjednodušil.
Zkuste například změnit kód v GetDepartmentsByName
metodě v souboru SchoolRepository.cs. V současné době v této metodě máte dotaz na objekt, který obsahuje Include
metody pro Person
vlastnosti a Courses
navigace. return
Nahraďte příkaz kódem, který provádí explicitní načtení, jak je znázorněno v následujícím příkladu:
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;
}
V ladicím programu spusťte stránku Departments.aspx a znovu zkontrolujte okno IntelliTrace jako předtím. Tam, kde předtím byl jeden dotaz, uvidíte jejich dlouhou posloupnost.
Klikněte na první ADO.NET řádek a podívejte se, co se stalo se složitým dotazem, který jste si zobrazili dříve.
Dotaz z oddělení se stal jednoduchým Select
dotazem bez Join
klauzule, ale po něm následují samostatné dotazy, které načtou související kurzy a správce pomocí sady dvou dotazů pro každé oddělení vrácené původním dotazem.
Poznámka
Pokud necháte povolené opožděné načítání, může být výsledkem opožděného načítání vzor, který zde vidíte a který se stejný dotaz několikrát opakuje. Vzor, kterému se obvykle chcete vyhnout, je opožděné načítání souvisejících dat pro každý řádek primární tabulky. Pokud jste si ověřili, že je dotaz s jedním spojením příliš složitý na to, aby byl efektivní, obvykle byste v takových případech mohli zvýšit výkon změnou primárního dotazu tak, aby používal dychtivé načítání.
Předgenerování zobrazení
Při prvním vytvoření objektu ObjectContext
v nové doméně aplikace Entity Framework vygeneruje sadu tříd, které používá pro přístup k databázi. Tyto třídy se nazývají zobrazení, a pokud máte velmi velký datový model, může generování těchto zobrazení zpozdit odpověď webu na první požadavek na stránku po inicializaci nové domény aplikace. Toto zpoždění prvního požadavku můžete snížit vytvořením zobrazení v době kompilace, nikoli v době běhu.
Poznámka
Pokud vaše aplikace nemá extrémně velký datový model nebo pokud má velký datový model, ale nezajímá vás problém s výkonem, který se týká jenom požadavku na první stránku po recyklaci služby IIS, můžete tuto část přeskočit. Vytvoření zobrazení neproběhlo pokaždé, když vytvoříte instanci objektu ObjectContext
, protože zobrazení jsou uložená v mezipaměti v doméně aplikace. Proto, pokud často recyklujete aplikaci ve službě IIS, bude předgenerovaná zobrazení přínosná jen velmi málo požadavků na stránku.
Zobrazení můžete předem generovat pomocí nástroje příkazového řádkuEdmGen.exe nebo pomocí šablony T4 (Text Template Transformation Toolkit). V tomto kurzu použijete šablonu T4.
Do složky DAL přidejte soubor pomocí šablony Text Template (je pod uzlem Obecné v seznamu Nainstalované šablony ) a pojmenujte ho SchoolModel.Views.tt. Nahraďte existující kód v souboru následujícím kódem:
<#
/***************************************************************************
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;
}
#>
Tento kód vygeneruje zobrazení pro soubor .edmx , který je umístěný ve stejné složce jako šablona a má stejný název jako soubor šablony. Pokud má například soubor šablony název SchoolModel.Views.tt, bude hledat soubor datového modelu s názvem SchoolModel.edmx.
Uložte soubor, klikněte pravým tlačítkem na soubor v Průzkumník řešení a vyberte Spustit vlastní nástroj.
Visual Studio vygeneruje soubor kódu, který vytvoří zobrazení s názvem SchoolModel.Views.cs na základě šablony. (Možná jste si všimli, že se soubor kódu vygeneroval ještě předtím, než vyberete Spustit vlastní nástroj, hned po uložení souboru šablony.)
Teď můžete aplikaci spustit a ověřit, že funguje stejně jako předtím.
Další informace o předgenerovaných zobrazeních najdete v následujících zdrojích informací:
- Postupy: Předgenerování zobrazení pro zlepšení výkonu dotazů na webu MSDN Vysvětluje, jak pomocí nástroje příkazového
EdmGen.exe
řádku předem vygenerovat zobrazení. - Izolace výkonu pomocí předkompilovaných nebo předem generovaných zobrazení v Entity Frameworku 4 na blogu týmu zákaznického poradce pro Windows Server AppFabric.
Tím se dokončí úvod ke zvýšení výkonu ve webové aplikaci ASP.NET, která používá Entity Framework. Další informace naleznete v následujících zdrojích:
- Aspekty výkonu (Entity Framework) na webu MSDN.
- Příspěvky související s výkonem na blogu týmu Entity Framework
- Možnosti sloučení EF a kompilované dotazy. Blogový příspěvek, který vysvětluje neočekávané chování kompilovaných dotazů a možností sloučení, jako
NoTracking
je . Pokud máte v aplikaci v úmyslu používat kompilované dotazy nebo manipulovat s nastavením možností sloučení, přečtěte si toto téma jako první. - Příspěvky související s Rozhraním Entity Framework na blogu Týmu pro poradenství pro zákazníky pro data a modelování Obsahuje příspěvky o kompilovaných dotazech a používání profileru sady Visual Studio 2010 ke zjišťování problémů s výkonem.
- ASP.NET doporučení ke správě stavu.
- Použití Entity Frameworku a ObjectDataSource: Vlastní stránkování. Příspěvek na blogu, který vychází z aplikace ContosoUniversity vytvořené v těchto kurzech, vysvětluje, jak implementovat stránkování na stránce Departments.aspx .
V dalším kurzu si projděte některá důležitá vylepšení Entity Frameworku, která jsou ve verzi 4 nová.