【问题标题】:JPA one-to-many filteringJPA 一对多过滤
【发布时间】:2012-10-29 15:56:46
【问题描述】:

我们正在嵌套多个实体。但是,在检索时,我们只想获取那些处于活动状态的实体。

@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)。

四处搜索我发现了一些hibernate annotations 和使用subqueries 的可能性。但是,两者都不适合我。尽管我们目前正在使用休眠,但我正在考虑用 Eclipselink 替换它,因为我们目前必须使用急切加载,而且我们可能会遇到性能问题。子查询并不能很好地工作,因为我们嵌套了几个级别。

Eclipselink 似乎有一个可以工作的@Customizer 注释,但是它似乎遵循与休眠@FilterDef 注释不同的概念,并且在切换时会导致额外的开销。

@JoinColumn 似乎不允许进一步过滤。有没有标准的 JPA 方法来解决这个问题?

【问题讨论】:

  • 有点OT,但是你确定active应该是Systemproperty ID的一部分吗?
  • 所以@Filter 不适合你?
  • @AdamDyga 我会踢掉旧的系统属性,但这会违反一些外键。
  • @AleksandrM 我更喜欢上面提到的非休眠依赖解决方案。
  • @AleksandrM @Filter 在直接获取实体的情况下有效(例如 EntityManager.find() )。当您通过使用 JPA/Hibernate 映射的 SetCollection 获取实体时,它不会被应用

标签: java jpa one-to-many


【解决方案1】:

使用@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;
}

【讨论】:

  • 你拯救了我的一天。
  • 如果 systempropertys 中的某些属性在 SystemProperty 类中不存在怎么办。
【解决方案2】:

我需要在 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);
          }
        }
      }
    }
    }
}

【讨论】:

    【解决方案3】:

    【讨论】:

      【解决方案4】:

      AFAIK 没有可移植的基于 JPA 的方法来执行此操作。一个干净但有点低效的解决方案是在 Java 端做所有事情并创建一个 getter getActiveSystemproperties() 手动迭代映射的 systempropertys 并返回一组不可变的活动属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-10
        • 2021-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-08
        • 2021-10-14
        相关资源
        最近更新 更多