2014-10-07 5 views
5

so mein Datenbankmodell geht so: Ich habe Store s und jeder Store hat einen lokalisierten Namen. So habe ich gewählt, um den lokalisierten Namen als Map wie folgt darstellen:Wie Abfragen von Kartenwerten mit Spring Data JPA?

public class Store { 
    private Map<Locale,LocalizedValue> name; 
} 

wie Sie es ist eine Karte von <Locale, LocalizedValue> sehen kann, wo die LocalizedValue ist eine Klasse wie folgt aus:

@Embeddable 
public class LocalizedValue { 

    @Column(name = "value") 
    private String value; 
} 

und alles funktioniert super. Allerdings komme ich zu einem Problem, bei dem ich mein Spring Data JPA-Repository abfragen und alle Stores mit einem bestimmten englischen Namen finden möchte. So sieht mein Repository Methode wie folgt:

Store findByName(Map.Entry<Locale, LocalizedValue> name); 

aber es wirft diese Ausnahme:

2014-10-07 23:49:55,862 [qtp354231028-165] ERROR: Parameter value [en=Some Value] did not match expected type [com.test.LocalizedValue(n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [en=Some Value] did not match expected type [com.test.LocalizedValue (n/a)] 
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [en=Some Value] did not match expected type [com.test.LocalizedValue (n/a)]; 
nested exception is java.lang.IllegalArgumentException: Parameter value [en=Some Value] did not match expected type [com.test.LocalizedValue (n/a)] 
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:384) 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:216) 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417) 
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) 
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) 

Also änderte ich meine Repository Methode wie folgt zu sein:

Store findByName(LocalizedValue name); 

aber dann habe ich habe diese Ausnahme:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'name1_.pk' in 'where clause' 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526) 

Ich habe auch versucht, Enthält in der Abfrage-Methode - immer noch kein Glück.

Also meine Frage ist: Gibt es eine Möglichkeit, für die Geschäfte mit dem englischen Namen 'Some Value' abzufragen?

Antwort

7

Dies erfordert eine manuell definierte Abfrage etwas wie folgt aus:

interface StoreRepository extends Repository<Store, Long> { 

    @Query("select s from Store s join s.map m where ?1 in (VALUE(m))" 
    Optional<Store> findByName(String name); 
} 

Es im Grunde die Persistenz-Provider erzählt die Kartenwerte zu erweitern und prüfen, ob der angegebene Parameter in der Liste der erweiterten Werte ist.

+2

Danke für Ihre Antwort. Ist dies in Spring JPA dokumentiert? Wo kann ich mehr Informationen darüber erhalten, wie die Map-Werte durch Spring JPA erweitert werden? – Sharadr

+0

Kann das auch mit Collection-Parameter gemacht werden? – mihn

1

Sie haben Ihre Mappings nicht veröffentlicht, aber es scheint mir ein grundsätzliches Problem mit der Art zu sein, dass Embeddables verschlüsselt werden.

Dies ist die einzige offensichtliche Weise, die ich den Vereins zur Karte sehen kann:

@Entity 
@Table(name = "stores") 
public class Store { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private Long id; 

    @ElementCollection 
    @CollectionTable(name = "store_names", joinColumns = @JoinColumn(name = "store_id")) 
    @MapKeyColumn(name = "locale") 
    private Map<Locale, LocalizedName> names; 

    public Map<Locale, LocalizedName> getNames() { 
     return names; 
    } 

    public String getName(Locale locale) { 
     return names.get(locale).getName(); 
    } 
} 


@Embeddable 
public class LocalizedName { 

    @Column(name = "name") 
    private String name; 

    @SuppressWarnings("unused") 
    private LocalizedName() { 

    } 

    public LocalizedName(String name) { 
     this.name = name; 
    } 

    public String getName(){ 
     return name; 
    } 
} 

Der folgende Test bestanden:

@Test 
public void testLoadStore() { 
    Store store = repository.findOne(1l); 
    Assert.assertNotNull(store); 
    Assert.assertEquals("EN Name", store.getName(Locale.ENGLISH)); 
    Assert.assertEquals("DE Name", store.getName(Locale.GERMAN)); 
} 

Das Problem dabei ist jedoch, dass ‚Locale‘ nie sein kann eine Eigenschaft von LocalisedName, sonst klagt Hibernate über eine doppelte Spaltenzuordnung. Sehen Sie den Fehlerbericht:

https://hibernate.atlassian.net/browse/HHH-5393

So, während es möglich ist, eine Abfragemethode zu schreiben:

öffentliche Schnittstelle StoreRepository erweitert JpaRepository {

@Query(value = "from Store s join s.names n where n.name = ?1") 
Store findByName(String name); 

}

, für die der folgender Test besteht aus

@Test 
public void testLoadByName() { 
    Store store = repository.findByName("EN Name"); 
    Assert.assertNotNull(store); 
    Assert.assertEquals("EN Name", store.getName(Locale.ENGLISH)); 
    Assert.assertEquals("DE Name", store.getName(Locale.GERMAN)); 
} 

Soweit ich sehen kann, kann dies niemals Gebietsschema berücksichtigen, da es keine Eigenschaft von LocalizedName ist.

+0

Nein, natürlich wird es nicht funktionieren - Sie geben das Gebietsschema nie an. Ich habe es ausprobiert und ich bekomme: "Parameter Wert [Einige Wert] nicht übereinstimmen erwarteten Typ [com.test.LocalizedValue (n/a)];" –

+0

Siehe aktualisierte Antwort. –

Verwandte Themen