Фильтрация JPA "один ко многим"
Мы размещаем несколько объектов. Однако при извлечении мы хотим получить только те объекты, которые активны.
@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;
}
При запросе Systemproperties
я хочу получить только те свойства active
(active = 1).
Поиск вокруг я нашел несколько аннотаций спящего режима и возможность использовать подзапросы. Однако для меня это действительно не работает. Несмотря на то, что в настоящее время мы используем спящий режим, я рассматриваю возможность его замены с помощью Eclipselink, потому что в настоящее время мы должны использовать интенсивную загрузку, и с этим мы, вероятно, столкнемся с проблемами производительности. Подзапросы на самом деле не работают хорошо, потому что мы размещаем несколько уровней.
У Eclipselink есть @Customizer аннотация, которая могла бы работать, однако, похоже, она соответствует другой концепции, тогда аннотация hibernate @FilterDef
и при переключении вызовет дополнительные накладные расходы.
@JoinColumn
, похоже, не позволяет продолжить фильтрацию. Существует ли стандартный способ JPA для решения этой проблемы?
Ответы
Ответ 1
AFAIK не существует переносного метода на основе JPA. Чистым, хотя и немного неэффективным решением было бы сделать все на стороне Java и создать getter getActiveSystemproperties()
, который вручную выполняет итерацию над отображаемым systempropertys
и возвращает неизменяемый набор активных свойств.
Ответ 2
Другой спящий способ сделать это с помощью @Where:
@Entity
public class System {
@Id
@Column(name = "ID")
private Integer id;
@OneToMany(mappedBy = "system")
@Where("active = true")
private Set<Systemproperty> systempropertys;
}
@Entity
public class Systemproperty {
@Id
@Column(name = "ID")
private Integer id;
@Id
@Column(name = "ACTIVE")
private Integer active;
}
Ответ 3
Нет способа JPA, но вы можете попробовать файловые строки Hibernate: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#objectstate-filters
Ответ 4
Мне нужно было решить подобную проблему в EclipseLink. Я использовал специальный SessionCustomizer и изменил условия отображения для аннотации OneToMany. У Maybee Hibernate есть что-то подобное.
Добавить элемент настройки для сохранения:
props.put(PersistenceUnitProperties.SESSION_CUSTOMIZER,MySessionCustomizer.class.getName());
EntityManagerFactory factory = new PersistenceProvider().createEntityManagerFactory(pu.getPersistenceUnitName(), props);
Фрагмент настройки:
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);
}
}
}
}
}
}