如何使用Spring Data JPA查询Map值?

所以我的数据库模型是这样的:我有Store ,每个Store都有一个本地化的名称。 所以我选择将本地化名称表示为这样的Map

 public class Store { private Map name; } 

你可以看到它是的Map,其中LocalizedValue是这样的类:

 @Embeddable public class LocalizedValue { @Column(name = "value") private String value; } 

这一切都很棒。 但是我遇到了一个问题,我想查询我的Spring Data JPA存储库并查找具有给定英文名称的所有商店。 所以我的存储库方法如下所示:

 Store findByName(Map.Entry name); 

但它抛出了这个exception:

  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’的商店?

这需要手动定义的查询,如下所示:

 interface StoreRepository extends Repository { @Query("select s from Store s join s.map m where ?1 in (VALUE(m))" Optional findByName(String name); } 

它基本上告诉持久性提供程序扩展映射值并检查给定参数是否在扩展值列表中。

你还没有发布你的映射,但在我看来,Embeddables是关键的一个基本问题。

这是我可以看到映射关联的唯一明显方式:

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

然而,问题是’Locale’永远不会是LocalisedName的属性,否则Hibernate会抱怨重复的列映射。 查看错误报告:

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的属性。