Definição de relações entre tabelas de banco de dados

Objectives

After completing this lesson, you will be able to:
  • Entenda as relações nos modelos de dados.
  • Definir dependências de chave externa em tabelas Dictionary.

Relações em modelos de dados

Normalmente, as entidades de um modelo de dados estão relacionadas entre si. A definição de um modelo de dados inclui a definição dessas relações.

Vejamos o modelo de dados de uma empresa, que inclui as entidades Empregado e Departamento. As duas entidades estão relacionadas porque os colaboradores estão atribuídos a departamentos.

Mas as duas entidades também podem compartilhar outras relações. Por exemplo, cada departamento é liderado por um dos empregados.

Características importantes de uma relação são suas cardinalidades ou multiplicidades. Eles informam quantas instâncias de uma entidade pertencem a uma instância da outra entidade.

Existem diferentes sistemas de notação para cardinalidades. A Unified Modeling Language (UML), por exemplo, utiliza um valor máximo e mínimo, com * para um máximo irrestrito.

Vejamos nossos exemplos:

Cada empregado deve ser atribuído a exatamente um departamento. Por isso, a cardinalidade nesta direção é 1..1. Na outra direção, um departamento pode ter qualquer número de empregados atribuídos a ele, mesmo que zero seja permitido. Por isso, a cardinalidade é 0..*.

Para a outra relação, consideremos que cada departamento é liderado por exatamente um funcionário, não mais, não menos. Isso significa que ignoramos casos especiais como posições de lead vagas (zero é um valor permitido) ou liderança dupla ou múltipla (são permitidos valores superiores a 1). Na outra direção, podemos facilmente dizer que nem todo funcionário é líder, o que significa que o mínimo é zero. Decidimos definir o máximo para 1, pelo qual expressamos, que um empregado não pode liderar dois departamentos ao mesmo tempo.

Nota

No ABAP Dictionary e no ABAP CDS, a cardinalidade e a multiplicidade são usadas como sinônimos. Estritamente falando, uma cardinalidade é o número real de instâncias, enquanto a multiplicidade especifica o intervalo de valores permitidos.

O ABAP CDS e o ABAP Dictionary usam conceitos diferentes para expressar relações:

Associações

O CDS ABAP utiliza associações para definir relações entre entidades de visão CDS. Normalmente, uma relação é refletida por duas associações, apontando em direções opostas.

Chaves externas

O ABAP Dictionary define uma dependência para campos de tabela para estabelecer uma relação com outra tabela de banco de dados. Uma dessas dependências de chave externa corresponde a uma relação.

Vamos explorar as possibilidades de definição de relações analisando mais detalhadamente as dependências de chave externa no ABAP Dictionary.

Definições de chave externa em tabelas Dictionary

No ABAP Dictionary, você pode utilizar dependências de chave externa para definir relações entre tabelas.

Na programação ABAP moderna, o principal objetivo dessas dependências de chave externa é a documentação. No desenvolvimento ABAP clássico, no entanto, eles tiveram uma influência direta na interface do usuário. Eles deram origem a verificações de entrada implícitas e entradas possíveis geradas.

Nota

No desenvolvimento ABAP moderno, as associações entre entidades de visão CDS assumiram parcialmente essa tarefa. Consulte a próxima lição para obter mais detalhes.

É importante observar que as definições de chave externa no ABAP Dictionary permanecem na camada ABAP. Eles não são transferidos para o banco de dados. Como consequência, eles não levam a verificações de consistência implícitas no banco de dados.

Uma dependência de chave externa define uma relação entre duas tabelas de banco de dados Dictionary, uma delas é chamada de tabela de chave externa e a outra é a tabela de verificação.

Uma dependência de chave externa completa liga cada campo de chave primária da tabela de verificação a um campo correspondente na tabela de chave externa. No exemplo, a chave primária da tabela de verificação é composta por três campos: C1, C2 e C3. A relação de chave externa liga os mesmos aos campos F1, F2 e F6 na tabela de chave externa. Os campos F1, F2 e F6 juntos formam a chave externa.

