Pergunta

Nas tabelas de banco de dados legadas, numeramos colunas como C1, C2, C3, C100 ou M1, M2, M3, M100.
Estas colunas representam dados do blob.

Não é possível alterar qualquer coisa neste banco de dados.

Ao usar o JPA incorporável, mapeamos todas as colunas para campos únicos. E, durante a incorporação, substituímos os nomes usando 100 anotações de substituição.

Recentemente, mudamos para Hibernate e encontrei coisas como UserCollectionType e CompositeUserType. Mas eu não encontrei nenhum caso de uso próximo ao meu.

É possível implementar algum tipo de usuário usando o Hibernate para poder mapear um pacote de colunas para uma coleção sem consulta adicional?

Editar:
Como você provavelmente notou, os nomes das colunas podem diferir de tabela para tabela. Quero criar um tipo como "LegacyArray", sem a necessidade de especificar todas as @columns cada vez que uso esse tipo. Mas em vez disso eu usaria

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "A"),
      @Parameter(name = "size", value = "128")
   })
   List<Integer> legacyA;

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "B"),
      @Parameter(name = "size", value = "64")
   })
   List<Integer> legacyB;
Foi útil?

Solução

Eu posso pensar em algumas maneiras de fazer isso.

1. Crie visualizações para as informações de coleta que simulam uma estrutura de tabela normalizada e mapeá -las para hibernar como uma coleção:

Supondo que sua tabela existente seja chamada primaryentity, Eu criaria uma visão semelhante ao seguinte:

-- untested SQL...
create view childentity as
(select primaryentity_id, c1 from primaryentity union
select primaryentity_id, c2 from primaryentity union
select primaryentity_id, c3 from primaryentity union
--...
select primaryentity_id, c100 from primaryentity)

Agora da perspectiva de Hibernate, childentity é apenas uma tabela normalizada que tem uma chave estrangeira para primarykey. Mapeando isso deve ser bastante direto e está coberto aqui:

Os benefícios dessa abordagem:

  • Do ponto de vista do hibernato, as mesas são normalizadas, é um mapeamento bastante simples
  • Sem atualizações para suas tabelas existentes

As desvantagens:

  • Os dados são somente leitura, não acho que sua visão possa ser definida de maneira atualizável (eu poderia estar errado)
  • Requer alterações no banco de dados, pode ser necessário criar muitas visualizações

Como alternativa, se o seu DBA nem permitirá adicionar uma visão ao banco de dados ou se precisar executar atualizações:


2. Use o hibernato instalação de mapeamento de modelo dinâmico Para mapear suas propriedades C1, C2, C3 para um Mapa, e tenha algum código para você seu Dao Camada faça a conversa apropriada entre o mapa e a propriedade de coleção:

Eu nunca fiz isso sozinho, mas acredito que o Hibernate permite que você mapeie as tabelas para os hashmaps. Não tenho certeza de quão dinamicamente o Hibernate permite que você faça isso (ou seja, você pode se safar simplesmente especificando o nome da tabela e com o Hibernate mapear automaticamente todas as colunas?), Mas é outra maneira de pensar em fazer isso.

Se estiver com essa abordagem, não se esqueça de usar o Objeto de acesso a dados padrão e verifique se a implementação interna (uso de hashmaps) está oculta do código do cliente. Verifique também antes de escrever no banco de dados se o tamanho da sua coleção não excede o número de colunas disponíveis.

Os benefícios dessa abordagem:

  • Nenhuma alteração no banco de dados
  • Os dados são atualizáveis
  • O mapeamento de o/r é relativamente simples

As desvantagens:

  • Muito encanamento na camada DAO para mapear os tipos apropriados
  • Usa recursos experimentais de hibernato que podem mudar no futuro

Outras dicas

Pessoalmente, acho que o design parece quebrar Primeira forma normal Para bancos de dados relacionais. O que acontece se você precisar de C101 ou M101? Mudar seu esquema de novo? Eu acho que é muito intrusivo.

Se você adicionar hibernado à mistura, é ainda pior. Adicionar C101 ou M101 significa ter que alterar seus objetos Java, seus mapeamentos de hibernato, tudo.

