java 如何使用 Spring Data JPA 查询 Map 值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26245351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to query for Map values with Spring Data JPA?
提问by Petar Tahchiev
so my database model goes like this: I have Store
s and every Store
has a localized name. So I have chosen to represent the localized name as a Map
like this:
所以我的数据库模型是这样的:我有Store
s 并且每个Store
都有一个本地化的名称。所以我选择将本地化名称表示为Map
这样:
public class Store {
private Map<Locale,LocalizedValue> name;
}
as you can see it's a Map of <Locale, LocalizedValue>
where the LocalizedValue
is a class like this:
正如你所看到的,它是一个地图,<Locale, LocalizedValue>
其中LocalizedValue
是这样的一个类:
@Embeddable
public class LocalizedValue {
@Column(name = "value")
private String value;
}
and it all works great. However I get to a problem where I want to query my Spring Data JPA repository and find all the stores with a given english name. So my repository method looks like this:
这一切都很好。但是我遇到了一个问题,我想查询我的 Spring Data JPA 存储库并找到具有给定英文名称的所有商店。所以我的存储库方法如下所示:
Store findByName(Map.Entry<Locale, LocalizedValue> name);
but it throws this 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)
So then I changed my repository method to be like this:
然后我将我的存储库方法更改为如下所示:
Store findByName(LocalizedValue name);
but then I got this exception:
但后来我得到了这个例外:
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)
I also tried using Contains in the query method - still no luck.
我还尝试在查询方法中使用 Contains - 仍然没有运气。
So my question is: Is there a way to query for the stores with English name 'Some Value'?
所以我的问题是:有没有办法查询英文名称为“Some Value”的商店?
回答by Oliver Drotbohm
This requires a manually defined query something like this:
这需要一个手动定义的查询,如下所示:
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);
}
It basically tells the persistence provider to expand the map values and check whether the given parameter is in the list of expanded values.
它基本上告诉持久性提供者扩展映射值并检查给定参数是否在扩展值列表中。
回答by Alan Hay
You have not posted your mappings but there seems to me to be a fundamental issue with way that Embeddables are keyed.
您还没有发布您的映射,但在我看来,嵌入式键控方式存在一个基本问题。
This is the only obvious way I can see to map the association:
这是我能看到的映射关联的唯一明显方法:
@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;
}
}
The following test passes:
以下测试通过:
@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));
}
The issue with this is however that 'Locale' can never be a property of LocalisedName otherwise Hibernate complains of a duplicate column mapping. See the bug report:
然而,问题在于“Locale”永远不能是 LocalisedName 的属性,否则 Hibernate 会抱怨重复的列映射。查看错误报告:
https://hibernate.atlassian.net/browse/HHH-5393
https://hibernate.atlassian.net/browse/HHH-5393
So while it is possible to write a query method:
因此,虽然可以编写查询方法:
public interface StoreRepository extends JpaRepository {
公共接口 StoreRepository 扩展 JpaRepository {
@Query(value = "from Store s join s.names n where n.name = ?1")
Store findByName(String name);
}
}
for which the following test passes
以下测试通过
@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));
}
as far as I can see this can never take Locale into account as it is not a property of LocalizedName.
据我所知,这永远不会考虑 Locale,因为它不是 LocalizedName 的属性。