Nota

Uma chave externa pode conter qualquer combinação de campos; campos-chave e campos não chave. Os campos relacionados na tabela de verificação são sempre campos-chave.

A dependência de chave externa restringe os valores nos campos de chave externa: só são permitidas as combinações que estão presentes na tabela de verificação. Esta restrição é particularmente importante para o último campo de chave externa, ou seja, o campo que está ligado ao último campo-chave primário da tabela de verificação. Este campo é chamado de campo de verificação. Em nosso exemplo, o campo de verificação é o campo F6.

Exemplo: relação de chave externa

Reproduza o vídeo para ver um exemplo de uma relação de chave externa.

Atributos semânticos de chaves externas

Quando você define uma relação de chave externa, pode adicionar informações semânticas para descrever mais a relação e influenciar a forma como ela é usada pelo framework.

A maioria das informações semânticas é especificada usando anotações de chave externa. Somente a cardinalidade é indicada diretamente na instrução DEFINE TABLE.

Se um campo tiver uma relação de chave externa, você pode adicionar as seguintes anotações de chave externa:

Descrição breve

O texto breve é utilizado como texto explicativo para uma relação de chave externa.

Tipo de campo de chave externa

A anotação @AbapCatalog.foreignKey.keyType descreve o significado dos campos de chave externa na tabela de chave externa. Selecione o valor #KEY, se todos os campos de chave externa forem campos-chave da tabela de chave externa. Selecione #NON_KEY se pelo menos um campo de chave externa não for um campo-chave da tabela de chave externa. No exemplo, #NON_KEY está correto, porque o campo DEPARTMENT_ID não é um campo-chave da tabela EMPLOYEE. O terceiro valor, #TEXT_KEY, é relevante se a tabela de chave externa for uma tabela de textos, ou seja, se contiver um texto traduzível para a tabela de verificação.

Verificação de valores para IU clássica

A anotação @ABAPCatalog.foreignKey.screenCheck controla se os diálogos de usuário clássicos executam verificações de valores com base nessa relação de chave externa. Se definido como verdadeiro, estão disponíveis outras anotações para indicar uma mensagem de erro dedicada. Caso contrário, é exibida uma mensagem de erro genérica.

Nota

As anotações de tela e mensagem não são relevantes em diálogos de usuário modernos. A menos que você planeje desenvolver IUs clássicas, defina o valor de @ABAPCatalog.foreignKey.screenCheck como falso.

A cardinalidade descreve uma relação de chave externa em relação ao número de registros dependentes possíveis (registros da tabela de chave externa) ou registros referenciados (registros da tabela de verificação).

No ABAP Dictionary, a cardinalidade é indicada com [ n , m ] imediatamente após a palavra-chave KEY.

  • O lado esquerdo (n) indica o número de registros de tabela de chave externa por registro de tabela de verificação e pode ter os valores 1, 0..1, 1..* e 0..*.
  • O lado direito (m) indica o número de registros da tabela de verificação por registro de tabela de chave externa e pode ter os valores 1 ou 0..1.

Para selecionar a cardinalidade correta, comece com o lado direito.

Selecione m = 1, se o campo de verificação for um campo obrigatório. Neste caso, cada registro na tabela de chave externa necessita de um valor no campo de verificação e de um registro correspondente na tabela de verificação.

Selecione m = 0..1, se o campo de verificação for opcional. Em seguida, os registros sem um valor no campo de verificação não necessitam de um registro correspondente na tabela de verificação.

Vejamos nosso exemplo com colaboradores e departamentos:

Se for obrigatório que um empregado seja atribuído a um departamento, a cardinalidade da chave externa deve ter m = 1. Se também for possível que um empregado não esteja atribuído a um departamento, a cardinalidade deve ter m = 0..1.

