Поделиться через


Обновление адаптера таблицы TableAdapter для использования JOIN (C#)

Скотт Митчелл

Скачивание PDF

При работе с базой данных обычно запрашивать данные, распределенные по нескольким таблицам. Чтобы получить данные из двух разных таблиц, можно использовать либо коррелированные вложенные запросы, либо операцию JOIN. В этом руководстве мы сравниваем коррелированные вложенные запросы и синтаксис JOIN, прежде чем узнать, как создать TableAdapter, включающий JOIN в его основной запрос.

Введение

С реляционными базами данных данные, с которыми мы заинтересованы в работе, часто распределяются по нескольким таблицам. Например, при отображении сведений о продукте мы, скорее всего, хотим вывести список соответствующих категорий и имен поставщиков каждого продукта. Таблица Products содержит CategoryID и SupplierID значения, но фактические имена категорий и поставщиков находятся в таблицах Categories и Suppliers соответственно.

Чтобы получить информацию из другой связанной таблицы, можно использовать сопоставленные вложенные запросы или JOINs. Коррелированный подзапрос — это вложенный SELECT запрос, ссылающийся на столбцы во внешнем запросе. Например, в руководстве «Создание уровня доступа к данным» мы использовали два коррелированных подзапроса в основном запросе ProductsTableAdapter, чтобы вернуть названия категорий и имен поставщиков для каждого продукта. Это JOIN конструкция SQL, которая объединяет связанные строки из двух разных таблиц. Мы использовали JOIN в руководстве Запрос данных с элементом управления SqlDataSource для отображения сведений о категориях вместе с каждым товаром.

Причина, по которой мы воздержались от использования тегов JOIN с TableAdapters, заключается в ограничениях мастера TableAdapters на автоматическое создание соответствующих инструкций INSERT, UPDATE и DELETE. В частности, если основной запрос TableAdapter содержит любые JOIN's, то TableAdapter не может автоматически создавать нерегламентированные инструкции SQL или хранимые процедуры для его свойств InsertCommand, UpdateCommand и DeleteCommand.

В этом руководстве мы кратко сравним и противопоставим коррелированные подзапросы и JOIN перед тем, как изучить, как создать TableAdapter, который включает JOIN в свой основной запрос.

Сравнение и противопоставление коррелированных вложенных запросов иJOIN s

Помните, что ProductsTableAdapter, созданный в первом руководстве в Northwind Наборе данных, использует коррелированные вложенные запросы для возвращения соответствующей категории и названия поставщика для каждого продукта. Ниже показан основной ProductsTableAdapter запрос.

SELECT ProductID, ProductName, SupplierID, CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = 
            Products.CategoryID) as CategoryName, 
       (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = 
            Products.SupplierID) as SupplierName
FROM Products

Два коррелированных вложенных запроса — (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) и (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) — представляют собой SELECT запросы, возвращающие одно значение для каждого продукта в качестве дополнительного столбца в списке столбцов внешней SELECT инструкции.

Кроме того, JOIN можно использовать для возврата имени поставщика и категории каждого продукта. Следующий запрос возвращает те же выходные данные, что и приведенный выше, но использует JOIN s вместо вложенных запросов:

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

Объединяет JOIN записи из одной таблицы с записями из другой таблицы на основе некоторых критериев. Например, LEFT JOIN Categories ON Categories.CategoryID = Products.CategoryID в приведенном выше запросе SQL Server указывает SQL Server объединить каждую запись продукта с записью категории, значение которой CategoryID соответствует значению CategoryID продукта. Объединенный результат позволяет работать с соответствующими полями категорий для каждого продукта (например CategoryName, ).

Замечание

JOIN часто используются для запросов данных из реляционных баз данных. Если вы не знакомы с JOIN синтаксисом или вам нужно немного приступить к его использованию, я бы рекомендовал руководство по присоединению к SQL в Школах W3. Кроме того, стоит ознакомиться с JOIN разделами "Основы " и "Основы субзапроса " в электронной документации ПО SQL.

Так как и JOIN вложенные запросы, и связанные подзапросы могут использоваться для получения соответствующих данных из других таблиц, многие разработчики ломают голову и задаются вопросом, какой подход выбрать. Все гуру SQL, с которыми я разговаривал, говорили примерно одно и то же, что это не особенно влияет на производительность, так как SQL Server создаёт примерно одинаковые планы выполнения. Их совет заключается в том, чтобы использовать технику, с которой вы и ваша команда чувствуете себя наиболее комфортно. Стоит отметить, что после того, как дают этот совет, эти эксперты немедленно выражают свое предпочтение JOIN по сравнению с коррелированными вложенными запросами.

