Atualizar o TableAdapter para usar JOINs (C#)

por Scott Mitchell

Baixar PDF

Ao trabalhar com um banco de dados, é comum solicitar dados distribuídos em várias tabelas. Para recuperar dados de duas tabelas diferentes, podemos usar uma subconsulta correlacionada ou uma operação JOIN. Neste tutorial, comparamos subconsultas correlacionadas e a sintaxe JOIN antes de examinar como criar um TableAdapter que inclui um JOIN em sua consulta main.

Introdução

Com bancos de dados relacionais, os dados com os quais estamos interessados em trabalhar geralmente são distribuídos em várias tabelas. Por exemplo, ao exibir informações do produto, provavelmente queremos listar os nomes de cada categoria e fornecedor correspondentes de cada produto. A Products tabela tem CategoryID valores e SupplierID , mas os nomes reais da categoria e do fornecedor estão nas Categories tabelas e Suppliers , respectivamente.

Para recuperar informações de outra tabela relacionada, podemos usar subconsultas correlacionadas ou JOINs. Uma subconsulta correlacionada é uma consulta aninhada SELECT que faz referência a colunas na consulta externa. Por exemplo, no tutorial Criando uma camada de acesso a dados, usamos duas subconsultas correlacionadas na ProductsTableAdapter consulta s main para retornar os nomes de categoria e fornecedor para cada produto. Um JOIN é um constructo SQL que mescla linhas relacionadas de duas tabelas diferentes. Usamos um JOIN no tutorial Consultando dados com o controle SqlDataSource para exibir informações de categoria junto com cada produto.

O motivo pelo qual nos abstivemos de usar JOIN s com o TableAdapters é devido a limitações no assistente tableAdapter s para gerar automaticamente instruções , UPDATEe DELETE correspondentesINSERT. Mais especificamente, se a consulta main tableAdapter contiver sJOIN, o TableAdapter não poderá criar automaticamente as instruções SQL ad hoc ou procedimentos armazenados para suas InsertCommandpropriedades , UpdateCommande DeleteCommand .

Neste tutorial, compararemos e compararemos brevemente subconsultas correlacionadas e JOIN s antes de explorar como criar um TableAdapter que inclua JOIN s em sua consulta main.

Comparando e contrastando subconsultas correlacionadas eJOIN s

Lembre-se de que o ProductsTableAdapter criado no primeiro tutorial do Northwind DataSet usa subconsultas correlacionadas para trazer de volta cada categoria e nome do fornecedor correspondentes de cada produto. A ProductsTableAdapter consulta s main é mostrada abaixo.

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

As duas subconsultas correlacionadas – (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) e – são SELECT consultas que retornam um único valor por produto como uma coluna adicional na lista de colunas da instrução externa SELECT(SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) .

Como alternativa, um JOIN pode ser usado para retornar o fornecedor e o nome da categoria de cada produto. A consulta a seguir retorna a mesma saída que a acima, mas usa JOIN s no lugar de subconsultas:

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

Um JOIN mescla os registros de uma tabela com registros de outra tabela com base em alguns critérios. Na consulta acima, por exemplo, o instrui SQL Server LEFT JOIN Categories ON Categories.CategoryID = Products.CategoryID a mesclar cada registro de produto com o registro de categoria cujo CategoryID valor corresponde ao valor do CategoryID produto. O resultado mesclado nos permite trabalhar com os campos de categoria correspondentes para cada produto (como CategoryName).

Observação

JOIN s são comumente usados ao consultar dados de bancos de dados relacionais. Se você não estiver familiarizado com a JOIN sintaxe ou precisar melhorar um pouco seu uso, recomendo o tutorial ingressar no SQL nas Escolas W3. Também vale a pena ler as JOIN seções Conceitos Básicos e Conceitos Básicos da Subconsulta dos Manuais Online do SQL.

Como JOIN s e subconsultas correlacionadas podem ser usadas para recuperar dados relacionados de outras tabelas, muitos desenvolvedores ficam coçando a cabeça e se perguntando qual abordagem usar. Todos os gurus do SQL com quem falei disseram aproximadamente a mesma coisa, que isso realmente não importa para o desempenho, pois SQL Server produzirá planos de execução aproximadamente idênticos. O conselho deles, então, é usar a técnica com a qual você e sua equipe estão mais confortáveis. Merece notar que, depois de dar esse conselho, esses especialistas imediatamente expressam sua preferência de JOIN s sobre subconsultas correlacionadas.

Ao criar uma Camada de Acesso a Dados usando DataSets Tipado, as ferramentas funcionam melhor ao usar subconsultas. Em particular, o assistente tableAdapter s não gerará automaticamente as instruções , UPDATEe DELETE correspondentes INSERTse a consulta main contiver sJOIN, mas gerará automaticamente essas instruções quando subconsultas correlacionadas forem usadas.

Para explorar essa deficiência, crie um Conjunto de Dados Tipado temporário na ~/App_Code/DAL pasta . Durante o assistente de Configuração do TableAdapter, escolha usar instruções SQL ad hoc e insira a seguinte SELECT consulta (consulte a Figura 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

Captura de tela mostrando a janela do Assistente de Configuração do TableAdaptor com uma consulta inserida que contém JOINs.

Figura 1: insira uma consulta principal que contenha JOIN s (clique para exibir a imagem em tamanho real)

Por padrão, o TableAdapter criará INSERTautomaticamente instruções , UPDATEe DELETE com base na consulta main. Se você clicar no botão Avançado, poderá ver que esse recurso está habilitado. Apesar dessa configuração, o TableAdapter não poderá criar as INSERTinstruções , UPDATEe DELETE porque a consulta main contém um JOIN.

Captura de tela mostrando a janela Opções Avançadas com a caixa de seleção Gerar instruções Inserir, Atualizar e Excluir selecionada.

Figura 2: Insira uma consulta principal que contenha JOIN s

Clique em Concluir para concluir o assistente. Neste ponto, o Designer do DataSet incluirá um único TableAdapter com uma DataTable com colunas para cada um dos campos retornados na SELECT lista de colunas da consulta. Isso inclui e CategoryNameSupplierName, como mostra a Figura 3.

A DataTable inclui uma coluna para cada campo retornado na lista de colunas

Figura 3: A DataTable inclui uma coluna para cada campo retornado na lista de colunas

Embora a DataTable tenha as colunas apropriadas, o TableAdapter não tem valores para suas InsertCommandpropriedades , UpdateCommande DeleteCommand . Para confirmar isso, clique no TableAdapter no Designer e vá para o janela Propriedades. Lá, você verá que as InsertCommandpropriedades , UpdateCommande DeleteCommand estão definidas como (Nenhum).

As propriedades InsertCommand, UpdateCommand e DeleteCommand são definidas como (Nenhum)

Figura 4: as InsertCommandpropriedades , UpdateCommande DeleteCommand são definidas como (Nenhum) (Clique para exibir a imagem em tamanho real)

Para contornar essa deficiência, podemos fornecer manualmente as instruções e parâmetros SQL para as InsertCommandpropriedades , UpdateCommande DeleteCommand por meio do janela Propriedades. Como alternativa, podemos começar configurando a consulta main tableAdapter para não incluir nenhum JOIN s. Isso permitirá que as INSERTinstruções , UPDATEe DELETE sejam geradas automaticamente para nós. Depois de concluir o assistente, podemos atualizar manualmente o TableAdapter s SelectCommand do janela Propriedades para que ele inclua a JOIN sintaxe.

Embora essa abordagem funcione, ela é muito frágil ao usar consultas SQL ad hoc porque sempre que a consulta main do TableAdapter é reconfigurada por meio do assistente, as instruções , UPDATEe DELETE geradas INSERTautomaticamente são recriadas. Isso significa que todas as personalizações feitas posteriormente seriam perdidas se clicarmos com o botão direito do mouse no TableAdapter, escolhermos Configurar no menu de contexto e concluirmos o assistente novamente.

A fragilidade das instruções , UPDATEe DELETE geradas INSERTautomaticamente pelo TableAdapter é, felizmente, limitada a instruções SQL ad hoc. Se o TableAdapter usar procedimentos armazenados, você poderá personalizar os SelectCommandprocedimentos armazenados , UpdateCommandInsertCommand, ou DeleteCommand e executar novamente o assistente de Configuração do TableAdapter sem ter que temer que os procedimentos armazenados sejam modificados.

Nas próximas etapas, criaremos um TableAdapter que, inicialmente, usa uma consulta main que omite qualquer JOIN s para que os procedimentos armazenados de inserção, atualização e exclusão correspondentes sejam gerados automaticamente. Em seguida, atualizaremos o SelectCommand para que use um JOIN que retorna colunas adicionais de tabelas relacionadas. Por fim, criaremos uma classe de Camada de Lógica de Negócios correspondente e demonstraremos o uso do TableAdapter em uma página da Web ASP.NET.

Etapa 1: Criando o TableAdapter usando uma consulta principal simplificada

Para este tutorial, adicionaremos um TableAdapter e um DataTable fortemente tipado para a Employees tabela no NorthwindWithSprocs DataSet. A Employees tabela contém um ReportsTo campo que especificou o EmployeeID do gerente do funcionário. Por exemplo, a funcionária Anne Dodsworth tem um ReportTo valor de 5, que é o EmployeeID de Steven Buchanan. Consequentemente, Anne se reporta a Steven, seu empresário. Além de relatar o valor de ReportsTo cada funcionário, talvez também queiramos recuperar o nome do gerente. Isso pode ser feito usando um JOIN. Mas usar um JOIN ao criar inicialmente o TableAdapter impede que o assistente gere automaticamente os recursos correspondentes de inserção, atualização e exclusão. Portanto, começaremos criando um TableAdapter cuja consulta main não contém nenhum JOIN s. Em seguida, na Etapa 2, atualizaremos o procedimento armazenado da consulta main para recuperar o nome do gerente por meio de um JOIN.

Comece abrindo o NorthwindWithSprocs DataSet na ~/App_Code/DAL pasta . Clique com o botão direito do mouse no Designer, selecione a opção Adicionar no menu de contexto e escolha o item de menu TableAdapter. Isso iniciará o assistente de Configuração do TableAdapter. Como a Figura 5 descreve, fazer com que o assistente crie novos procedimentos armazenados e clique em Avançar. Para obter um atualizador sobre como criar novos procedimentos armazenados do assistente TableAdapter s, consulte o tutorial Criando novos procedimentos armazenados para o TableAdapters do Conjunto de Dados Tipado .

Selecione a opção Criar procedimentos armazenados

Figura 5: Selecione a opção Criar procedimentos armazenados (clique para exibir a imagem em tamanho real)

Use a seguinte SELECT instrução para a consulta main tableAdapter:

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

Como essa consulta não inclui nenhum JOIN s, o assistente TableAdapter criará automaticamente procedimentos armazenados com instruções , UPDATEe DELETE correspondentesINSERT, bem como um procedimento armazenado para executar a consulta main.

A etapa a seguir nos permite nomear os procedimentos armazenados do TableAdapter. Use os nomes Employees_Select, Employees_Insert, Employees_Updatee Employees_Delete, conforme mostrado na Figura 6.

Nomear os procedimentos armazenados do TableAdapter

Figura 6: Nomear os Procedimentos Armazenados do TableAdapter (clique para exibir a imagem em tamanho real)

A etapa final nos solicita o nome dos métodos de TableAdapter. Use Fill e GetEmployees como os nomes de método. Além disso, deixe a caixa de seleção Criar métodos para enviar atualizações diretamente ao banco de dados (GenerateDBDirectMethods) marcada.

Nomear os métodos Fill e GetEmployees do TableAdapter

Figura 7: Nomear os métodos FillGetEmployees tableAdapter e (clique para exibir a imagem em tamanho real)

Depois de concluir o assistente, reserve um momento para examinar os procedimentos armazenados no banco de dados. Você deverá ver quatro novos: Employees_Select, Employees_Insert, Employees_Updatee Employees_Delete. Em seguida, inspecione o EmployeesDataTable e EmployeesTableAdapter o acabou de criar. A DataTable contém uma coluna para cada campo retornado pela consulta main. Clique no TableAdapter e vá para o janela Propriedades. Lá, você verá que as InsertCommandpropriedades , UpdateCommande DeleteCommand estão configuradas corretamente para chamar os procedimentos armazenados correspondentes.

O TableAdapter inclui recursos de inserção, atualização e exclusão

Figura 8: o TableAdapter inclui recursos de inserção, atualização e exclusão (clique para exibir a imagem em tamanho real)

Com os procedimentos armazenados de inserção, atualização e exclusão criados automaticamente e as InsertCommandpropriedades , UpdateCommande DeleteCommand configuradas corretamente, estamos prontos para personalizar o SelectCommand procedimento armazenado s para retornar informações adicionais sobre cada gerente de funcionário. Especificamente, precisamos atualizar o Employees_Select procedimento armazenado para usar um JOIN e retornar os valores e LastName s do FirstName gerente. Depois que o procedimento armazenado for atualizado, precisaremos atualizar o DataTable para que ele inclua essas colunas adicionais. Abordaremos essas duas tarefas nas Etapas 2 e 3.

Etapa 2: Personalizando o procedimento armazenado para incluir umJOIN

Comece acessando o servidor Explorer, fazendo uma busca detalhada na pasta Procedimentos Armazenados do banco de dados Northwind e abrindo o Employees_Select procedimento armazenado. Se você não vir esse procedimento armazenado, clique com o botão direito do mouse na pasta Procedimentos Armazenados e escolha Atualizar. Atualize o procedimento armazenado para que ele use um LEFT JOIN para retornar o nome e o sobrenome do gerente:

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

Depois de atualizar a SELECT instrução , salve as alterações acessando o menu Arquivo e escolhendo Salvar Employees_Select. Como alternativa, você pode clicar no ícone Salvar na barra de ferramentas ou clicar em Ctrl+S. Depois de salvar as alterações, clique com o botão direito do Employees_Select mouse no procedimento armazenado na Explorer servidor e escolha Executar. Isso executará o procedimento armazenado e mostrará seus resultados na janela Saída (consulte a Figura 9).

Os resultados dos procedimentos armazenados são exibidos na janela de saída

Figura 9: Os resultados dos procedimentos armazenados são exibidos na janela saída (clique para exibir a imagem em tamanho real)

Etapa 3: Atualizando as colunas da DataTable s

Neste ponto, o Employees_Select procedimento armazenado retorna ManagerFirstName valores e ManagerLastName , mas o EmployeesDataTable está faltando essas colunas. Essas colunas ausentes podem ser adicionadas à DataTable de duas maneiras:

  • Manualmente – clique com o botão direito do mouse na DataTable no Designer DataSet e, no menu Adicionar, escolha Coluna. Em seguida, você pode nomear a coluna e definir suas propriedades adequadamente.
  • Automaticamente – o assistente de Configuração de TableAdapter atualizará as colunas de DataTable para refletir os campos retornados pelo SelectCommand procedimento armazenado. Ao usar instruções SQL ad hoc, o assistente também removerá as InsertCommandpropriedades , UpdateCommande DeleteCommand , já que o SelectCommand agora contém um JOIN. No entanto, ao usar procedimentos armazenados, essas propriedades de comando permanecem intactas.

Exploramos a adição manual de colunas DataTable em tutoriais anteriores, incluindo Mestre/Detalhe usando uma lista com marcadores de registros mestres com uma DataList de Detalhes e Carregando Arquivos, e examinaremos esse processo novamente com mais detalhes em nosso próximo tutorial. Para este tutorial, no entanto, vamos usar a abordagem automática por meio do assistente de Configuração de TableAdapter.

Comece clicando com o botão direito do EmployeesTableAdapter mouse no e selecionando Configurar no menu de contexto. Isso abre o assistente de Configuração do TableAdapter, que lista os procedimentos armazenados usados para selecionar, inserir, atualizar e excluir, juntamente com seus valores e parâmetros retornados (se houver). A Figura 10 mostra esse assistente. Aqui podemos ver que o Employees_Select procedimento armazenado agora retorna os ManagerFirstName campos e ManagerLastName .

O Assistente mostra a lista de colunas atualizadas para o procedimento armazenado Employees_Select

Figura 10: o assistente mostra a lista de colunas atualizada para o Employees_Select procedimento armazenado (clique para exibir a imagem em tamanho real)

Conclua o assistente clicando em Concluir. Ao retornar ao dataset Designer, o EmployeesDataTable inclui duas colunas adicionais: ManagerFirstName e ManagerLastName.

A EmployeesDataTable contém duas novas colunas

Figura 11: o EmployeesDataTable contém duas novas colunas (clique para exibir a imagem em tamanho real)

Para ilustrar que o procedimento armazenado atualizado Employees_Select está em vigor e que os recursos de inserção, atualização e exclusão do TableAdapter ainda estão funcionais, vamos criar uma página da Web que permita que os usuários exibam e excluam funcionários. No entanto, antes de criarmos essa página, precisamos primeiro criar uma nova classe na Camada de Lógica de Negócios para trabalhar com funcionários do NorthwindWithSprocs DataSet. Na Etapa 4, criaremos uma EmployeesBLLWithSprocs classe. Na Etapa 5, usaremos essa classe de uma página ASP.NET.

Etapa 4: Implementando a camada de lógica de negócios

Crie um novo arquivo de classe na ~/App_Code/BLL pasta chamada EmployeesBLLWithSprocs.cs. Essa classe imita a semântica da classe existente EmployeesBLL , apenas essa nova fornece menos métodos e usa o NorthwindWithSprocs DataSet (em vez do Northwind DataSet). Adicione o código a seguir à classe 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;
    }
}