Agora vamos dar uma olhada no lado esquerdo da cardinalidade. O significado dos diferentes valores é o seguinte:

  n = 1

Existe exatamente um registro dependente (registro da tabela de chave externa) para cada registro da tabela de verificação.

n = 0..1

Existe no máximo um registro dependente para cada registro da tabela de verificação. Mas existem registros da tabela de verificação para os quais não existe nenhum registro dependente na tabela de chave externa.

n = 1..*

Existe pelo menos um registro dependente para cada registro da tabela de verificação.

n = 0..*

Pode existir qualquer número de registros dependentes para cada registro da tabela de verificação: nenhum, um ou mais de um.

Em nosso exemplo, você deve se perguntar: Quantos funcionários podem ser atribuídos ao mesmo departamento? Exatamente um? No máximo um? Pelo menos um? Algum número? O que você acha?

Como definir uma relação de chave externa

Reproduza o vídeo para ver como definir uma relação de chave externa.

Definir uma relação de chave externa

Você define uma segunda tabela de banco de dados para departamentos e define a relação de chave externa entre departamentos e empregados.

Modelo:

  • /LRN/EMPLOY_DEP (Definição de tabela de banco de dados)

Solução:

  • /LRN/DEPMENT_REL (Definição de tabela de banco de dados)
  • /LRN/EMPLOY_REL (Definição de tabela de banco de dados)
  • /LRN/DEPMENT_HEAD (Elemento de dados)
  • /LRN/DEPMENT_ASSISTANT (Elemento de dados)

Pré-requisitos