При создании уровня доступа к данным с помощью типизированных наборов данных средства лучше работают при использовании вложенных запросов. В частности, мастер TableAdapter не будет автоматически создавать соответствующие инструкции INSERT, UPDATE и операторы DELETE, если основной запрос содержит какие-либо JOIN, но автоматически создает их при использовании сопоставленных вложенных запросов.

Чтобы изучить этот недостаток, создайте временный типизированный набор данных в папке ~/App_Code/DAL . В мастере настройки TableAdapter выберите использование нерегламентированных инструкций SQL и введите следующий SELECT запрос (см. рис. 1).

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

Снимок экрана: окно мастера настройки TableAdaptor с введенным запросом, содержащим joIN.

Рис. 1. Введите основной запрос, содержащий JOIN s (щелкните, чтобы просмотреть изображение полного размера)

По умолчанию TableAdapter автоматически создает INSERT, UPDATE операторы и DELETE инструкции на основе основного запроса. Если нажать кнопку "Дополнительно", вы увидите, что эта функция включена. Несмотря на этот параметр, TableAdapter не сможет создать операторы INSERT, UPDATE и DELETE, так как основной запрос содержит JOIN.

Снимок экрана: окно

Рис. 2. Введите основной запрос, содержащий JOIN s

Нажмите кнопку "Готово", чтобы завершить работу мастера. На этом этапе Конструктор DataSet будет включать один TableAdapter с DataTable, содержащей столбцы для каждого из полей, возвращаемых в списке столбцов запроса SELECT. Это включает в себя CategoryName и SupplierName, как показано на рисунке 3.

DataTable содержит столбец для каждого поля, возвращаемого в списке столбцов.

Рис. 3. Таблица данных содержит столбец для каждого поля, возвращаемого в списке столбцов.

Хотя DataTable имеет нужные столбцы, TableAdapter не имеет значений для своих свойств InsertCommand, UpdateCommand и DeleteCommand. Чтобы подтвердить это, щелкните TableAdapter в конструкторе и перейдите в окно "Свойства". Там вы увидите, что свойства InsertCommand, UpdateCommand и DeleteCommand установлены на (None).

Свойства InsertCommand, UpdateCommand и DeleteCommand имеют значение (None)

Рис. 4. Для свойств InsertCommand, UpdateCommand, и DeleteCommand задано значение (Нет) (Щелкните здесь, чтобы просмотреть изображение в полном размере)

Чтобы обойти этот недостаток, мы можем вручную указать инструкции и параметры SQL для InsertCommand объекта, UpdateCommand и DeleteCommand свойства через окно свойств. Кроме того, мы могли бы начать с настройки основного запроса TableAdapter, чтобы не включать ни один JOIN. Это позволит INSERT, UPDATE и DELETE автоматически создавать инструкции для нас. После завершения работы мастера, мы могли бы затем вручную обновить TableAdapter в SelectCommand окне свойств, чтобы он содержал JOIN синтаксис.

Хотя этот подход работает, он очень нестабилен при использовании нерегламентированных запросов SQL, потому что каждый раз, когда основной запрос TableAdapter перенастраивается через мастер, автоматически созданные инструкции INSERT, UPDATE и DELETE создаются повторно. Это означает, что все настройки, которые мы сделали позже, будут потеряны, если щелкнуть правой кнопкой мыши по TableAdapter, выбрать "Настроить" в контекстном меню и снова завершить мастер.

Хрупкость автоматически созданных INSERT TableAdapter, UPDATE, и DELETE инструкций, к счастью, ограничена неформальными SQL инструкциями. Если ваш TableAdapter использует хранимые процедуры, вы можете настроить хранимые процедуры SelectCommand, InsertCommand, UpdateCommand и DeleteCommand, а затем повторно запустить мастер конфигурации TableAdapter, не опасаясь, что хранимые процедуры будут изменены.

На следующих нескольких шагах мы создадим TableAdapter, который изначально использует основной запрос, пропускающий любые JOIN, чтобы соответствующие хранимые процедуры вставки, обновления и удаления были автоматически созданы. Затем мы обновим SelectCommand так, чтобы он использовал JOIN, который возвращает дополнительные столбцы из связанных таблиц. Наконец, мы создадим соответствующий класс уровня бизнес-логики и продемонстрировать использование TableAdapter на веб-странице ASP.NET.