A EmployeesBLLWithSprocs propriedade da classe s Adapter retorna uma instância do NorthwindWithSprocs DataSet s EmployeesTableAdapter. Isso é usado pelos métodos e DeleteEmployee da classe sGetEmployees. O GetEmployees método chama o EmployeesTableAdapter método correspondente GetEmployees s, que invoca o Employees_Select procedimento armazenado e preenche seus resultados em um EmployeeDataTable. O DeleteEmployee método também chama o EmployeesTableAdapter método s Delete , que invoca o Employees_Delete procedimento armazenado.

Etapa 5: Trabalhando com os dados na camada de apresentação

Com a EmployeesBLLWithSprocs classe concluída, estamos prontos para trabalhar com os dados dos funcionários por meio de uma página ASP.NET. Abra a JOINs.aspx página na AdvancedDAL pasta e arraste um GridView da Caixa de Ferramentas para o Designer, definindo sua ID propriedade Employeescomo . Em seguida, na marca inteligente GridView, associe a grade a um novo controle ObjectDataSource chamado EmployeesDataSource.

Configure o ObjectDataSource para usar a EmployeesBLLWithSprocs classe e, nas guias SELECT e DELETE, verifique se os GetEmployees métodos e DeleteEmployee estão selecionados nas listas suspensas. Clique em Concluir para concluir a configuração do ObjectDataSource.

