2013-05-14 1 views
11

J'ai deux configurations de fèves Entitymanager. Chaque pointant vers une base de données séparée avec un schéma différent (l'un est Oracle, l'autre est un H2 en mémoire)Ressource JPA: référentiels pour plusieurs configurations base de données/Entitymanger

Que pourrais-je faire pour résoudre l'ambiguïté de ce que Entitymanager devrait être utilisé pour chaque Repository? En ce moment, je reçois cette erreur:

No unique bean of type [javax.persistence.EntityManagerFactory] is defined: 
expected single bean but found 2 

Je suppose que je pourrais fournir une solution rapide en utilisant simplement quelque chose comme

<jpa:repositories base-package="com.foo.repos.ora" 
entity-manager-factory-ref="entityManagerFactoryA"> 

<jpa:repositories base-package="com.foo.repos.m2" 
entity-manager-factory-ref="entityManagerFactoryB"> 

Mais nous espérons qu'il ya une meilleure solution.

EDIT:

Je vous donne une idée du scénario actuel:

Spring-Config: il sont deux EM

<jpa:repositories base-package="com.foo.repos.ora" entity-manager-factory-ref="entityManagerFactory"/> 
<jpa:repositories base-package="com.foo.repos.m2" entity-manager-factory-ref="entityManagerFactory2"/> 
<context:component-scan base-package="com.foo" /> .... 

Tout à partir d'ici est en « package com.foo.repos.ora " Suivant le modèle de how to make a custom repository je reçois deux interfaces 'ARepository', 'ARepositoryCustom' et son implémentation 'ARepositoryImpl' comme

@Repository 
public interface ARepository extends ARepositoryCustom, JpaRepository<myEntity, BigDecimal>, QueryDslPredicateExecutor { 

} 

public interface ARepositoryCustom { 
    FooBar lookupFooBar() 
} 

public class ARepositoryImpl extends QueryDslRepositorySupport implements ARepositoryCustom { 
    ARepositoryImpl(Class<?> domainClass) { 
     super(domainClass.class) 
    } 

    ARepositoryImpl() { 
     this(myEntity.class) 
    } 

    @Override 
    FooBar lookupFooBar() { 
     JPQLQuery query = .... 
     .... 
     return found 
    } 
} 

résultant dans le message d'erreur suivant:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'aRepositoryImpl': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2

Ce qui est bien sûr correct, il y a 2 haricots EM, mais depuis que je restreint EM # 1 alias 'EntityManagerFactory' au package « com.foo .repos.ora 'seulement, je ne suis toujours pas sûr de savoir comment référencer le bean EM exact.

Répondre

13

Il n'y a pas de magie sous le capot.

<jpa:repositories base-package="com.foo.repos.ora" entity-manager-factory-ref="entityManagerFactory"/> 

ne vous aide pas du tout avec vos implémentations d'interface personnalisées. Le meilleur moyen que j'ai trouvé est de traiter vos implémentations personnalisées comme des haricots réguliers. Donc, je définissais un « sharedEntitManager » haricot dans ma configuration de printemps comme si

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     ... 
</bean> 
<bean id="sharedEntityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean"> 
     <property name = "entityManagerFactory" ref="entityManagerFactory"/> 
</bean> 

Après cela, je simplement réinjecté la EntityManager dans mes grains de mise en œuvre

<bean id="aRepositoryImpl" class="comm.foo.repos.ora.ARepositoryImpl"> 
    <property name="entityManager" ref="sharedEntityManager"/> 
</bean> 

Le « -manager-usine-ref entité » attribut établit une distinction entre les différentes fabriques d'entité mais uniquement pour les référentiels de données Spring (c'est-à-dire uniquement pour les interfaces). Il ne se préoccupe cependant pas de vos implémentations.

En résumé

1) si vous comptez tout simplement sur les référentiels standards Spring données sans implémentation personnalisée, utilisez l'attribut « entité-manager-usine-ref » pour différencier les bases de données. 2a) De plus, si vous utilisez une implémentation personnalisée, injectez le EntityManager approprié directement dans la classe d'implémentation. Le câblage est fait sous le contrôle de votre configuration printanière. Pour une raison quelconque, je n'ai pas pu utiliser l'annotation @Autowire avec un @Qualifier pour référencer l'EntityManager correct.EDIT Je viens d'apprendre sur l'annotation @Resource

@Resource(name = "sharedEntityManagerA") 
EntityManager entityManager 


<bean id="sharedEntityManagerA" name="sharedEntityManagerA" class="org.springframework.orm.jpa.support.SharedEntityManagerBean"> 
     <property name = "entityManagerFactory" ref="entityManagerFactory"/> 
</bean> 

Avec cette sélection à portée de main ce que EntityMAnger doit être utilisé devient simple. Pas besoin de plomberie tout togehther dans votre contexte xml.

2b) Comme alternative à la configuration XML de printemps pour brancher vos trucs vous pouvez également aller avec

@PersistenceContext(unitName = "nameOfPersistenceUnit")

pour injecter le EntityManagerFactory correct

Alors que « nameOfPersistenceUnit » référés à votre persévérance assis dans votre standard JPA persistence.xml

Cependant 2b) ne va pas bien avec 'QueryDslRepositorySupport', car il attend une instance EntityManager. Mais j'ai trouvé que 'QueryDslRepositorySupport' n'offre pas beaucoup de support de toute façon, alors je l'ai supprimé.

+0

2b) fonctionne également comme un charme si vous avez deux 'LocalContainerEntityManagerFactoryBean's dans votre contexte d'application, chacun avec leur propre 'persistenceUnitName'. –

Questions connexes