JPA - Persistence Unit criada via código

17 respostas
F

Boa tarde,

Estou trabalhando em uma aplicação usando JPA (Toplink) e PostgreSQL onde preciso conectar em várias bases de dados diferentes que inclusive poderão ser adicionadas e configuradas depois que o sistema estiver rodando.
O problema é que eu não tenho como colocar isso no persistence.xml porque a princípio não sei quantas bases serão usadas. Por isso pensei em criar dinamicamente as persistence units ou então usar a mesma persistence unit e apenas mudar a propriedade URL (colocando o IP no qual quero conectar).
Procurei por todo o google e na documentação do toplink mas não encontrei nada a respeito sobre desconsiderar o XML e criar a persistence unit no código…
Usando a mesma persistence unit e mudando apenas a propriedade URL a JPA tem me retornado uma outra fábrica (como era esperado) porém esta outra fábrica aponta para o mesmo banco anterior, ou seja, as propriedades que foram passadas são desconsideradas (talvez por ser a mesma persistent unit).

Alguém tem alguma sugestão pra este tipo de situação?

Att,
Fred

17 Respostas

K

Nao sei se entendi direito a sua duvida …
Mas acredito que essa seja a solucao:

Se esta usando EJB3 (Nao sei se 2.1 eh possivel) use injecao de dependecia

@PersistenceUnit EntityManagerFactory emf ;

T

Nã não no EJB2.x isso não é possível rs

T

E não há grandes problemas em usar PUs assim… O único que vejo é que vc tira do containes a responsablidade de gerenciar seu contexto de persistência…

F

Na verdade é uma aplicação desktop. Toda a camada de persistência já está implementada e funcionando bem. O problema é que agora surgiu este requisito de poder conectar em bases de dados diferentes. Ex.:
O usuário da Loja 1 antes de efetuar login escolhe se quer logar na base de dados da sua loja ou de outra filial qualquer. Existe um combobox listando as lojas e quando ele selecionar alguma eu tento efetuar a conexão pra aquela base de dados. Ao carregar a tela de login eu mando por parâmetro uma lista com objetos lojas que contêm a URL da base de dados. Essa lista de lojas é carregada a partir de um arquivo de configurações que fica junto com a aplicação.
O problema é que como eu não sei a princípio quantas lojas serão, eu não posso criar uma persistence unit pra cada… O ideal seria obter a minha EntityManagerFactory através de uma persistence unit criada via código e abandonar o persistence.xml.
Pesquisei em vários lugares e não encontrei como fazer isso. Se alguém tiver uma pista a respeito fico muito grato se puder compartilhar.

Att,
Fred

K

@PersistenceUnit EntityManagerFactory mf

EntityManagerFactory emf = Persistence.createEntityManagerFactory(“NOME”);
EntityManager em = emf.createEntityManager(); // Aqui se cria o Contexto de persistencia extendido.

Bom, agora acredito que esta solucionado.

Espero ter ajudado.

F
EntityManagerFactory emf = Persistence.createEntityManagerFactory("NOME");
Mas aí que tá, o problema é que eu não tenho o "NOME" da persistence unit, pois vários bancos poderão ser adicionados em tempo de execução. Daí o desafio está em criar uma persistence unit via código e passar para o createEntityManagerFactory e então obter o EntityManager para aquele banco. Seria algo como isso:
MinhaPersistenceUnit pu = ClasseQueCriaPersistenceUnit.criarPersistenceUnit();
pu.setPersistenceProvider(oracle.toplink.essentials.PersistenceProvider);
pu.setName("MinhaPersistenceUnitCriadaViaCodigo");
pu.setTransactionType("RESOURCE_LOCAL");
pu.setClasses(arrayDeClasses);
pu.setProperties(propriedades);
pu.setOutrasConfiguracoes(outrasConfiguracoes);
EntityManagerFactory emf = Persistence.createEntityManagerFactory(pu); // Tudo bem, eu sei que esse método só recebe String e um Map, mas seria interessante se pudesse funcionar assim tb não é?  :) 
// Além do mais, se houver um método que liga uma persistence unit recém criada a um nome, que então será passado pra ele tb resolveria
EntityManager em = emf.createEntityManager();

Mas pelo que tenho pesquisado parece que a JPA não fornece esse recurso.... Minha esperança é que as extensões do toplink forneçam.
Se existir uma possibilidade de fazer algo parecido com o que demonstrei aí em cima, o xml pode ser abolido da JPA.
Se não for possível acho que vou ter que apontar um local alternativo para o persistence.xml, editar esse xml em tempo de execução pra criar novas persistence units e então recarregar minha factory. Só que isso me cheira a gambiarra.... Seria muito melhor se a JPA permitisse o que eu acabei de descrever.

F

Alguém…?

J

se não me engano vc pode ter N persistenceUnits ecarregar o que vc quer em tempo de execução.
se vc tem 5 opções de banco, crie 5 persistenceUnit e carregue o que foi selecionado.
talvez funcione.

[]´s

Q

Sugiro uma POG

EntityManagerFactory emf = Persistence.createEntityManagerFactory(getProperty("bancodedados.selecionado"));

O que vocês acham? :mrgreen:

T