Шаг 1. Создание tableAdapter с помощью упрощенного основного запроса

В этом руководстве мы добавим элементы TableAdapter и строго типизированный элемент DataTable для таблицы Employees в NorthwindWithSprocs Наборе данных. Таблица Employees содержит ReportsTo поле, указывающее EmployeeID руководителя сотрудника. Например, сотрудница Энн Додсворт имеет значение ReportTo 5, что является значением EmployeeID Стивена Бьюкенена. Таким образом, Энн сообщает Стивену, её менеджеру. Вместе со сведениями о значении каждого сотрудника ReportsTo может быть полезно также узнать имя его руководителя. Это можно сделать с помощью JOIN. Однако использование JOIN при первоначальном создании TableAdapter мешает мастеру автоматически создавать соответствующие возможности вставки, обновления и удаления. Поэтому мы начнем с создания TableAdapter, основной запрос которого не содержит никаких JOIN s. Затем на втором шаге мы обновим основную процедуру хранимого запроса, чтобы получить имя руководителя с помощью JOIN.

Начните с открытия NorthwindWithSprocs набора данных в папке ~/App_Code/DAL . Щелкните правой кнопкой мыши на Конструкторе, выберите опцию "Добавить" в контекстном меню, а затем пункт меню TableAdapter. Откроется мастер настройки TableAdapter. Как показано на рисунке 5, создайте новые хранимые процедуры с помощью мастера, затем нажмите кнопку "Далее". Чтобы освежить знания о создании новых хранимых процедур с помощью мастера TableAdapter, ознакомьтесь с руководством по созданию новых хранимых процедур для TableAdapter типизированного DataSet.

Выберите параметр

Рис. 5. Выберите параметр "Создать новые хранимые процедуры" (щелкните, чтобы просмотреть изображение полного размера)

Используйте следующую SELECT инструкцию для основного запроса TableAdapter:

SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country
FROM Employees

Так как этот запрос не содержит JOIN, мастер TableAdapter автоматически создаст хранимые процедуры с соответствующими операторами INSERT, UPDATE и DELETE, а также хранимую процедуру для выполнения основного запроса.

На следующем шаге мы назовем хранимые процедуры TableAdapter. Используйте именаEmployees_Select, Employees_InsertEmployees_UpdateиEmployees_Delete, как показано на рис. 6.

Имя хранимых процедур TableAdapter

Рис. 6. Назовите хранимые процедуры TableAdapter (щелкните, чтобы просмотреть изображение полного размера)

Последний шаг предложит нам назвать методы TableAdapter. Используйте Fill и GetEmployees в качестве имен методов. Также не забудьте оставить флажок "Создать методы" для отправки обновлений непосредственно в базу данных (GenerateDBDirectMethods).

Назовите методы TableAdapter Fill и GetEmployees

Рис. 7. Назовите методы Fill TableAdapter и GetEmployees (Щелкните, чтобы просмотреть изображение полного размера)

Завершив работу мастера, ознакомьтесь с хранимыми процедурами в базе данных. Вы должны увидеть четыре новых: Employees_Select, Employees_Insert, Employees_Updateи Employees_Delete. Затем проверьте только что созданные EmployeesDataTable и EmployeesTableAdapter. DataTable содержит столбец для каждого поля, возвращаемого основным запросом. Щелкните tableAdapter и перейдите в окно "Свойства". Там вы увидите, что свойства InsertCommand, UpdateCommand и DeleteCommand правильно настроены для вызова соответствующих хранимых процедур.

TableAdapter включает возможности вставки, обновления и удаления

Рис. 8. TableAdapter включает возможности вставки, обновления и удаления (щелкните здесь, чтобы просмотреть изображение в полном размере)

При автоматическом создании хранимых процедур для вставки, обновления и удаления, а также при правильной настройке свойств InsertCommand, UpdateCommand и DeleteCommand, мы готовы настроить хранимую процедуру SelectCommand, чтобы возвращать дополнительные сведения о менеджере каждого сотрудника. В частности, необходимо обновить Employees_Select хранимую процедуру, чтобы использовать JOIN и возвращать значения менеджера: FirstName и LastName. После того как хранимая процедура будет обновлена, нам потребуется обновить DataTable, чтобы он включал эти дополнительные столбцы. Мы рассмотрим эти две задачи в шагах 2 и 3.