Configurar o ObjectDataSource para usar a classe EmployeesBLLWithSprocs

Figura 12: Configurar o ObjectDataSource para usar a EmployeesBLLWithSprocs classe (clique para exibir a imagem em tamanho real)

Fazer com que o ObjectDataSource use os métodos GetEmployees e DeleteEmployee

Figura 13: Fazer com que o ObjectDataSource use os GetEmployees métodos e DeleteEmployee (clique para exibir a imagem em tamanho real)

O Visual Studio adicionará um BoundField ao GridView para cada uma das EmployeesDataTable colunas s. Remova todos esses BoundFields, exceto Title, LastName, FirstNameManagerFirstName, e ManagerLastName renomeie as HeaderText propriedades dos últimos quatro BoundFields como Sobrenome, Nome, Nome do Gerente e Sobrenome do Gerente, respectivamente.

Para permitir que os usuários excluam funcionários desta página, precisamos fazer duas coisas. Primeiro, instrua o GridView a fornecer recursos de exclusão verificando a opção Habilitar Exclusão de sua marca inteligente. Em segundo lugar, altere a propriedade objectDataSource do OldValuesParameterFormatString valor definido pelo assistente ObjectDataSource (original_{0}) para seu valor padrão ({0}). Depois de fazer essas alterações, a marcação declarativa de GridView e ObjectDataSource deve ser semelhante à seguinte:

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

