2013-05-14 10 views
11

Ich habe zwei Entitymanager Bean-Konfigurationen. Jeder zeigt auf eine separate Datenbank mit einem anderen Schema (einer ist Oracle, der andere ist ein In-Speicher H2)Spring Data JPA: Repositories für mehrere Datenbank/Entitymanger-Konfigurationen

Was könnte ich tun, um die Ambiguität zu lösen, welcher Entitymanager für jedes Repository verwendet werden sollte? Im Moment bin ich immer diese Fehlermeldung:

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

Ich denke, ich einfach eine schnelle Lösung bieten könnte durch so etwas wie

<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"> 

mit Aber hoffentlich gibt es eine bessere Lösung.

EDIT:

Ich gebe Ihnen eine Vorstellung von dem aktuellen Szenario:

Frühling-Config: Es sind zwei 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" /> .... 

Alles von hier ist in „-Paket com.foo.repos.ora " Nach dem Muster von how to make a custom repository bekomme ich zwei Schnittstellen 'ARepository', 'ARepositoryCustom' und seine Implementierung 'ARepositoryImpl' wie so

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

in der folgenden Fehlermeldung resultierende:

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

Was natürlich richtig ist, gibt es 2 EM Bohnen, aber da ich EM # 1 aka 'EntityManagerFactory' beschränkt zu verpacken ‚com.foo .repos.ora 'nur, ich bin mir immer noch nicht sicher, wie man die genaue EM Bohne referenziert.

Antwort

13

Es gibt keine Magie unter der Haube.

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

hilft Ihnen überhaupt nicht mit Ihren benutzerdefinierten Schnittstellenimplementierungen. Der beste Weg, den ich gefunden habe, ist, Ihre benutzerdefinierten Implementierungen als normale Beans zu behandeln. Also habe ich eine 'sharedEntitManager' Bean definiert in meiner Federkonfiguration wie so

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

Danach habe ich injiziert einfach die EntityManager in meine Implementierung Bohnen

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

Die 'Entity-Manager-Fabrik-ref' Attribut diskriminiert zwischen verschiedenen Entitymanager-Factorys, aber nur für direkte Spring Data Repositories (dh nur für Interfaces). Es betrifft jedoch keine Ihrer Implementierungen.

Um es zusammenzufassen

1), wenn Sie einfach auf Standard-Spring Data Repositories ohne benutzerdefinierte Implementierung verlassen, verwenden Sie die "Entity-Manager-Fabrik-ref" -Attribut Datenbanken zu unterscheiden.

2a) Zusätzlich, wenn Sie eine benutzerdefinierte Implementierung verwenden, injizieren Sie den entsprechenden EntityManager direkt in die implementierende Klasse. Wirering wird unter Kontrolle Ihrer Spring Xml-Konfiguration durchgeführt. Aus irgendeinem Grund konnte ich die @Autowire Annotation nicht mit einem @Qualifier verwenden, um auf den richtigen EntityManager zu verweisen.EDIT ich gerade gelernt, über die @Resource Anmerkung

@Resource(name = "sharedEntityManagerA") 
EntityManager entityManager 


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

Damit bei der Hand der Auswahl, was EntityMAnger verwendet werden soll, wird einfach. Keine Notwendigkeit, alles zusammen in Ihrem Kontext xml zu plombieren.

2b) Als Alternative zu Spring XML-Konfiguration für Ihre Sachen Einhaken können Sie mit

@PersistenceContext(unitName = "nameOfPersistenceUnit")

gehen auch die richtige EntityManagerFactory

zu injizieren, während ‚nameOfPersistenceUnit‘ referes auf Ihre Sitzung Persistenz in Ihrem Standard JPA persistence.xml

Allerdings funktioniert 2b) nicht gut mit 'QueryDslRepositorySupport', da es eine EntityManager-Instanz erwartet. Aber ich habe festgestellt, dass "QueryDslRepositorySupport" sowieso nicht viel Unterstützung bietet, also habe ich es entfernt.

+0

2b) funktioniert auch wie ein Charme, wenn Sie zwei 'LocalContainerEntityManagerFactoryBean's in Ihrem Anwendungskontext haben, jedes mit ihrem eigenen 'persistenceUnitName'. –