Шаг 2. Настройка хранимой процедуры для того, чтобы включитьJOIN

Начните, перейдя в обозреватель серверов, развернув папку хранимых процедур базы данных Northwind и открыв хранимую процедуру Employees_Select . Если эта хранимая процедура не отображается, щелкните правой кнопкой мыши папку хранимых процедур и выберите "Обновить". Обновите хранимую процедуру, чтобы она использовала LEFT JOIN для возврата имени и фамилии руководителя.

SELECT Employees.EmployeeID, Employees.LastName, 
       Employees.FirstName, Employees.Title, 
       Employees.HireDate, Employees.ReportsTo, 
       Employees.Country,
       Manager.FirstName as ManagerFirstName, 
       Manager.LastName as ManagerLastName
FROM Employees
    LEFT JOIN Employees AS Manager ON
        Employees.ReportsTo = Manager.EmployeeID

После обновления инструкции SELECT сохраните изменения, перейдя в меню "Файл" и выбрав "Сохранить Employees_Select". Кроме того, можно щелкнуть значок "Сохранить" на панели инструментов или нажать клавиши CTRL+S. После сохранения изменений щелкните правой кнопкой мыши Employees_Select хранимую процедуру в обозревателе серверов и выберите "Выполнить". При этом выполняется хранимая процедура и отображаются результаты в окне вывода (см. рис. 9).

Результаты хранимых процедур отображаются в окне вывода

Рис. 9. Результаты хранимых процедур отображаются в окне вывода (щелкните, чтобы просмотреть изображение полного размера)

Шаг 3. Обновление столбцов DataTable

На этом этапе процедура хранимая Employees_Select возвращает значения ManagerFirstName и ManagerLastName, но в EmployeesDataTable отсутствуют столбцы. Эти отсутствующие столбцы можно добавить в DataTable одним из двух способов:

  • Вручную щелкните правой кнопкой мыши dataTable в конструкторе наборов данных и в меню "Добавить" выберите столбец. Затем можно присвоить столбцу имя и задать его свойства соответствующим образом.
  • Автоматически — мастер настройки TableAdapter обновит столбцы DataTable, чтобы отразить поля, возвращаемые хранимой SelectCommand процедурой. При использовании нерегламентированных инструкций SQL мастер также удаляет свойства InsertCommand, UpdateCommand и DeleteCommand, так как теперь SelectCommand содержит объект JOIN. Но при использовании хранимых процедур эти свойства команд остаются неизменными.

Мы изучили вручную добавление столбцов DataTable в предыдущих руководствах, включая master/Details Using a Bulleted List of Master Records with a Details DataList and Uploading Files, и мы рассмотрим этот процесс еще раз в следующем руководстве. Однако в этом руководстве мы будем использовать автоматический подход с помощью мастера настройки TableAdapter.

Начните, щелкнув EmployeesTableAdapter правой кнопкой мыши и выбрав "Настроить" в контекстном меню. Откроется мастер настройки TableAdapter, в котором перечислены хранимые процедуры, используемые для выбора, вставки, обновления и удаления, а также их возвращаемых значений и параметров (при наличии). На рисунке 10 показан этот мастер. Здесь мы видим, что Employees_Select хранимая процедура теперь возвращает ManagerFirstName и ManagerLastName поля.

Помощник показывает обновленный список столбцов для хранимой процедуры Employees_Select

Рис. 10. Мастер отображает обновленный список столбцов для Employees_Select хранимой процедуры (щелкните, чтобы просмотреть изображение полного размера)

Завершите работу мастера, нажав кнопку "Завершить". После возвращения в конструктор наборов данных EmployeesDataTable включает два дополнительных столбца: ManagerFirstName и ManagerLastName.

EmployeesDataTable содержит два новых столбца

Рис. 11. Содержит EmployeesDataTable два новых столбца (щелкните, чтобы просмотреть изображение полного размера)

Чтобы показать, что обновленная хранимая процедура Employees_Select действует и что возможности вставки, обновления и удаления TableAdapter по-прежнему работают, создадим веб-страницу, которая позволит пользователям просматривать и удалять сотрудников. Прежде чем создавать такую страницу, необходимо сначала создать новый класс на уровне бизнес-логики для работы с сотрудниками из NorthwindWithSprocs набора данных. На шаге 4 мы создадим EmployeesBLLWithSprocs класс. На шаге 5 мы будем использовать этот класс на странице ASP.NET.

