Максимизация производительности с помощью Entity Framework 4.0 в веб-приложении ASP.NET 4
Эта серия руководств основана на веб-приложении Университета Contoso, созданном начало работы с серией учебников По Entity Framework 4.0. Если вы не выполнили предыдущие руководства, в качестве отправной точки для этого руководства можно скачать созданное приложение . Вы также можете скачать приложение , созданное в полной серии учебников. Если у вас есть вопросы по этим руководствам, вы можете опубликовать их на форуме ASP.NET Entity Framework.
В предыдущем руководстве вы узнали, как обрабатывать конфликты параллелизма. В этом руководстве показаны варианты повышения производительности веб-приложения ASP.NET, использующего Entity Framework. Вы узнаете о нескольких методах повышения производительности или диагностики проблем с производительностью.
Сведения, представленные в следующих разделах, скорее всего, будут полезны в самых разных сценариях:
- Эффективная загрузка связанных данных.
- Управление состоянием представления.
Сведения, представленные в следующих разделах, могут оказаться полезными, если у вас есть отдельные запросы, которые представляют проблемы с производительностью:
NoTracking
Используйте параметр слияния.- Предварительная компиляция запросов LINQ.
- Изучите команды запроса, отправленные в базу данных.
Сведения, представленные в следующем разделе, потенциально полезны для приложений с очень большими моделями данных:
- Предварительное создание представлений.
Примечание
На производительность веб-приложения влияют многие факторы, в том числе размер данных запросов и ответов, скорость запросов к базе данных, количество запросов, которые сервер может вставить в очередь и как быстро он может их обслуживать, а также эффективность любых библиотек клиентских сценариев, которые вы можете использовать. Если производительность приложения является критически важной или если тестирование или опыт показывает, что производительность приложения не является удовлетворительной, следует следовать обычному протоколу для настройки производительности. Выполните меру, чтобы определить, где возникают узкие места производительности, а затем устранить области, которые будут оказывать наибольшее влияние на общую производительность приложения.
В этом разделе основное внимание уделяется способам потенциального повышения производительности entity Framework в ASP.NET. Приведенные здесь рекомендации полезны, если вы определили, что доступ к данным является одним из узких мест производительности в приложении. За исключением отмеченного, описанные здесь методы не следует рассматривать как "лучшие методики" в целом— многие из них подходят только в исключительных ситуациях или для решения весьма конкретных узких мест производительности.
Чтобы приступить к работе с этим руководством, запустите Visual Studio и откройте веб-приложение Университета Contoso, с которым вы работали в предыдущем руководстве.
Эффективная загрузка связанных данных
Платформа Entity Framework может загружать связанные данные в свойства навигации сущности несколькими способами.
Отложенная загрузка. При первом чтении сущности связанные данные не извлекаются. Однако при первой попытке доступа к свойству навигации необходимые для этого свойства навигации данные извлекаются автоматически. Это приводит к отправке нескольких запросов к базе данных — по одному для самой сущности и по одному при каждом получении связанных данных для сущности.
Безотложная загрузка. При чтении сущности связанные данные извлекаются вместе с ней. Обычно такая загрузка представляет собой одиночный запрос с соединением, который получает все необходимые данные. Вы указываете неотложную загрузку Include
с помощью метода , как вы уже видели в этих руководствах.
Явная загрузка. Это похоже на отложенную загрузку, за исключением того, что вы явным образом извлекаете связанные данные в коде; Это не происходит автоматически при доступе к свойству навигации. Связанные данные загружают вручную с помощью
Load
метода свойства навигации для коллекций или используютLoad
метод ссылочного свойства для свойств, которые содержат один объект. (Например, вызываетсяPersonReference.Load
метод для загрузки свойства навигацииPerson
сущностиDepartment
.)
Так как они не получают значения свойств сразу, отложенная загрузка и явная загрузка также называются отложенной загрузкой.
Отложенная загрузка — это поведение по умолчанию для контекста объекта, созданного конструктором. Если открыть SchoolModel.Designer. Cs-файл, определяющий класс контекста объекта, вы найдете три метода конструктора, каждый из которых содержит следующую инструкцию:
this.ContextOptions.LazyLoadingEnabled = true;
Как правило, если вы знаете, что вам нужны связанные данные для каждой полученной сущности, то безотложная загрузка обеспечивает наилучшую производительность, так как один запрос, отправленный в базу данных, обычно более эффективен, чем отдельные запросы для каждой полученной сущности. С другой стороны, если требуется доступ к свойствам навигации сущности только редко или только для небольшого набора сущностей, отложенная загрузка или явная загрузка может быть более эффективной, так как при неотложной загрузке будет получено больше данных, чем требуется.
В веб-приложении отложенная загрузка в любом случае может иметь относительно малое значение, так как действия пользователя, влияющие на потребность в связанных данных, выполняются в браузере, который не имеет подключения к контексту объекта, отображающего страницу. С другой стороны, при привязке данных к элементу управления обычно известно, какие данные вам нужны, поэтому обычно лучше выбирать неотложную или отложенную загрузку в зависимости от того, что подходит для каждого сценария.
Кроме того, элемент управления для исходящего трафика данных может использовать объект сущности после удаления контекста объекта. В этом случае попытка отложенной загрузки свойства навигации завершится ошибкой. Отображается ясное сообщение об ошибке: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
"
Элемент EntityDataSource
управления по умолчанию отключает отложенную загрузку. ObjectDataSource
Для элемента управления, который вы используете для текущего руководства (или если вы обращаетесь к контексту объекта из кода страницы), есть несколько способов отключить отложенную загрузку по умолчанию. Его можно отключить при создании экземпляра контекста объекта. Например, можно добавить следующую строку в метод конструктора SchoolRepository
класса :
context.ContextOptions.LazyLoadingEnabled = false;
Для приложения Contoso University вы автоматически отключаете отложенную загрузку контекста объекта, чтобы не задавать это свойство при создании экземпляра контекста.
Откройте модель данных SchoolModel.edmx , щелкните область конструктора, а затем в области свойств установите для свойства Отложенная загрузка включено значение False
. Сохраните и закройте модель данных.
Управление состоянием представления
Чтобы обеспечить функциональность обновления, ASP.NET веб-страница должна хранить исходные значения свойств сущности при отрисовке страницы. Во время обратной обработки элемент управления может повторно создать исходное состояние сущности и вызвать метод сущности Attach
перед применением изменений и вызовом SaveChanges
метода . По умолчанию ASP.NET Web Forms элементы управления данными используют состояние представления для хранения исходных значений. Однако состояние представления может повлиять на производительность, так как оно хранится в скрытых полях, которые могут значительно увеличить размер страницы, отправляемой в браузер и из него.
Методы управления состоянием представления или альтернативные варианты, такие как состояние сеанса, не являются уникальными для Entity Framework, поэтому в этом руководстве подробно не рассматривается этот раздел. Дополнительные сведения см. по ссылкам в конце учебника.
Однако версия 4 ASP.NET предоставляет новый способ работы с состоянием представления, который должен знать каждый ASP.NET разработчик веб-формы приложений: ViewStateMode
свойство . Это новое свойство можно задать на уровне страницы или элемента управления и позволяет отключить состояние просмотра по умолчанию для страницы и включить его только для элементов управления, которым оно нужно.
Для приложений, где важна производительность, рекомендуется всегда отключать состояние просмотра на уровне страницы и включать его только для элементов управления, которым оно требуется. Размер состояния представления на страницах Университета Contoso не будет существенно уменьшен этим методом, но чтобы увидеть, как это работает, вы сделаете это для страницы Instructors.aspx . Эта страница содержит множество элементов управления, включая Label
элемент управления с отключенным состоянием просмотра. Ни один из элементов управления на этой странице не должен включать состояние просмотра. (Свойство DataKeyNames
GridView
элемента управления указывает состояние, которое должно поддерживаться между обратными передачами, но эти значения хранятся в состоянии элемента управления, на которое свойство не влияет ViewStateMode
.)
В настоящее время директива Page
и Label
разметка элемента управления похожи на следующий пример:
<%@ 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>
...
Внесите следующие изменения:
- Добавьте
ViewStateMode="Disabled"
в директивуPage
. - Удалить
ViewStateMode="Disabled"
изLabel
элемента управления .
Разметка теперь похожа на следующий пример:
<%@ 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>
...
Состояние просмотра теперь отключено для всех элементов управления. Если позже вы добавите элемент управления, который должен использовать состояние представления, достаточно включить ViewStateMode="Enabled"
атрибут для этого элемента управления.
Использование параметра noTracking Merge
Когда контекст объекта извлекает строки базы данных и создает объекты сущностей, которые их представляют, по умолчанию эти объекты также отслеживают с помощью диспетчера состояний объектов. Эти данные отслеживания действуют как кэш и используются при обновлении сущности. Так как веб-приложение обычно имеет кратковременные экземпляры контекста объекта, запросы часто возвращают данные, которые не нужно отслеживать, так как контекст объекта, который их считывает, будет удален до того, как какие-либо из считываемых сущностей будут использоваться повторно или обновлены.
В Entity Framework можно указать, отслеживает ли контекст объекта объекты сущности, задав параметр слияния. Параметр слияния можно задать для отдельных запросов или для наборов сущностей. Если вы задали его для набора сущностей, это означает, что вы устанавливаете параметр слияния по умолчанию для всех запросов, созданных для этого набора сущностей.
Для приложения Contoso University отслеживание не требуется для каких-либо наборов сущностей, к которым вы обращаетесь из репозитория, поэтому при создании экземпляра контекста объекта в классе репозитория можно задать для параметра NoTracking
слияния значение . (Обратите внимание, что в этом руководстве задание параметра слияния не оказывает заметного влияния на производительность приложения. Этот NoTracking
параметр, скорее всего, приведет к заметному повышению производительности только в некоторых сценариях с большим объемом данных.)
В папке DAL откройте файл SchoolRepository.cs и добавьте метод конструктора, который задает параметр слияния для наборов сущностей, к которым обращается репозиторий:
public SchoolRepository()
{
context.Departments.MergeOption = MergeOption.NoTracking;
context.InstructorNames.MergeOption = MergeOption.NoTracking;
context.OfficeAssignments.MergeOption = MergeOption.NoTracking;
}
Предварительная компиляция запросов LINQ
Когда Платформа Entity Framework впервые выполняет запрос Entity SQL в течение срока действия данного ObjectContext
экземпляра, компиляция запроса занимает некоторое время. Результат компиляции кэшируется, что означает, что последующие выполнения запроса выполняются гораздо быстрее. Запросы LINQ следуют аналогичному шаблону, за исключением того, что часть работы, необходимой для компиляции запроса, выполняется каждый раз при выполнении запроса. Другими словами, для запросов LINQ по умолчанию кэшируются не все результаты компиляции.
Если у вас есть запрос LINQ, который должен выполняться многократно в контексте объекта, можно написать код, который приводит к кэшированию всех результатов компиляции при первом выполнении запроса LINQ.
В качестве иллюстрации вы будете делать это для двух Get
методов в SchoolRepository
классе, один из которых не принимает никаких параметров ( GetInstructorNames
метод), а другой требует параметр ( GetDepartmentsByAdministrator
метод ). Эти методы в том виде, в который они сейчас скомпилированы, на самом деле не нужно компилировать, так как они не являются запросами 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();
}
Тем не менее, чтобы вы могли опробовать скомпилированные запросы, вы будете действовать так, как если бы они были написаны как следующие запросы 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();
}
Вы можете изменить код в этих методах на то, что показано выше, и запустить приложение, чтобы убедиться, что он работает, прежде чем продолжить. Но приведенные ниже инструкции переходят непосредственно к созданию предварительно скомпилированных версий этих версий.
Создайте файл класса в папке DAL , назовите его SchoolEntities.cs и замените существующий код следующим кодом:
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();
}
}
}
Этот код создает разделяемый класс, который расширяет автоматически создаваемый класс контекста объекта. Разделяемый класс включает два скомпилированных запроса LINQ с помощью Compile
метода CompiledQuery
класса . Он также создает методы, которые можно использовать для вызова запросов. Сохраните и закройте этот файл.
Затем в Файле SchoolRepository.cs измените существующие GetInstructorNames
методы и GetDepartmentsByAdministrator
в классе репозитория, чтобы они вызывали скомпилированные запросы:
public IEnumerable<InstructorName> GetInstructorNames()
{
return context.CompiledInstructorNamesQuery();
}
public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
return context.CompiledDepartmentsByAdministratorQuery(administrator);
}
Запустите страницу Departments.aspx , чтобы убедиться, что она работает так же, как и раньше. Метод GetInstructorNames
вызывается для заполнения раскрывающегося списка администратора, а GetDepartmentsByAdministrator
метод вызывается при нажатии кнопки Обновить , чтобы убедиться, что ни один преподаватель не является администратором нескольких отделов.
Вы предварительно скомпилировали запросы в приложении Contoso University только для того, чтобы узнать, как это сделать, а не потому, что это значительно повысит производительность. Предварительная компиляция запросов LINQ повышает уровень сложности кода, поэтому убедитесь, что вы делаете это только для запросов, которые фактически представляют узкие места производительности в приложении.
Проверка запросов, отправленных в базу данных
При изучении проблем с производительностью иногда полезно знать точные команды SQL, которые Entity Framework отправляет в базу данных. Если вы работаете IQueryable
с объектом , один из способов сделать это — использовать ToTraceString
метод .
В файле SchoolRepository.cs измените код в методе GetDepartmentsByName
в соответствии со следующим примером:
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();
}
Переменная departments
должна быть приведена к типу ObjectQuery
только потому, что Where
метод в конце предыдущей строки создает IQueryable
объект; без Where
метода приведение не было бы обязательным.
Задайте точку останова в строке return
, а затем запустите страницу Departments.aspx в отладчике. При достижении точки останова проверьте commandText
переменную в окне Локальные и используйте визуализатор текста (лупу в столбце Значение ), чтобы отобразить ее значение в окне Визуализатор текста . Вы можете просмотреть всю команду SQL, полученную из этого кода:
В качестве альтернативы функция IntelliTrace в Visual Studio Ultimate предоставляет способ просмотра команд SQL, созданных Entity Framework, для которых не требуется изменять код или даже устанавливать точку останова.
Примечание
Следующие процедуры можно выполнить только при наличии Visual Studio Ultimate.
Восстановите исходный код в методе GetDepartmentsByName
, а затем запустите страницу Departments.aspx в отладчике.
В Visual Studio выберите меню Отладка , Затем IntelliTrace и События IntelliTrace.
В окне IntelliTrace щелкните Разорвать все.
В окне IntelliTrace отображается список последних событий:
Щелкните строку ADO.NET . Он разворачивается, чтобы отобразить текст команды:
Вы можете скопировать всю текстовую строку команды в буфер обмена из окна Локальные .
Предположим, что вы работали с базой данных с большими таблицами, связями и столбцами, чем в простой School
базе данных. Вы можете обнаружить, что запрос, который собирает все необходимые сведения в одной Select
инструкции, содержащей несколько Join
предложений, становится слишком сложным для эффективной работы. В этом случае можно переключиться с неотложной загрузки на явную загрузку, чтобы упростить запрос.
Например, попробуйте изменить код в методе GetDepartmentsByName
SchoolRepository.cs. В настоящее время в этом методе есть запрос на объект, который содержит Include
методы для свойств навигации Person
и Courses
. Замените инструкцию return
кодом, выполняющим явную загрузку, как показано в следующем примере:
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;
}
Запустите страницу Departments.aspx в отладчике и проверка окно IntelliTrace еще раз, как и раньше. Теперь, когда ранее существовал один запрос, вы увидите длинную последовательность из них.
Щелкните первую строку ADO.NET , чтобы узнать, что произошло со сложным запросом, который вы просматривали ранее.
Запрос от отделов стал простым Select
запросом без Join
предложения, но за ним следуют отдельные запросы, которые извлекают связанные курсы и администратора, используя набор из двух запросов для каждого отдела, возвращаемых исходным запросом.
Примечание
Если оставить отложенную загрузку включенной, шаблон, который вы видите здесь, с тем же запросом, повторяющийся много раз, может быть результатом отложенной загрузки. Шаблон, которого обычно требуется избегать, — это отложенная загрузка связанных данных для каждой строки основной таблицы. Если вы не убедились, что запрос на одно соединение слишком сложен, чтобы быть эффективным, вы обычно можете повысить производительность в таких случаях, изменив основной запрос, чтобы использовать неотложную загрузку.
Предварительное создание представлений
ObjectContext
При первом создании объекта в новом домене приложения Entity Framework создает набор классов, которые используются для доступа к базе данных. Эти классы называются представлениями, и если у вас очень большая модель данных, создание этих представлений может задержать ответ веб-сайта на первый запрос страницы после инициализации нового домена приложения. Вы можете уменьшить задержку первого запроса, создав представления во время компиляции, а не во время выполнения.
Примечание
Если приложение не имеет очень большой модели данных или имеет модель больших данных, но вы не беспокоитесь о проблеме с производительностью, которая влияет только на самый первый запрос страницы после перезапуска IIS, этот раздел можно пропустить. Создание представления происходит не каждый раз при создании экземпляра ObjectContext
объекта, так как представления кэшируются в домене приложения. Таким образом, если вы часто не перезапуските приложение в СЛУЖБАх IIS, очень немногие запросы страниц будут полезны от предварительно созданных представлений.
Представления можно предварительно создать с помощью программы командной строкиEdmGen.exe или с помощью шаблона T4. В этом руководстве вы будете использовать шаблон T4.
В папке DAL добавьте файл с помощью шаблона Текстовый шаблон (он находится в узле Общие в списке Установленные шаблоны ) и присвойте ему имя SchoolModel.Views.tt. Замените существующий код в файле следующим кодом:
<#
/***************************************************************************
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;
}
#>
Этот код создает представления для EDMX-файла , который находится в той же папке, что и шаблон, и имя которого совпадает с именем файла шаблона. Например, если файл шаблона называется SchoolModel.Views.tt, он будет искать файл модели данных с именем SchoolModel.edmx.
Сохраните файл, щелкните его правой кнопкой мыши в Обозреватель решений и выберите Запустить пользовательское средство.
Visual Studio создает файл кода, который создает представления с именем SchoolModel.Views.cs на основе шаблона. (Возможно, вы заметили, что файл кода создается еще до нажатия кнопки Запустить пользовательское средство, сразу после сохранения файла шаблона.)
Теперь вы можете запустить приложение и убедиться, что оно работает так же, как и раньше.
Дополнительные сведения о предварительно созданных представлениях см. в следующих ресурсах:
- Практическое руководство. Предварительное создание представлений для повышения производительности запросов на веб-сайте MSDN. Объясняется, как использовать программу командной
EdmGen.exe
строки для предварительного создания представлений. - Изоляция производительности с помощью предварительно скомпилированных или предварительно созданных представлений в Entity Framework 4 в блоге Группы рекомендаций клиентов Windows Server AppFabric.
На этом завершается введение в повышение производительности в веб-приложении ASP.NET, использующим Entity Framework. Дополнительные сведения см. в следующих ресурсах:
- Рекомендации по производительности (Entity Framework) на веб-сайте MSDN.
- Записи, связанные с производительностью, в блоге команды Entity Framework.
- Параметры слияния EF и скомпилированные запросы. Запись блога, объясняющая непредвиденное поведение скомпилированных запросов и параметров слияния, таких как
NoTracking
. Если вы планируете использовать скомпилированные запросы или управлять параметрами параметров слияния в приложении, сначала прочтите это. - Записи, связанные с Entity Framework, в блоге группы по консультированию клиентов по данным и моделированию. Включает записи о скомпилированных запросах и использовании Профилировщика Visual Studio 2010 для обнаружения проблем с производительностью.
- ASP.NET рекомендации по управлению состоянием.
- Использование Entity Framework и ObjectDataSource: настраиваемое разбиение по страницам. В записи блога, созданной на основе приложения ContosoUniversity, созданного в этих руководствах, объясняется, как реализовать разбиение по страницам на странице Departments.aspx .
В следующем руководстве рассматриваются некоторые важные улучшения Entity Framework, которые являются новыми в версии 4.