Para este exercício, você precisa da tabela de banco de dados para os dados do empregado que criou e preencheu em um exercício anterior (o nome sugerido foi: Z##EMPLOY, em que ## é o número do seu grupo). Se você não tiver concluído esse exercício, crie uma cópia da tabela de banco de dados /LRN/EMPLOY_DEP.

Tarefa 1: Definir uma tabela de banco de dados para dados do departamento

Crie uma definição de tabela de banco de dados para armazenar dados de departamento (nome sugerido: Z##DEPMENT, em que ## é o número de seu grupo).

Além do campo de mandante, adicione os seguintes campos:

Nome do campoData Element
IDZ##_DEPARTMENT_ID (criado no exercício anterior)
descrição/LRN/DEPMENT_DESCRIPTION

Adicione o campo ID à chave da tabela e inclua a estrutura /LRN/S_ADMIN para dados administrativos na lista de campos.

Etapas

  1. Crie um novo objeto de desenvolvimento do tipo Tabela de banco de dados (nome sugerido: Z##DEPMENT).

    1. No Explorador de projetos, expanda seu pacote e abra o menu de contexto no subnó Dicionário.

    2. Selecione Nova→tabela de banco de dados.

    3. Confirme o pacote, insira o nome Z##DEPMENT e a descrição Departamento e, em seguida, selecione Seguinte.

    4. Atribua o novo objeto a uma ordem de transporte e selecione Concluir.

    5. O código da definição de tabela de banco de dados deve ter o seguinte aspecto:

      Code Snippet
      123456789101112
      @EndUserText.label : 'Department' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table z##depment { key client : abap.clnt not null; }
  2. Após o campo do cliente, adicione um segundo ID de campo-chave e digite-o com o elemento de dados Z##_DEPARTMENT_ID.

    Nota

    Se você não concluiu o exercício correspondente, utilize o elemento de dados /LRN/DEPARTMENT_ID.
    1. Ajuste o código da seguinte forma:

      Code Snippet
      12345678
      define table z##depment { key client : abap.clnt not null; key id : z##_department_id; }
  3. Adicione uma descrição do campo com base no elemento de dados /LRN/DEPMENT_DESCRIPTION.

    1. Ajuste o código da seguinte forma:

      Code Snippet
      123456789
      define table z##depment { key client : abap.clnt not null; key id : z##_department_id; description : /lrn/depment_description; }
  4. Incluir estrutura /LRN/S_ADMIN com campos administrativos.

    1. Ajuste o código da seguinte forma:

      Code Snippet
      12345678910
      define table z##depment { key client : abap.clnt not null; key id : z##_department_id; description : /lrn/depment_description; include : /lrn/s_admin; }
  5. Atualize as configurações técnicas da tabela. Utilize as entradas possíveis para selecionar valores adequados para a classe de dados e a categoria de tamanho.

    Nota

    Esperamos que a tabela contenha menos de 100 entradas.
    1. Clique com o botão direito do mouse em qualquer lugar do editor e selecione Abrir outros→Configurações técnicas.

    2. Selecione APPL0 Dados mestre, tabela transparente.

    3. Selecione 0 Registros previstos 0 - 2.600.

  6. Ative as configurações técnicas de tabela e a definição de tabela de banco de dados.

    1. Enquanto ainda estiver na caixa de diálogo Configurações técnicas de tabela, pressione Ctrl + F3 para ativar as configurações técnicas da tabela.

    2. Retorne ao editor com o texto fonte da definição de tabela de banco de dados e pressione Ctrl + F3 para ativar a definição de tabela de banco de dados.

Tarefa 2: Definir uma relação de chave externa

Defina uma relação de chave externa entre suas tabelas de banco de dados para dados do empregado e dados do departamento. A relação deve documentar que os empregados só podem ser atribuídos a departamentos existentes. Ou seja, no campo department_id da tabela Z##EMPLOY, só são permitidos os valores para os quais existe uma entrada na tabela Z##DEMENT. Selecione uma cardinalidade adequada para documentar que qualquer número de empregados pode ser atribuído a um único departamento.

Etapas

  1. Identifique a tabela de chave externa e navegue para o campo de verificação.

    1. Abra a definição de sua tabela de banco de dados para dados do empregado (o nome sugerido foi Z##EMPLOY).

    2. Role para baixo até o campo department_id.

  2. Adicione uma chave externa ao campo de verificação.

    Dica

    Utilize a conclusão de código sempre que possível.
    1. Na definição do campo department_id, posicione o cursor antes do ponto e vírgula de fechamento (;) e pressione Enter para inserir uma nova linha de código.

    2. Posicione o cursor no início da nova linha e pressione Ctrl + espaço para chamar a conclusão de código.

    3. Na lista de sugestões, selecione com chave externa - palavra-chave.

    4. Insira um espaço em branco e pressione Ctrl + espaço para chamar novamente a conclusão do código.

    5. Na lista de sugestões, selecione sua tabela de banco de dados para dados do departamento, ou seja, a entrada z##depment - table.

    6. Insira um espaço em branco e use code-completion para inserir a palavra-chave WHERE.

    7. Continue usando o code completion para adicionar a atribuição de campos-chave (no lado esquerdo) e campos-chave externos (no lado direito).

  3. Salve a definição de tabela de banco de dados para chamar a formatação automática.

    Nota

    Ao salvar a definição, o editor também adiciona a anotação @AbapCatalog.foreignKey.screenCheck.
    1. Pressione Ctrl + espaço para salvar o objeto de desenvolvimento.

    2. O código deve ter o seguinte aspecto:

      Code Snippet
      12345678
      entry_date : z##_entry_date; @AbapCatalog.foreignKey.screenCheck : false department_id : z##_department_id with foreign key z##depment where client = z##employ.client and id = z##employ.department_id;
  4. Adicione uma cardinalidade para documentar que um único ID de departamento pode ser usado em qualquer número de conjuntos de dados de funcionários e que, por outro lado, cada funcionário deve ser atribuído a um departamento existente.

    1. Ajuste o código da seguinte forma:

      Code Snippet
      12345678
      entry_date : z##_entry_date; @AbapCatalog.foreignKey.screenCheck : false department_id : z##_department_id with foreign key [0..*,1] z##depment where client = z##employ.client and id = z##employ.department_id;
  5. Ative a definição de tabela de banco de dados.

    1. Pressione Ctrl + F3 para ativar o objeto de desenvolvimento.

Tarefa 3: Definir chefe de departamento e assistente

Amplie sua tabela de banco de dados para dados de departamento com campos para o chefe de departamento e o assistente de departamento (nomes sugeridos: head_id e assistant_id). Defina um novo elemento de dados para cada um dos campos, mas certifique-se de usar o mesmo domínio que no campo employee_id da sua tabela de funcionários. Em seguida, defina uma relação de chave externa para cada um dos campos para documentar que só são permitidos números de empregado existentes.

Etapas

  1. Edite a lista de campos da sua tabela de banco de dados para dados do departamento. Antes da instrução INCLUDE, adicione os seguintes campos e utilize uma correção rápida para criar os novos elementos de dados:

    Nome do campoData Element
    department_headZ##_DEPMENT_HEAD
    assistente_departamentoZ##_DEPMENT_ASSISTANT

    Para ambos os elementos de dados, utilize o domínio Z##_EMPLOYEE_IDas como tipo de dados.

    Nota

    Somente se você não tiver criado um domínio Z##_EMPLOYEE_ID, poderá usar o domínio /LRN/EMPLOYEE_ID. Certifique-se de que o ID do campo-chave de sua tabela de banco de dados para dados do empregado (o nome sugerido era Z##EMPLOY) é baseado no mesmo domínio.
    1. No final da lista de elementos, insira department_head : z##_depment_head; (sendo ## o número do seu grupo).

    2. Abra a visão Problemas. Você deve ver um erro Campo DEPARTMENT_HEAD: o tipo de componente ou domínio usado não está ativo ou não existe.

    3. Posicione o cursor emz##_depment_head e pressione Ctrl + 1 para abrir o menu de solução rápida.

    4. No menu de solução rápida, clique duas vezes em Criar elemento de dados ....

    5. Confirme o pacote e o nome, insira uma descrição, por exemplo, Chefe do departamento, e selecione Seguinte.

    6. Atribua o novo objeto a uma ordem de transporte e selecione Concluir.

    7. Em Nome do tipo, insira Z##_EMPLOYEE_ID e insira os seguintes denominadores de campo:

      CampoValor
      Curto

      Dep. Cabeçalho

      Médio

      Chefe do departamento

      Longo

      Chefe do departamento

      Título

      Chefe do departamento

    8. Ative o novo elemento de dados e retorne à tabela de banco de dados Z##DEPMENT.

    9. Em uma nova linha de código, insira assistant_id : Z##_depment_assistant; e utilize a correção rápida novamente para criar o elemento de dados Z##_DEPMENT_ASSISTANT utilizando o mesmo domínio, mas com os seguintes denominadores de campo:

      CampoValor
      Curto

      Assistente

      Médio

      Dep. Assistente

      Longo

      Assistente de departamento

      Título

      Assistente de departamento

  2. Para os dois novos campos, adicione uma relação de chave externa com a tabela Z##EMPLOY como tabela de verificação. Em seguida, salve a definição de tabela de banco de dados para chamar a formatação automática.

    Dica

    Utilize a conclusão de código sempre que possível.
    1. Depois de aplicar a formatação automática, o código deve ter o seguinte aspecto:

      Code Snippet
      123456789101112131415161718192021
      define table z##depment { key client : abap.clnt not null; key id : z##_department_id not null; description : /lrn/depment_description; @AbapCatalog.foreignKey.screenCheck : false head_id : z##_depment_head with foreign key z##employ where client = z##depment.client and employee_id = z##depment.head_id; @AbapCatalog.foreignKey.screenCheck : false assistant_id : z##_depment_assistant with foreign key z##employ where client = z##depment.client and employee_id = z##depment.assistant_id; include /lrn/s_admin; }
  3. Adicione uma cardinalidade às duas relações de chave externa. Selecione a cardinalidade com base nas seguintes informações:

    • Nem todo empregado pode ser um chefe de departamento ou um assistente de departamento.
    • O mesmo colaborador não pode ser chefe de mais de um departamento.
    • O mesmo colaborador não pode ser assistente de mais de um departamento.
    • Cada departamento precisa exatamente de um assistente de departamento.
    • Um departamento poderia muito bem fazer sem um chefe de departamento.
    1. Ajuste o código da seguinte forma:

      Code Snippet
      12345678910111213
      @AbapCatalog.foreignKey.screenCheck : false head_id : z##_depment_head with foreign key [0..1,0..1] z##employ where client = z##depment.client and employee_id = z##depment.head_id; @AbapCatalog.foreignKey.screenCheck : false assistant_id : z##_depment_assistant with foreign key [0..1,1] z##employ where client = z##depment.client and employee_id = z##depment.assistant_id;
  4. Ative a definição de tabela de banco de dados.

    1. Pressione Ctrl + F3 para ativar o objeto de desenvolvimento.

Tarefa 4: Preencher tabelas

Preencha sua nova tabela de banco de dados com alguns dados de departamento e atualize a tabela de empregados. Para isso, crie uma cópia da classe ABAP /LRN/CL_S4D430_CHECK_AND_FILL e ajuste os valores das constantes c_version, c_Employ_table e c_depment_table. Em seguida, ative e execute a classe como um aplicativo de console.

Etapas

  1. Crie uma cópia da classe ABAP /LRN/CL_S4D430_CHECK_AND_FILL, nomeie-a como Z##_S4D430_CHECK_AND_FILL e coloque-a em seu pacote ZS4D430_##.

    Nota

    Ignore esta etapa se você criou uma cópia de /LRN/CL_S4D430_CHECK_AND_FILL em um exercício anterior.
    1. Na visão Explorador de projetos, localize a classe ABAP no pacote /LRN/S4D430_EXERCISE e clique com o botão direito nele para abrir o menu de contexto.

    2. No menu de contexto, selecione Duplicar.

    3. Insira o nome do seu pacote, o nome da cópia e uma descrição. Em seguida, selecione Seguinte.

    4. Atribua o novo objeto a uma ordem de transporte e selecione Concluir.

  2. Altere o valor da constante c_version de lcl_Generator=>employee_table_only para lcl_Generator=>with_Relations.

    Dica

    Você pode adicionar um sinal de comentário antes da definição atual e remover o sinal de comentário da segunda definição alternativa.
    1. Ajuste o código da seguinte forma:

      Code Snippet
      12345
      * CONSTANTS c_version TYPE t_version VALUE lcl_generator=>employee_table_only. CONSTANTS c_version TYPE t_version VALUE lcl_generator=>with_relationships. * CONSTANTS c_version TYPE t_version VALUE lcl_generator=>with_extensions.
  3. Modifique os valores das constantes c_Employ_table e c_depment_table para os nomes das suas tabelas de banco de dados.

    1. Role para baixo até a linha de código que começa com CONSTANTS c_employ_table.

    2. Se o literal depois de VALUE ainda contiver ##, substitua-o pelo seu número de grupo.

    3. Role para baixo até a linha de código que começa com CONSTANTS c_depment_table.

    4. No literal após VALUE, substitua ## pelo seu número de grupo.

  4. Ative a classe ABAP e execute-a como um app de console. Se a saída do console contiver erros, ajuste a definição de suas tabelas de banco de dados até que elas sejam compatíveis com as definições de tabela de banco de dados /LRN/EMPLOY_REL e LRN/DEPMENT_REL.

    1. Pressione Ctrl + F3 para ativar o objeto de desenvolvimento.

    2. Pressione F9 para executar a classe ABAP como app de console.

    3. Certifique-se de que a saída do console contém o texto Tabela preenchida ... para ambas as tabelas de banco de dados.