Sdílet prostřednictvím


Maximalizace výkonu pomocí Entity Framework 4.0 ve webové aplikaci ASP.NET 4

Tom Dykstra

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.

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.

    Obrázek 05

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.

Obrázek 07

  • 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říklad PersonReference.Load načíst Person navigační vlastnost Department entity.)

    Obrázek 06

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 Falsehodnotu . Uložte a zavřete datový model.

Obrázek 04

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 DataKeyNamesGridView 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 direktivy Page .
  • Odeberte ViewStateMode="Disabled" z Label 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í.

Obrázek03

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:

Obrázek08

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.

Obrázek 11

V okně IntelliTrace klikněte na Přerušit vše.

Obrázek 12

V okně IntelliTrace se zobrazí seznam posledních událostí:

Obrázek09

Klikněte na řádek ADO.NET . Rozbalí se a zobrazí text příkazu:

Obrázek 10

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.

Obrázek 13

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.

Obrázek 14

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.

Obrázek02

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.)

Obrázek01

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í:

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:

V dalším kurzu si projděte některá důležitá vylepšení Entity Frameworku, která jsou ve verzi 4 nová.