2016-08-19 54 views
11

我有以下的持久类:使用Hibernate的标准地图中的过滤键和值

public class Code { 

    @ElementCollection(targetClass = CodeValue.class) 
    @MapKeyClass(CodeProperty.class) 
    @JoinTable(name="code_properties") 
    @CreateIfNull(value = false) 
    private Map<CodeProperty,CodeValue> propertiesMap = 
     new HashMap<CodeProperty, CodeValue>(); 

    ... 
} 

public class CodeProperty { 
    private String name; 
    ... 
} 

public class CodeValue { 
    private String value; 
    ... 
} 

而我试图让一些性质我propertiesMap在过滤代码列表(例如其中,财产名为“颜色”的码的值是“绿色”

我用下面的底座标准:

Criteria criteria = currentSession() 
    .createCriteria(Code.class, "code") 
    .setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 

当我尝试执行收集过滤器(如建议here):

criteria.createAlias("code.properties", "p"); 
criteria.add(Restrictions.eq("p.foo", "test1")); 
criteria.setFetchMode("code.properties", FetchMode.JOIN); 
criteria.list(); 

我得到以下错误:

org.hibernate.QueryException: could not resolve property: foo of: com.example.CodeValue 

这意味着,我真的不明白为什么,Hibernate是考虑到code.properties地图CodeValue代替!

我也尝试访问这个字段而不创建别名,并且这种方式冬眠似乎访问了正确的代码类。我用properties.indeces(如建议here):

criteria.add(Restrictions.eq("properties.indeces", "foo")); 
criteria.list(); 

但有了这个,我得到了以下错误:

could not resolve property: properties.indeces of: com.example.Code 

有人可以帮助我了解什么是错?正确的标准查询将以绿色找到代码是什么?您可以结帐the Github project that demonstrates this problem

感谢

+0

我注意到你正在使用@MapKeyClass的JPA 2.1特性。您是否一定会使用弃用的Hibernate Criteria API而不是JPA Criteria API? – Naros

+0

@Naros代表micdcar回答 - 是的,不幸的是,这意味着将整个sessionfactory配置切换到entitymanager,这可以被探索,但不会在如此短的时间内发布。因此,我们必须创建标准,它返回一个休眠条件。 – mmalmeida

回答

1

我不相信你可以与遗留Hibernate API的标准做到这一点,有一个与使用JPA标准API Hibernate的实现一个小的限制。解决的方法之一是:

直接查询该实体与谓语的要求得到一个List<CodeProperty>

List<CodeProperty> propertyKeys = entityManager 
    .createQuery("FROM CodeProperty p WHERE p.name = :name") 
    .setParameter("name", "foo") 
    .getResultList(); 

查询使用JPA标准的Code实体。

// setup the query 
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
CriteriaQuery<Code> query = cb.createQuery(Code.class); 
Root<Code> root = query.from(Code.class); 
MapJoin<Code, CodeProperty, CodeValue> mapRoot = root.joinMap("propertiesMap"); 
query.select(root).where(mapRoot.key().in(propertyKeys)); 

// get results 
List<Code> results = entityManager.createQuery(query).getResultList(); 

我试着用这些来组合:

query 
    .select(root) 
    .where (cb.eq(mapRoot.key().get("name"), "foo")) 

问题是这样导致NotYetImplemented例外:(。

1

请确认您是否使用过的indeces曾在预测问题或指数。正确的用法如下:

criteria.createAlias("code.properties", "p"); 
criteria.add(Restrictions.eq("p.indices", "foo")); 
criteria.list(); 

或者,您可以在限制使用

eq("p." + CollectionPropertyNames.COLLECTION_INDICES) 

请让我知道它是否仍然不适合你。

1

您的方法存在各种问题: 在您的项目中观看MapTest文件夹github我建议您始终将变量名称作为列名称,并在条件中使用这些相同的名称。 标准是地图,其第一个参数是属性名称,第二个参数是属性值。 对于多对多的关系,你可以尝试使用:

@JoinTable(
     name="docente_classe", 
     joinColumns= 
      @JoinColumn(name="id_dipendente", referencedColumnName="id_dipendente"), 
     inverseJoinColumns= 
      @JoinColumn(name="id_classe", referencedColumnName="id_classe") 
) 

这是JPA注解,我不知道这是否编译您的项目。

https://github.com/tredue1/School_Manager/blob/master/code/SM/src/main/java/agc2/it/sm/gestioneDocente/DocenteJpa.java

对于查询的多对多的关系看这个帖子:

jpa criteria for many to many relationship

+0

对不起,我没跟着。你的例子没有任何地图。 查询通过集合实现多对多是不同的事情。 您能否使用GitHub示例(或项目分支)来澄清您的答案? – mmalmeida

+0

你有没有尝试检查链接:http://stackoverflow.com/questions/8135612/jpa-criteria-for-many-to-many-relationship ????这是一个很好的例子。 – pioardi