Olá pessoal. Estou tranbalhando com EJB3 e estou com um probleminha de relacionamento OneToMany. O meu entity tem 3 relacionamentos OneToMany, cada entity desse relacionado com o principal tem o UID(chava primaria) no entity ou seja relacionamento unidirecional, eu estou persistindo da seguinte forma. Pego todas as collections e “seto” elas no entity principal. No final do metodo eu do um persist(entity). Os registros são persistidos na base certinho, só que nos relacionamentos o campo onde deveria aparecer a chave primária do entity principal fica nulo, ele não atualiza com o entity principal. Alguem já passou por isso?

F

jgbt:
se não me engano vc pode ter N persistenceUnits ecarregar o que vc quer em tempo de execução.
se vc tem 5 opções de banco, crie 5 persistenceUnit e carregue o que foi selecionado.
talvez funcione.

[]´s

Nós estamos fazendo isso, o problema é que dessa forma não podemos permitir que o próprio cliente adicione uma nova conexão apenas informando o IP por exemplo, e então veja em uma mesma tela informações vindas de N bases de dados porque a quantidade de persistence units (PU) será fixa, já que não conseguimos adicionar apenas pelo código, sem precisar do persistence.xml. Então somos obrigados a criar algumas PU no xml e com isso a quantidade de conexões possível fica sendo este número de PUs criadas.

O problema nesse caso é que a PU tb tem que existir previamente, e a quantidade de PUs continua fixa.

Encontrei um código que faz exatamente isso, mas infelizmente é pra hibernate e nós usamos toplink :cry:

http://www.pcal.net/blog/2007/04/dynamic-persist.html

Estou tentando achar uma forma de fazer isso com o toplink, se eu conseguir posto aqui o resultado. Mas se alguém souber o caminho das pedras e puder compartilhar eu agradeço! :smiley:

PS.: o ideal mesmo seria a JPA prover esse recurso! :frowning: Tomara que a próxima versão venha com isso!

M

Olá Fredi!
Desculpe desenterrar este tópico, mas estou com a mesma dúvida que vc:
Conseguiu resolver seu problema?
Estou com a mesma dificuldade aqui.
Preciso montar o persistence de acordo com parametros que tenho em um outro XML, que é criado na instalação do sistema, mediante a inserção de parametros pelo usuário.
Durante a instalação é informado o IP do servidor, user e senha…
No instalador é feita a instalação do MySQL, criação do user e senha definidos anteriormente
O passo seguinte seria colocar estes parametros que o usuário informou, dentro do persistence.xml
Isso é possível?
ou teremos que fazer um monte de menu comboBox com opções limitadas?

Valeu pela atenção

F

Olá! Na época, o projeto que precisava desta funcionalidade foi interrompido por outros motivos e não chegamos a resolver o problema.
Sinceramente, sei que JPA é o padrão, que promove abstração da ferramenta ORM mas… hoje, ao trabalhar com Java, tenho usado mais o Hibernate diretamente. Se lhe for permitido introduzir outra ferramenta ORM no projeto (imagino que esteja usando o TopLink com JPA) te aconselho a dar uma olhada no Hibernate. Vc vai conseguir trabalhar a conexão de forma mais programática sem ficar tão preso ao XML, além de ter alguns outros recursos interessantes promovidos pelo Hibernate. Não sei se a JPA 2 já saiu (tenho investido atualmente em RoR) e se ela possui todos os recursos do Hibernate. Se for o caso, então pode ser que valha a pena se manter no padrão com a JPA 2.

[]'s
Fred

M

Ok Fredi
Obrigado pela dica.
Vou pesquisar mais o hibernate.

H

Olá pessoal,

resolvi o problema usando da seguinte forma:

  1. configurando normalmente o arquivo persitence.xml, declaro uma persistence-unit apenas e apaga as linhas correspondentes a tag “properties”.






então declaro um mapa contendo os demais propriedades que exclui no passo anterior da seguinte forma:

Map mapa = new HashMap();

mapa.put(“javax.persistence.jdbc.url”, );

mapa.put(“javax.persistence.jdbc.user”, );

mapa.put(“javax.persistence.jdbc.password”, );

emf = Persistence.createEntityManagerFactory(“ManagerPU”, mapa);

Comigo funcionou.

E

hortevan sua solução funcionou certo? Mas quem está gerenciando as transações, você ou o container? Como você declarou o EntityManagerFactory, usou injeção de dependência ou faz isso manualmente?

C

Bom Dia.
Sei que o Tópico é antigo, mas a minha dúvida é exatamente a mesma, como criar unidade de persistência dinamicamente sem usar o persistence.xml.
Tem alguma possibilidade, o caso de uso que tenho que resolver é semelhante FredMP.
O servidor esta rodando é há varias databases. Quem administra o sistema pode criar novas databases(empresas novas que usarão o sistema), mas não terá acesso ao persistence.xml,
somente dará acesso a tal usuário a tal database. quando o usuário logar no sistema, o próprio sistema terá que conectar no banco de dados correto.
Desde já agradeço pela ajuda.
att

Criado 12 de dezembro de 2007
Ultima resposta 10 de fev. de 2012
Respostas 17
Participantes 10