Se você tiver relacionamentos 1: M com tabelas C e M, poderá lidar com os casos que acabei de citar adicionando linhas adicionais. Seus objetos Java contêm coletau003CC> ou coleçãou003CM> . Seus mapeamentos de hibernato são um para muitos que não mudam.

Talvez o motivo pelo qual você não veja nenhum exemplo de hibernação para corresponder ao seu caso, porque é um design que não é recomendado.

Se você deve, talvez você deva olhar para Mapeamento de componentes de hibernato.

ATUALIZAÇÃO: O fato de esse ser legado é devidamente observado. Meu argumento em trazer à tona a primeira forma normal é tanto para outras pessoas que podem encontrar essa pergunta no futuro como para a pessoa que postou a pergunta. Eu não gostaria de responder à pergunta de tal maneira que ela silenciosamente afirmou esse design como "bom".

Apontar o mapeamento de componentes de hibernato é pertinente, porque saber o nome do que você está procurando pode ser a chave quando você está pesquisando. O Hibernate permite que um modelo de objeto seja mais fino do que o modelo relacional que ele mapeia. Você é livre para modelar um esquema desnormalizado (por exemplo, nome e endereço como parte de um objeto de pessoa maior). Esse é apenas o nome que eles dão essa técnica. Pode ajudar a encontrar outros exemplos também.

Desculpe se estou entendendo mal o seu problema aqui, não sei muito sobre o hibernado. Mas você não poderia apenas concatenar durante a seleção do banco de dados para obter algo como o que deseja?

Curti:

SELECT whatever
     , C1||C2||C3||C4||...||C100 AS CDATA
     , M1||M2||M3||M4||...||M100 AS MDATA
FROM ...
WHERE ...

(Obviamente, o operador de concatenação difere entre RDBMSs.)

Editar] Eu sugiro usar um CompositeUserType. Aqui está um exemplo. Há também um bom exemplo na página 228f no livro "Java Persistence with Hibernate".

Isso permite que você lide com as muitas colunas como um único objeto em Java.

O mapeamento se parece com o seguinte:

@org.hibernate.annotations.Columns(columns = {
    @Column(name="C1"),
    @Column(name="C2"),
    @Column(name="C3"),
    ...
})
private List<Integer> c;

O Hibernate carregará todas as colunas de uma só vez durante a consulta normal.

No seu caso, você deve copiar os valores int da lista para um número fixo de colunas em nullSafeSet. Pseudo-código:

for (int i=1; i<numColumns; i++)
    if (i < list.size())
        resultSet.setInt(index+i, list.get(i));
    else
        resultSet.setNull(index+i, Hibernate.INTEGER.sqlType());

Dentro nullSafeGet Você deve criar uma lista e parar de adicionar elementos quando uma coluna é nula. Para segurança adicional, sugiro criar sua própria implementação de lista que não permita crescer além do número de colunas (herdar de ArrayList e substituir ensureCapacity()).

Edit2] Se você não deseja digitar todas as anotações @Column, use um gerador de código para eles. Isso pode ser tão simples quanto script que você fornece um nome e um número e imprime @column (...) para system.out. Depois que o script foi executado, basta cortar e colar os dados na fonte.

A única outra solução seria acessar a API interna do Hibernate para criar essas informações em tempo de execução, mas essa API é interna, então muitas coisas são privadas. Você pode usar a reflexão Java e setAccessible(true) Mas esse código provavelmente não sobreviverá à próxima atualização do Hibernate.

Você pode usar UserTypes para mapear um determinado número de colunas para qualquer tipo que desejar. Isso pode ser uma coleção se (por exemplo) para coleções for sempre limitado em tamanho por um número conhecido de itens.

Já faz um tempo (> 3 anos) desde que usei o hibernado, por isso estou muito enferrujado, mas lembro -me de ser muito fácil de fazer; sua BespokeUserType aula é passada pelo ResultSet para hidrato seu objeto dele.

Eu também nunca usei o Hibernate.

Eu sugiro escrever um pequeno programa em um idioma interpretado (como Pitão) em que você pode executar uma string como se fosse um comando. Você pode construir uma declaração que tira o trabalho tedioso fazendo o que deseja fazer manualmente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top