Teste a página visitando-a por meio de um navegador. Como mostra a Figura 14, a página listará cada funcionário e o nome do gerente (supondo que eles tenham um).

O JOIN no procedimento armazenado Employees_Select retorna o nome do gerente

Figura 14: o JOIN no Employees_Select procedimento armazenado retorna o nome do gerente (clique para exibir a imagem em tamanho real)

Clicar no botão Excluir inicia o fluxo de trabalho de exclusão, que culmina na execução do Employees_Delete procedimento armazenado. No entanto, a tentativa DELETE de instrução no procedimento armazenado falha devido a uma violação de restrição de chave estrangeira (consulte a Figura 15). Especificamente, cada funcionário tem um ou mais registros na Orders tabela, fazendo com que a exclusão falhe.

Excluir um funcionário que tenha pedidos correspondentes resulta em uma violação de restrição de chave estrangeira

Figura 15: Excluir um funcionário que tenha pedidos correspondentes resulta em uma violação de restrição de chave estrangeira (clique para exibir a imagem em tamanho real)

Para permitir que um funcionário seja excluído, você pode:

  • Atualize a restrição de chave estrangeira para exclusões em cascata,
  • Exclua manualmente os registros da Orders tabela para os funcionários que você deseja excluir ou
  • Atualize o Employees_Delete procedimento armazenado para primeiro excluir os registros relacionados da tabela antes de Orders excluir o Employees registro. Discutimos essa técnica no tutorial Usando procedimentos armazenados existentes para tableAdapters do Conjunto de Dados Tipado .

