2014-10-07 97 views
5

所以我的數據庫模型是這樣的:我有Store s和每個Store都有一個本地化的名稱。所以,我選擇了代表的本地化名稱作爲Map這樣的:如何使用Spring Data JPA查詢Map值?

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

,你可以看到這是一個地圖的<Locale, LocalizedValue>其中LocalizedValue是這樣一類:

@Embeddable 
public class LocalizedValue { 

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

而這一切效果很好。但是,我遇到了一個問題,我想查詢我的Spring Data JPA存儲庫並查找具有給定英文名稱的所有商店。所以,我的倉庫方法是這樣的:

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

但引發此異常:

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) 

於是我改變了我的資料庫的方法是這樣的:

Store findByName(LocalizedValue name); 

後來我得到這個例外:

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) 

我也嘗試在查詢方法中使用Contains - 仍然沒有運氣。

所以我的問題是:有沒有辦法查詢英文名稱爲「Some Value」的商店?

回答

7

這需要手動定義的查詢是這樣的:

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); 
} 

它基本上告訴持久性提供擴展映射值和檢查給定參數是否處於擴張值的列表。

+2

感謝您的回答。這是在Spring JPA中記錄的嗎?我在哪裏可以獲得更多關於Spring JPA如何擴展地圖值的信息。 – Sharadr 2017-02-27 09:05:22

+0

同樣可以用Collection參數來完成嗎? – mihn 2017-05-22 12:49:45

1

你還沒有發佈你的映射,但在我看來,嵌入式是鍵控的一個基本問題。

這是唯一明顯的方法,我可以看到映射的關聯關係:

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

下測試通過:

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

這個問題。然而這就是語言環境「絕不可能LocalisedName的一個屬性,否則Hibernate抱怨重複的列映射。見bug報告:

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

所以雖然可以編寫一個查詢方法:

公共接口StoreRepository擴展JpaRepository {

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

}

爲其以下測試通過

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

據我所見,這永遠不會考慮Locale,因爲它不是LocalizedName的屬性。

+0

不,當然它不會起作用 - 您從不指定區域設置。我試過了,我得到:「參數值[Some Value]與預期類型[com.test.LocalizedValue(n/a)]不匹配;」 – 2014-10-08 12:08:55

+0

查看更新的答案。 – 2014-10-08 19:28:29

相關問題