Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой серии учебников расширяется функциональность веб-приложения Contoso University, которое было создано с помощью серии учебников Начало работы с Entity Framework 4.0. Если вы не прошли предыдущие уроки, для начала этого руководства вы можете скачать приложение, которое бы вы создали. Вы также можете скачать приложение , созданное в полной серии учебников.
Пример веб-приложения Contoso University демонстрирует создание приложений веб-форм ASP.NET с помощью Entity Framework 4.0 и Visual Studio 2010. Пример приложения — это веб-сайт для вымышленного университета Contoso. На нем предусмотрены различные функции, в том числе прием учащихся, создание курсов и назначение преподавателей.
В этом руководстве показаны примеры в C#. Скачиваемый пример содержит код как в C#, так и в Visual Basic.
База данных в первую очередь
Существует три способа работы с данными в Entity Framework: База данных First, Model First и Code First. Это руководство предназначено для базы данных First. Сведения о различиях между этими рабочими процессами и рекомендациями по выбору лучшего для вашего сценария см. в разделе "Рабочие процессы разработки Entity Framework".
Веб-формы
Как и в серии "Начало работы", в этой серии учебников используется модель веб-форм ASP.NET и предполагается, что вы знаете, как работать с веб-формами ASP.NET в Visual Studio. Если вы этого не сделали, см. руководство "Начало работы с веб-формами ASP.NET 4.5". Если вы предпочитаете работать с платформой ASP.NET MVC, см. статью "Начало работы с Entity Framework" с помощью ASP.NET MVC.
Версии программного обеспечения
Показан в руководстве Также работает с Windows 7 Windows 8 Visual Studio 2010 г. Visual Studio 2010 Express для Интернета. Руководство не было протестировано с помощью более поздних версий Visual Studio. Существует множество различий в выборах меню, диалоговых окнах и шаблонах. .NET 4 .NET 4.5 является обратно совместимым с .NET 4, но руководство не было протестировано с .NET 4.5. Entity Framework 4 Руководство не было протестировано с помощью более поздних версий Entity Framework. Начиная с Entity Framework 5, EF по умолчанию использует DbContext API, который был представлен в EF 4.1. Элемент управления EntityDataSource предназначен для использованияObjectContextAPI. Сведения о том, как использовать элемент управления EntityDataSource с API, см. в этой записи блога. Вопросы
Если у вас есть вопросы, которые не связаны напрямую с руководством, их можно опубликовать на форуме ASP.NET Entity Framework, форуме Entity Framework и LINQ to Entity Entity, или StackOverflow.com.
Элемент EntityDataSource управления позволяет создавать приложение очень быстро, но обычно требуется сохранить значительный объем бизнес-логики и логики доступа к данным на страницах .aspx . Если вы ожидаете, что ваше приложение будет увеличиваться в сложности и требовать постоянного сопровождения, вы можете заранее вложить больше времени в разработку, чтобы создать многоуровневую или многоуровневую структуру приложения, которая более легко поддерживается. Чтобы реализовать эту архитектуру, вы отделяете слой презентации от уровня бизнес-логики (BLL) и уровня доступа к данным (DAL). Одним из способов реализации этой структуры является использование ObjectDataSource элемента управления вместо EntityDataSource элемента управления. При использовании ObjectDataSource элемента управления вы реализуете собственный код доступа к данным, а затем вызываете его на .aspx страницах с помощью элемента управления, имеющего многие из тех же функций, что и другие элементы управления источниками данных. Это позволяет объединить преимущества многоуровневого подхода с преимуществами использования элемента управления Web Forms для доступа к данным.
Кроме того, элемент ObjectDataSource управления обеспечивает большую гибкость и в других отношениях. Поскольку вы пишете собственный код для доступа к данным, вы можете делать больше, чем просто читать, вставлять, обновлять или удалять определенный тип сущности, что являются задачами, для выполнения которых предназначен элемент управления EntityDataSource. Например, при каждом обновлении сущности можно выполнять ведение журнала, архивировать данные при каждом удалении сущности или автоматически проверять и обновлять связанные данные при вставке строки со значением внешнего ключа.
Классы бизнес-логики и репозитория
Элемент ObjectDataSource управления работает путем вызова создаваемого класса. Класс включает методы, которые извлекают и обновляют данные, и вы предоставляете имена этих методов элементу управления в разметке ObjectDataSource . Во время отрисовки или обратной обработки ObjectDataSource вызывает указанные методы.
Помимо основных операций CRUD, класс, который вы создаете для использования с элементом ObjectDataSource управления, может потребоваться выполнить бизнес-логику при ObjectDataSource чтении или обновлении данных. Например, при обновлении отдела может потребоваться проверить, что другие отделы не имеют одного администратора, так как один человек не может быть администратором нескольких отделов.
В некоторых ObjectDataSource документах, таких как обзор класса ObjectDataSource, элемент управления вызывает класс, называемый бизнес-объектом , который включает как бизнес-логику, так и логику доступа к данным. В этом руководстве вы создадите отдельные классы для бизнес-логики и логики доступа к данным. Класс, инкапсулирующий логику доступа к данным, называется репозиторием. Класс бизнес-логики включает как методы бизнес-логики, так и методы доступа к данным, но методы доступа к данным вызывают репозиторий для выполнения задач доступа к данным.
Вы также создадите уровень абстракции между BLL и DAL, который упрощает автоматическое модульное тестирование BLL. Этот уровень абстракции реализуется путем создания интерфейса и использования интерфейса при создании экземпляра репозитория в классе бизнес-логики. Это позволяет предоставить класс бизнес-логики со ссылкой на любой объект, реализующий интерфейс репозитория. Для нормальной работы предоставляется объект репозитория, который работает с Entity Framework. Для тестирования предоставляется объект репозитория, который работает с данными, хранящимися в удобном режиме, например переменными класса, определенными как коллекции.
На следующем рисунке показано различие между классом бизнес-логики, который включает логику доступа к данным без репозитория и один из них, использующий репозиторий.
Сначала создайте веб-страницы, в которых ObjectDataSource элемент управления привязан непосредственно к репозиторию, так как он выполняет только основные задачи доступа к данным. В следующем руководстве вы создадите класс бизнес-логики с логикой проверки и привязываете ObjectDataSource элемент управления к данному классу вместо класса репозитория. Вы также создадите модульные тесты для логики проверки. В третьем руководстве этой серии вы добавите функции сортировки и фильтрации в приложение.
Страницы, которые вы создаете в этом руководстве, работают с Departments набором сущностей модели данных, который вы создали в серии учебников для начинающих.
Обновление базы данных и модели данных
В этом руководстве вы начнете с внесения двух изменений в базу данных, для которых также потребуется внести соответствующие изменения в модель данных, созданную в руководстве Начало работы с Entity Framework и Web Forms. В одном из этих руководств вы внесли изменения в конструктор вручную, чтобы синхронизировать модель данных с базой данных после изменения базы данных. В этом руководстве вы будете использовать инструмент конструктора Update Model From Database для автоматического обновления модели данных.
Добавление связи в базу данных
В Visual Studio откройте веб-приложение Contoso University, созданное в серии руководств по началу работы с Entity Framework и Web Forms , а затем откройте схему SchoolDiagram базы данных.
Если вы посмотрите на таблицу Department на схеме базы данных, вы увидите, что она имеет столбец Administrator. Этот столбец является внешним ключом к Person таблице, но в базе данных не определена связь внешнего ключа. Необходимо создать связь и обновить модель данных, чтобы Entity Framework автоматически обрабатывала эту связь.
На схеме базы данных щелкните таблицу правой Department кнопкой мыши и выберите "Связи".
В поле "Связи внешнего ключа " нажмите кнопку "Добавить", а затем щелкните многоточие для спецификации таблиц и столбцов.
В диалоговом окне "Таблицы и столбцы", задайте таблицу и поле первичного ключа как Person и PersonID, а таблицу и поле внешнего ключа как Department и Administrator. (При выполнении этого имя связи изменится с FK_Department_Department, на FK_Department_Person.)
Нажмите кнопку "ОК " в поле "Таблицы и столбцы ", нажмите кнопку "Закрыть " в поле "Связи внешнего ключа " и сохраните изменения. Если вам будет предложено сохранить Person таблицы и Department таблицы, нажмите кнопку "Да".
Замечание
Если вы удалили Person строки, соответствующие данным, уже имеющимся в столбце Administrator , вы не сможете сохранить это изменение. В этом случае используйте редактор таблиц в обозревателе серверов , чтобы убедиться, что Administrator значение в каждой Department строке содержит идентификатор записи, которая фактически существует в Person таблице.
После сохранения изменения вы не сможете удалить строку из Person таблицы, если этот пользователь является администратором отдела. В рабочем приложении вы предоставите определенное сообщение об ошибке, если ограничение базы данных предотвращает удаление или укажите каскадное удаление. Для примера указания каскадного удаления см. Entity Framework и ASP.NET — Getting Started Part 2.
Добавление представления в базу данных
На новой странице Departments.aspx , которую вы создадите, необходимо указать раскрывающийся список инструкторов с именами в формате last, first, чтобы пользователи могли выбирать администраторов отдела. Чтобы упростить это, вы создадите представление в базе данных. Представление будет состоять только из данных, необходимых в раскрывающемся списке: полное имя (правильно отформатированное) и идентификатор записи.
В обозревателе серверов разверните School.mdf, щелкните правой кнопкой мыши папку "Представления " и выберите "Добавить новое представление".
Нажмите кнопку "Закрыть ", когда появится диалоговое окно "Добавить таблицу " и вставьте следующую инструкцию SQL в область SQL:
SELECT LastName + ',' + FirstName AS FullName, PersonID
FROM dbo.Person
WHERE (HireDate IS NOT NULL)
Сохраните представление как vInstructorName.
Обновление модели данных
В папке DAL откройте файл SchoolModel.edmx , щелкните правой кнопкой мыши область конструктора и выберите "Обновить модель" из базы данных.
В диалоговом окне "Выбор объектов базы данных " выберите вкладку "Добавить " и выберите только что созданное представление.
Нажмите кнопку "Готово".
В конструкторе вы увидите, что средство создало сущность vInstructorName и новую связь между сущностями Department и Person.
Замечание
В окнах "Вывод" и "Список ошибок" может появиться сообщение с предупреждением о том, что средство автоматически создало первичный ключ для нового vInstructorName представления. Это ожидаемое поведение.
Если вы ссылаетесь на новую vInstructorName сущность в коде, вы не хотите использовать соглашение базы данных о префиксе нижнего регистра "v" для него. Таким образом, вы переименуете сущность и набор сущностей в модели.
Откройте браузер моделей. Вы видите, что vInstructorName указан как тип сущности и представление.
В разделе SchoolModel (не SchoolModel.Store), щелкните правой кнопкой мыши vInstructorName и выберите "Свойства". В окне "Свойства " измените свойство Name на "InstructorName" и измените свойство "Имя набора сущностей " на "InstructorNames".
Сохраните и закройте модель данных, а затем перестроите проект.
Использование класса репозитория и элемента управления ObjectDataSource
Создайте файл класса в папке DAL , назовите его SchoolRepository.cs и замените существующий код следующим кодом:
using System;
using System.Collections.Generic;
using System.Linq;
using ContosoUniversity.DAL;
namespace ContosoUniversity.DAL
{
public class SchoolRepository : IDisposable
{
private SchoolEntities context = new SchoolEntities();
public IEnumerable<Department> GetDepartments()
{
return context.Departments.Include("Person").ToList();
}
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
context.Dispose();
}
}
this.disposedValue = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
Этот код предоставляет один GetDepartments метод, который возвращает все сущности в наборе Departments сущностей. Так как вы знаете, что будете получать доступ к свойству Person навигации для каждой возвращаемой строки, необходимо задать принудительную Include загрузку этого свойства с помощью метода. Класс также реализует интерфейс IDisposable, чтобы гарантировать освобождение подключения к базе данных при уничтожении объекта.
Замечание
Распространенная практика заключается в создании класса репозитория для каждого типа сущности. В этом руководстве используется один класс репозитория для нескольких типов сущностей. Дополнительные сведения о шаблоне репозитория см. в блоге команды Entity Framework и блоге Джули Лермана.
Метод GetDepartments возвращает IEnumerable объект, а не IQueryable объект, чтобы убедиться, что возвращаемая коллекция доступна даже после удаления самого объекта репозитория.
IQueryable Объект может выполнять доступ к базе данных каждый раз, когда к нему обращаются, но объект репозитория может быть удалён до того, как элемент управления привязанных данных попытается отобразить данные. Можно вернуть другой тип коллекции, например IList объект вместо IEnumerable объекта. Однако возврат IEnumerable объекта гарантирует, что вы можете выполнять типичные задачи обработки списков только для чтения, такие как foreach циклы и запросы LINQ, но нельзя добавлять или удалять элементы в коллекции, что может означать, что такие изменения будут сохранены в базе данных.
Создайте страницу Departments.aspx , использующую главную страницу Site.Master , и добавьте следующую разметку в Content элемент управления с именем Content2:
<h2>Departments</h2>
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments" >
</asp:ObjectDataSource>
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" >
<Columns>
<asp:CommandField ShowEditButton="True" ShowDeleteButton="True"
ItemStyle-VerticalAlign="Top">
</asp:CommandField>
<asp:DynamicField DataField="Name" HeaderText="Name" SortExpression="Name" ItemStyle-VerticalAlign="Top" />
<asp:DynamicField DataField="Budget" HeaderText="Budget" SortExpression="Budget" ItemStyle-VerticalAlign="Top" />
<asp:DynamicField DataField="StartDate" HeaderText="Start Date" ItemStyle-VerticalAlign="Top" />
<asp:TemplateField HeaderText="Administrator" SortExpression="Person.LastName" ItemStyle-VerticalAlign="Top" >
<ItemTemplate>
<asp:Label ID="AdministratorLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>'></asp:Label>,
<asp:Label ID="AdministratorFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Эта разметка создает ObjectDataSource элемент управления, использующий только что созданный класс репозитория, и GridView элемент управления для отображения данных. Элемент GridView управления задает команды "Изменить " и "Удалить ", но вы еще не добавили код для их поддержки.
Несколько столбцов используют DynamicField элементы управления, чтобы воспользоваться преимуществами автоматического форматирования и проверки данных. Для работы этих методов необходимо вызвать EnableDynamicData метод в обработчике Page_Init событий. (DynamicControl элементы управления не используются в Administrator поле, так как они не работают с свойствами навигации.)
Атрибуты Vertical-Align="Top" становятся важными позже при добавлении столбца с вложенным GridView элементом управления в сетку.
Откройте файл Departments.aspx.cs и добавьте следующую using инструкцию:
using ContosoUniversity.DAL;
Затем добавьте следующий обработчик для события страницы Init :
protected void Page_Init(object sender, EventArgs e)
{
DepartmentsGridView.EnableDynamicData(typeof(Department));
}
В папке DAL создайте файл класса с именем Department.cs и замените существующий код следующим кодом:
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.DAL
{
[MetadataType(typeof(DepartmentMetaData))]
public partial class Department
{
}
public class DepartmentMetaData
{
[DataType(DataType.Currency)]
[Range(0, 1000000, ErrorMessage = "Budget must be less than $1,000,000.00")]
public Decimal Budget { get; set; }
[DisplayFormat(DataFormatString="{0:d}",ApplyFormatInEditMode=true)]
public DateTime StartDate { get; set; }
}
}
Этот код добавляет метаданные в модель данных. Он указывает, что свойство Budget сущности Department фактически представляет валюту, хотя его тип данных — Decimal, и указывает, что значение должно быть от 0 до $1 000 000,00. Он также указывает, что StartDate свойство должно быть отформатировано как дата в формате мм/дд/гггг.
Запустите страницу Departments.aspx .
Обратите внимание, что, несмотря на отсутствие строки формата в разметке страницы Departments.aspx для столбцов "Бюджет" и "Дата начала", к ним было применено стандартное форматирование валюты и даты средствами элемента управления DynamicField, с использованием метаданных, предоставленных в файле Department.cs.
Добавление функций вставки и удаления
Откройте SchoolRepository.cs, добавьте следующий код, чтобы создать Insert метод и Delete метод. Код также содержит метод с именем GenerateDepartmentID , который вычисляет следующее доступное значение ключа записи для использования методом Insert . Это необходимо, так как база данных не настроена для автоматического выполнения вычисления для таблицы Department.
public void InsertDepartment(Department department)
{
try
{
department.DepartmentID = GenerateDepartmentID();
context.Departments.AddObject(department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
public void DeleteDepartment(Department department)
{
try
{
context.Departments.Attach(department);
context.Departments.DeleteObject(department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
private Int32 GenerateDepartmentID()
{
Int32 maxDepartmentID = 0;
var department = (from d in GetDepartments()
orderby d.DepartmentID descending
select d).FirstOrDefault();
if (department != null)
{
maxDepartmentID = department.DepartmentID + 1;
}
return maxDepartmentID;
}
Метод Attach
Метод DeleteDepartment вызывает метод Attach, чтобы повторно установить ссылку, которая хранится в диспетчере состояния в контексте объекта между сущностью в памяти и строкой базы данных, которую она представляет. Это должно произойти перед вызовом SaveChanges метода.
Термин контекст объекта обозначает класс Entity Framework, производный от класса ObjectContext, который используется для доступа к наборам сущностей и самим сущностям. В коде этого проекта класс называется SchoolEntities, а экземпляр этого проекта всегда называется context.
Диспетчер состояний объекта контекста объекта — это класс, производный от ObjectStateManager класса. Контакт объекта использует диспетчер состояний объекта для хранения объектов сущностей и отслеживания того, синхронизирован ли каждый объект с соответствующей строкой таблицы или строками в базе данных.
При чтении сущности контекст объекта сохраняет его в диспетчере состояний объекта и отслеживает, синхронизировано ли представление объекта с базой данных. Например, если изменить значение свойства, флаг задается, чтобы указать, что измененное свойство больше не синхронизировано с базой данных. Затем при вызове SaveChanges метода контекст объекта знает, что делать в базе данных, так как диспетчер состояний объекта точно знает, что отличается от текущего состояния сущности и состояния базы данных.
Однако этот процесс обычно не работает в веб-приложении, так как экземпляр контекста объекта, который считывает сущность, а также все в диспетчере состояний объекта, удаляется после отрисовки страницы. Экземпляр контекста объекта, который должен применять изменения, является новым и создаётся специально для обработки обратных вызовов. В случае DeleteDepartment метода ObjectDataSource элемент управления повторно создает исходную версию сущности для вас на основе значений из состояния представления, но эта повторно созданная Department сущность не существует в диспетчере состояний объекта. Если вы вызвали метод для DeleteObject этой повторно созданной сущности, вызов завершится ошибкой, так как контекст объекта не знает, синхронизирована ли сущность с базой данных. Однако вызов Attach метода повторно устанавливает то же отслеживание между повторно созданной сущностью и значениями в базе данных, которая изначально была выполнена автоматически при чтении сущности в предыдущем экземпляре контекста объекта.
Иногда не требуется, чтобы контекст объекта отслеживал сущности в диспетчере состояний объектов, и вы можете задать флаги, чтобы предотвратить это. Примеры этого показаны в последующих руководствах в этой серии.
Метод SaveChanges
Этот простой класс репозитория иллюстрирует основные принципы выполнения операций CRUD. В этом примере SaveChanges метод вызывается сразу после каждого обновления. В рабочем приложении может потребоваться вызвать SaveChanges метод из отдельного метода, чтобы обеспечить более широкий контроль над обновлением базы данных. (В конце следующего учебного пособия вы найдете ссылку на технический документ, который обсуждает шаблон "единица работы", являющийся одним из подходов к координации связанных обновлений.) Обратите внимание, что в примере метод DeleteDepartment не содержит кода для обработки конфликтов многопоточности; код для этого будет добавлен в следующем руководстве этой серии.
Получение имен инструкторов для выбора при вставке
Пользователи должны иметь возможность выбрать администратора из списка инструкторов в раскрывающемся списке при создании новых отделов. Поэтому добавьте следующий код в SchoolRepository.cs , чтобы создать метод для получения списка инструкторов с помощью созданного ранее представления:
public IEnumerable<InstructorName> GetInstructorNames()
{
return context.InstructorNames.OrderBy("it.FullName").ToList();
}
Создание страницы для вставки отделов
Создайте страницу DepartmentsAdd.aspx , использующую страницу Site.Master , и добавьте следующую разметку в Content элемент управления с именем Content2:
<h2>Departments</h2>
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository" DataObjectTypeName="ContosoUniversity.DAL.Department"
InsertMethod="InsertDepartment" >
</asp:ObjectDataSource>
<asp:DetailsView ID="DepartmentsDetailsView" runat="server"
DataSourceID="DepartmentsObjectDataSource" AutoGenerateRows="False"
DefaultMode="Insert" OnItemInserting="DepartmentsDetailsView_ItemInserting">
<Fields>
<asp:DynamicField DataField="Name" HeaderText="Name" />
<asp:DynamicField DataField="Budget" HeaderText="Budget" />
<asp:DynamicField DataField="StartDate" HeaderText="Start Date" />
<asp:TemplateField HeaderText="Administrator">
<InsertItemTemplate>
<asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
SelectMethod="GetInstructorNames" >
</asp:ObjectDataSource>
<asp:DropDownList ID="InstructorsDropDownList" runat="server"
DataSourceID="InstructorsObjectDataSource"
DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init">
</asp:DropDownList>
</InsertItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
<asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
Эта разметка создает два ObjectDataSource элемента управления, один для вставки новых Department сущностей и один для получения имен инструкторов для DropDownList элемента управления, используемого для выбора администраторов отдела. Разметка создает DetailsView элемент управления для ввода новых отделов и задает обработчик события элемента управления ItemInserting , чтобы задать Administrator значение внешнего ключа. В конце находится ValidationSummary элемент управления для отображения сообщений об ошибках.
Откройте DepartmentsAdd.aspx.cs и добавьте следующую using инструкцию:
using ContosoUniversity.DAL;
Добавьте следующую переменную класса и методы:
private DropDownList administratorsDropDownList;
protected void Page_Init(object sender, EventArgs e)
{
DepartmentsDetailsView.EnableDynamicData(typeof(Department));
}
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
administratorsDropDownList = sender as DropDownList;
}
protected void DepartmentsDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
e.Values["Administrator"] = administratorsDropDownList.SelectedValue;
}
Этот Page_Init метод включает функциональные возможности динамических данных. Обработчик DropDownList события элемента управления Init сохраняет ссылку на элемент управления, а обработчик события элемента управления DetailsView использует такую ссылку для Inserting получения PersonID значения выбранного инструктора и обновления Administrator свойства внешнего ключа сущностиDepartment.
Запустите страницу, добавьте сведения для нового отдела и щелкните ссылку "Вставить ".
Введите значения для другого нового отдела. Введите число больше 100 000 000,00 в поле "Бюджет " и перейдите к следующему полю. Звездочка отображается в поле, а если указатель мыши на него удерживается, вы увидите сообщение об ошибке, введенное в метаданные для этого поля.
Нажмите кнопку "Вставить" и отображается сообщение об ошибке, отображаемое ValidationSummary элементом управления в нижней части страницы.
Затем закройте браузер и откройте страницу Departments.aspx . Добавьте возможность удаления на страницу Departments.aspx путем добавления DeleteMethod атрибута в ObjectDataSource элемент управления и DataKeyNames атрибута в GridView элемент управления. Открывающие теги для этих элементов управления теперь будут выглядеть следующим образом:
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments"
DeleteMethod="DeleteDepartment" >
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID" >
Запустите страницу.
Удалите отдел, добавленный при запуске страницы DepartmentsAdd.aspx .
Добавление функций обновления
Откройте SchoolRepository.cs и добавьте следующий Update метод:
public void UpdateDepartment(Department department, Department origDepartment)
{
try
{
context.Departments.Attach(origDepartment);
context.ApplyCurrentValues("Departments", department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
При нажатии кнопки "Обновить" на странице Departments.aspx, элемент управления ObjectDataSource создает две Department сущности для передачи в метод UpdateDepartment. Один содержит исходные значения, хранящиеся в состоянии просмотра, а другой — новые значения, введенные в управляющий элемент GridView. Код в методе UpdateDepartment передает сущность Department, содержащую исходные значения, методу Attach, чтобы установить отслеживание между этой сущностью и данными в базе данных. Затем код передает Department сущность с новыми значениями в ApplyCurrentValues метод. Контекст объекта сравнивает старые и новые значения. Если новое значение отличается от старого значения, контекст объекта изменяет значение свойства. Затем SaveChanges метод обновляет только измененные столбцы в базе данных. (Однако если функция обновления для этой сущности сопоставлена с хранимой процедурой, все строки будут обновлены независимо от того, какие столбцы были изменены.)
Откройте файл Departments.aspx и добавьте в элемент управления следующие атрибуты DepartmentsObjectDataSource :
UpdateMethod="UpdateDepartment"ConflictDetection="CompareAllValues"
Это приводит к тому, что старые значения хранятся в состоянии представления, чтобы их можно было сравнить с новыми значениями в методеUpdate.OldValuesParameterFormatString="orig{0}"
Это сообщает элементу управления, что имя исходного параметра значений —origDepartment.
Разметка для открывающего тега ObjectDataSource элемента управления теперь похожа на следующий пример:
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments" DeleteMethod="DeleteDepartment"
UpdateMethod="UpdateDepartment"
ConflictDetection="CompareAllValues"
OldValuesParameterFormatString="orig{0}" >
Добавьте атрибут OnRowUpdating="DepartmentsGridView_RowUpdating" к элементу управления GridView. Вы будете использовать это, чтобы задать значение свойства Administrator, основываясь на строке, выбранной пользователем в раскрывающемся списке. Открывающий GridView тег теперь похож на следующий пример:
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID"
OnRowUpdating="DepartmentsGridView_RowUpdating">
Добавьте контроль EditItemTemplate для столбца Administrator в контроль GridView, сразу после контрола ItemTemplate для этого столбца.
<EditItemTemplate>
<asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server" DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
SelectMethod="GetInstructorNames" TypeName="ContosoUniversity.DAL.SchoolRepository">
</asp:ObjectDataSource>
<asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsObjectDataSource"
SelectedValue='<%# Eval("Administrator") %>'
DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init" >
</asp:DropDownList>
</EditItemTemplate>
Этот EditItemTemplate элемент управления аналогичен InsertItemTemplate элементу управления на странице DepartmentsAdd.aspx . Разница заключается в том, что начальное значение элемента управления задается с помощью атрибута SelectedValue .
Перед элементом управления GridView добавьте элемент управления ValidationSummary, как на странице DepartmentsAdd.aspx.
<asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
Откройте Departments.aspx.cs и сразу после объявления частичного класса добавьте следующий код, чтобы создать частное поле для ссылки на DropDownList элемент управления:
private DropDownList administratorsDropDownList;
Затем добавьте обработчики события для DropDownList элемента управления Init и для GridView элемента управления RowUpdating.
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
administratorsDropDownList = sender as DropDownList;
}
protected void DepartmentsGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
e.NewValues["Administrator"] = administratorsDropDownList.SelectedValue;
}
Обработчик Init события сохраняет ссылку на DropDownList элемент управления в поле класса. Обработчик события RowUpdating использует ссылку, чтобы получить введенное пользователем значение и применить его к свойству Administrator сущности Department.
Используйте страницу DepartmentsAdd.aspx для добавления нового отдела, а затем запустите страницу Departments.aspx и нажмите кнопку "Изменить " в добавленной строке.
Замечание
Вы не сможете редактировать строки, которые вы не добавили (т. е. которые уже были в базе данных), из-за недопустимых данных в базе данных; Администраторы строк, созданных с базой данных, являются учащимися. При попытке изменить один из них вы получите страницу ошибок, которая сообщает об ошибке, например 'InstructorsDropDownList' has a SelectedValue which is invalid because it does not exist in the list of items.
Если ввести недопустимую сумму бюджета , а затем нажмите кнопку "Обновить", вы увидите тот же звездочку и сообщение об ошибке, которое вы видели на странице Departments.aspx .
Измените значение поля или выберите другого администратора и нажмите кнопку "Обновить". Отображается изменение.
Это завершает введение в использование элемента управления ObjectDataSource для выполнения базовых операций CRUD (создание, чтение, обновление, удаление) с Entity Framework. Вы создали простое n-уровневое приложение, но уровень бизнес-логики по-прежнему тесно связан с уровнем доступа к данным, что усложняет автоматизированное модульное тестирование. В следующем руководстве вы узнаете, как реализовать шаблон репозитория для упрощения модульного тестирования.