JPA - Persistence Unit criada via código

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

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 ;

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

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…

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

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

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:
[code]
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();[/code]

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.

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.

Alguém…?

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

Sugiro uma POG

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

O que vocês acham? :mrgreen:

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?

[quote=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
[/quote]

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!

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

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

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

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.

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?

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