Eu deixo isso como um exercício para o leitor.

Resumo

Ao trabalhar com bancos de dados relacionais, é comum que as consultas efetuem pull dos dados de várias tabelas relacionadas. Subconsultas correlacionadas e JOIN s fornecem duas técnicas diferentes para acessar dados de tabelas relacionadas em uma consulta. Nos tutoriais anteriores, geralmente usamos subconsultas correlacionadas porque o TableAdapter não pode gerar INSERTautomaticamente as instruções , UPDATEe DELETE para consultas que envolvem JOIN s. Embora esses valores possam ser fornecidos manualmente, ao usar instruções SQL ad hoc, todas as personalizações serão substituídas quando o assistente de Configuração do TableAdapter for concluído.

Felizmente, os TableAdapters criados usando procedimentos armazenados não sofrem da mesma fragilidade que aqueles criados usando instruções SQL ad hoc. Portanto, é viável criar um TableAdapter cuja consulta main usa um JOIN ao usar procedimentos armazenados. Neste tutorial, vimos como criar um TableAdapter desse tipo. Começamos usando uma JOINconsulta -less SELECT para a consulta main tableAdapter para que os procedimentos armazenados de inserção, atualização e exclusão correspondentes fossem criados automaticamente. Com a configuração inicial do TableAdapter concluída, aumentamos o SelectCommand procedimento armazenado para usar um JOIN e executar novamente o assistente de Configuração de TableAdapter para atualizar as EmployeesDataTable colunas s.

Executar novamente o assistente de Configuração do TableAdapter atualizou automaticamente as EmployeesDataTable colunas para refletir os campos de dados retornados pelo Employees_Select procedimento armazenado. Como alternativa, poderíamos ter adicionado essas colunas manualmente à DataTable. Exploraremos a adição manual de colunas à DataTable no próximo tutorial.

Programação feliz!

Sobre o autor

Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.

Agradecimentos Especiais

Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Hilton Geisenow, David Suru e Teresa Murphy. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.