Шаг 4. Реализация уровня бизнес-логики

Создайте файл класса в папке ~/App_Code/BLL с именем EmployeesBLLWithSprocs.cs. Этот класс имитирует семантику существующего EmployeesBLL класса, только этот новый предоставляет меньше методов и использует NorthwindWithSprocs Набор данных (вместо Northwind Набора данных). Добавьте в класс EmployeesBLLWithSprocs приведенный далее код.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindWithSprocsTableAdapters;
[System.ComponentModel.DataObject]
public class EmployeesBLLWithSprocs
{
    private EmployeesTableAdapter _employeesAdapter = null;
    protected EmployeesTableAdapter Adapter
    {
        get
        {
            if (_employeesAdapter == null)
                _employeesAdapter = new EmployeesTableAdapter();
            return _employeesAdapter;
        }
    }
    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, true)]
    public NorthwindWithSprocs.EmployeesDataTable GetEmployees()
    {
        return Adapter.GetEmployees();
    }
    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Delete, true)]
    public bool DeleteEmployee(int employeeID)
    {
        int rowsAffected = Adapter.Delete(employeeID);
        // Return true if precisely one row was deleted, otherwise false
        return rowsAffected == 1;
    }
}

Свойство EmployeesBLLWithSprocs класса Adapter возвращает экземпляр NorthwindWithSprocs набора данных EmployeesTableAdapter. Это используется методами класса GetEmployees и DeleteEmployee. Метод GetEmployees вызывает соответствующий EmployeesTableAdapter метод GetEmployees, который вызывает хранимую процедуру Employees_Select и заполняет результаты в EmployeeDataTable. Метод DeleteEmployee аналогично вызывает EmployeesTableAdapter метод s Delete , который вызывает хранимую процедуру Employees_Delete .

Шаг 5. Работа с данными на уровне презентации

EmployeesBLLWithSprocs После завершения класса мы готовы работать с данными сотрудников с помощью страницы ASP.NET. Откройте страницу JOINs.aspx в папке AdvancedDAL и перетащите GridView из панели элементов в конструктор, присвоив свойству ID значение Employees. Затем из смарт-тега GridView привязать сетку к новому элементу управления ObjectDataSource с именем EmployeesDataSource.

Настройте ObjectDataSource для использования класса EmployeesBLLWithSprocs, и на вкладках SELECT и DELETE, убедитесь, что методы GetEmployees и DeleteEmployee выбраны из раскрывающихся списков. Нажмите кнопку "Готово", чтобы завершить настройку ObjectDataSource.

Настройка ObjectDataSource для использования класса EmployeesBLLWithSprocs

Рис. 12. Настройка ObjectDataSource для использования EmployeesBLLWithSprocs класса (щелкните, чтобы просмотреть изображение полного размера)

Настройте ObjectDataSource для использования методов GetEmployees и DeleteEmployee

Рис. 13: Использование ObjectDataSource, используя методы GetEmployees и DeleteEmployee (нажмите, чтобы просмотреть изображение полного размера)

Visual Studio добавит BoundField в GridView для каждого столбца EmployeesDataTable . Удалите все эти поля BoundFields, за исключением Title, LastName, FirstName, ManagerFirstName, и переименуйте свойства ManagerLastName и HeaderText последних четырех BoundFields на "Фамилия", "Имя", "Имя менеджера" и "Фамилия менеджера" соответственно.

Чтобы разрешить пользователям удалять сотрудников на этой странице, необходимо выполнить две действия. Во-первых, настройте GridView, чтобы предоставить возможность удаления, выбрав параметр "Включить возможность удаления" из его смарт-тега. Во-вторых, измените свойство ObjectDataSource из значения, заданного мастером ObjectDataSource OldValuesParameterFormatString (original_{0}) на значение по умолчанию ({0}). После внесения этих изменений декларативная разметка GridView и ObjectDataSource должны выглядеть следующим образом:

