java JPA 一对多过滤
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13306235/
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
JPA one-to-many filtering
提问by Udo Held
We are nesting several entities. However upon retrieving we only want to get those entities which are active.
我们嵌套了几个实体。然而,在检索时,我们只想获取那些活动的实体。
@Entity
public class System {
@Id
@Column(name = "ID")
private Integer id;
@OneToMany(mappedBy = "system")
private Set<Systemproperty> systempropertys;
}
@Entity
public class Systemproperty {
@Id
@Column(name = "ID")
private Integer id;
@Id
@Column(name = "ACTIVE")
private Integer active;
}
When requesting the Systemproperties
I only want to get the properties that are active
(active = 1).
请求时,Systemproperties
我只想获取active
( active = 1)的属性。
Searching around I found some hibernate annotationsand the possibility to use subqueries. However both don't really work for me. Even though we are currently using hibernate I'm considering to replace it with Eclipselink, because we currently have to use eager loading and we are likely to run into performance problems with that. The subqueries don't really work well, because we are nesting several levels.
四处搜索我发现了一些休眠注释和使用子查询的可能性。然而,两者都不适合我。尽管我们目前正在使用 hibernate,但我正在考虑用 Eclipselink 替换它,因为我们目前必须使用预先加载,而且我们很可能会遇到性能问题。子查询并不能很好地工作,因为我们嵌套了几个级别。
Eclipselink seems to have a @Customizerannotation that could work, however it seems to follow a different concept then the hibernate @FilterDef
annotation and would cause additional overhead when switching.
Eclipselink 似乎有一个可以工作的@Customizer注释,但是它似乎遵循与休眠@FilterDef
注释不同的概念,并且在切换时会导致额外的开销。
The @JoinColumn
doesn't seem to allow further filtering. Is there a standard JPA way to solve this problem?
在@JoinColumn
似乎没有允许进一步的筛选。有没有标准的 JPA 方法来解决这个问题?
采纳答案by Adam Dyga
AFAIK there is no portable JPA-based way to do this. A clean, however a little bit inefficient, solution would be to do everything on Java-side and create a getter getActiveSystemproperties()
that manually iterates over mapped systempropertys
and returns an immutable set of active properties.
AFAIK 没有可移植的基于 JPA 的方法来做到这一点。一个干净但有点低效的解决方案是在 Java 端做所有事情,并创建一个 getter getActiveSystemproperties()
,手动迭代映射systempropertys
并返回一组不可变的活动属性。
回答by danial
Another hibernate way of doing it with @Where:
另一种使用@Where进行休眠的方式:
@Entity
public class System {
@Id
@Column(name = "ID")
private Integer id;
@OneToMany(mappedBy = "system")
@Where(clause = "active = true")
private Set<Systemproperty> systempropertys;
}
@Entity
public class Systemproperty {
@Id
@Column(name = "ID")
private Integer id;
@Id
@Column(name = "ACTIVE")
private Integer active;
}
回答by hurtledown
There is no JPA way, but you can try Hibernate filetrs: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#objectstate-filters
没有 JPA 方式,但您可以尝试 Hibernate filetrs:http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#objectstate-filters
回答by David Kacetl
I needed to solve similar problem in EclipseLink. I used special SessionCustomizer and changed mapping condition for OneToMany annotation. Maybee Hibernate has something similar.
我需要在 EclipseLink 中解决类似的问题。我使用了特殊的 SessionCustomizer 并更改了 OneToMany 注释的映射条件。Maybee Hibernate 也有类似的东西。
Add customizer to persistence unit:
将定制器添加到持久性单元:
props.put(PersistenceUnitProperties.SESSION_CUSTOMIZER,MySessionCustomizer.class.getName());
EntityManagerFactory factory = new PersistenceProvider().createEntityManagerFactory(pu.getPersistenceUnitName(), props);
Fragment of customizer:
定制器的片段:
public class MySessionCustomizer implements SessionCustomizer {
public void customize(Session session) throws Exception {
final Map<?, ?> descs = session.getDescriptors();
if (descs != null)
{
// This code assumes single table per descriptor!
for (final Object descObj : descs.values())
{
final ClassDescriptor desc = (ClassDescriptor) descObj;
final Class<?> sourceClass = desc.getJavaClass();
for (DatabaseMapping mapping : desc.getMappings())
{
if (mapping instanceof OneToManyMapping)
{
final OneToManyMapping collectionMapping = ((OneToManyMapping) mapping);
// create default foreign key condition (nescessary):
final DatabaseField sourceField = mapping.getSourceKeyFields().get(0);
final DatabaseField targetField = mapping.getTargetForeignKeyFields().get(0);
final Expression defaultFkExpression = new ExpressionBuilder(mapping.getReferenceClass()).getParameter(sourceField).equal(eb.getField(targetField));
// add filter condition "additionalExpression"
final Expression finalExpression = defaultFkExpression.and(additionalExpression);
// SET default foreign key condition and filter condition to mapping
mapping.setSelectionCriteria(finalExpression);
}
}
}
}
}
}