<asp:GridView ID="Employees" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="EmployeeID" DataSourceID="EmployeesDataSource">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        <asp:BoundField DataField="Title" 
            HeaderText="Title" 
            SortExpression="Title" />
        <asp:BoundField DataField="LastName" 
            HeaderText="Last Name" 
            SortExpression="LastName" />
        <asp:BoundField DataField="FirstName" 
            HeaderText="First Name" 
            SortExpression="FirstName" />
        <asp:BoundField DataField="ManagerFirstName" 
            HeaderText="Manager's First Name" 
            SortExpression="ManagerFirstName" />
        <asp:BoundField DataField="ManagerLastName" 
            HeaderText="Manager's Last Name" 
            SortExpression="ManagerLastName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="EmployeesDataSource" runat="server" 
    DeleteMethod="DeleteEmployee" OldValuesParameterFormatString="{0}" 
    SelectMethod="GetEmployees" TypeName="EmployeesBLLWithSprocs">
    <DeleteParameters>
        <asp:Parameter Name="employeeID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Проверьте страницу, перейдя к ней через браузер. Как показано на рисунке 14, страница будет содержать список каждого сотрудника и имя его или её руководителя, если таковой имеется.

JOIN в хранимой процедуре Employees_Select возвращает имя менеджера

Рис. 14. В JOINEmployees_Select хранимой процедуре возвращается имя менеджера (щелкните, чтобы увеличить изображение)

Нажатие кнопки "Удалить" запускает рабочий процесс удаления, который завершается выполнением Employees_Delete хранимой процедуры. Однако попытка DELETE инструкции в хранимой процедуре завершается сбоем из-за нарушения ограничения внешнего ключа (см. рис. 15). В частности, у каждого сотрудника есть одна или несколько записей в Orders таблице, что приводит к сбою удаления.

Удаление сотрудника с соответствующими заказами приводит к нарушению ограничения внешнего ключа

Рис. 15. Удаление сотрудника с соответствующими заказами приводит к нарушению ограничения внешнего ключа (щелкните, чтобы просмотреть изображение полного размера)

Чтобы разрешить удалению сотрудника, можно выполнить следующие действия.

  • Обновите ограничение внешнего ключа для разрешения каскадных удалений.
  • Вручную удалите записи из Orders таблицы для сотрудников, которые вы хотите удалить, или
  • Employees_Delete Обновите хранимую процедуру, чтобы сначала удалить связанные записи из Orders таблицы перед удалением Employees записи. Мы обсудили этот метод в руководстве по использованию существующих хранимых процедур для typed DataSet s TableAdapters .

Я оставлю это как упражнение для читателя.

Сводка

При работе с реляционными базами данных обычно запросы извлекают данные из нескольких связанных таблиц. Коррелированные вложенные запросы и JOIN предоставляют два различных метода доступа к данным из связанных таблиц в запросе. В предыдущих руководствах мы чаще всего использовали коррелированные подзапросы, так как TableAdapter не может автоматически создавать операторы INSERT, UPDATE, и DELETE для запросов, включающих JOIN. Хотя эти значения можно указать вручную, при использовании нерегламентированных инструкций SQL все настройки будут перезаписаны при завершении мастера настройки TableAdapter.

К счастью, TableAdapters, созданные с помощью хранимых процедур, не страдают от той же хрупкости, что и созданные с помощью нерегламентированных инструкций SQL. Поэтому можно создать TableAdapter, основной запрос которого используется JOIN при использовании хранимых процедур. В этом руководстве мы узнали, как создать такой объект TableAdapter. Мы начали использовать JOINзапрос -less SELECT для основного запроса TableAdapter, чтобы соответствующие процедуры вставки, обновления и удаления хранимых процедур были созданы автоматически. После завершения начальной конфигурации TableAdapter мы изменили SelectCommand хранимую процедуру, чтобы она использовала JOIN, и повторно запустили мастер конфигурации TableAdapter для обновления столбцов EmployeesDataTable.

Повторное выполнение мастера настройки TableAdapter автоматически обновило столбцы EmployeesDataTable, чтобы отразить поля данных, возвращаемые хранимой процедурой Employees_Select. Кроме того, эти столбцы можно было добавить вручную в DataTable. В следующем руководстве мы рассмотрим ручное добавление столбцов в DataTable.

Счастливое программирование!

Сведения о авторе

Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Учись сам ASP.NET 2.0 за 24 часа. Его можно достичь по адресу mitchell@4GuysFromRolla.com.

Особое спасибо кому

Эта серия учебников была проверена многими полезными рецензентами. Основные рецензенты для этого руководства были Хилтон Гайсеноу, Дэвид Суру и Тереза Мерфи. Хотите просмотреть мои предстоящие статьи MSDN? Если да, напишите мне на mitchell@4GuysFromRolla.com.