冬眠。引用 SINGLE_TABLE 继承类的集合字段在 fething 时忽略 DiscriminatorValue

发布于 2025-01-10 06:28:46 字数 3322 浏览 0 评论 0原文

问题:一对多集合字段忽略鉴别器列并获取所有条目而不是专用子类。

我有带有继承策略 SINGLE_TABLE 的基超类。

@DiscriminatorColumn(name = "state")
@Data
@Table(name = "named_entity", indexes = @Index(columnList = "state"))
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Entity
public class BaseNamedEntity {
    @Id
    private UUID id = UUID.randomUUID();
    @Column(insertable = false, updatable = false)
    @Setter(AccessLevel.PROTECTED)
    @Enumerated(EnumType.STRING)
    private EntityState state; // declared for jpql purposes
    private String name;
    @ManyToOne 
    @JoinColumn(name = "collection_holder_id", referencedColumnName = "id")
    private CollectionHolderEntity otmCollection; // field will be important later
}

状态“活动”和“已删除”的两个子类:

@Entity
@DiscriminatorValue("active")
public class ActiveNamedEntity extends BaseNamedEntity {
}
@Entity
@DiscriminatorValue("deleted")
public class DeletedNamedEntity extends BaseNamedEntity {
}

基本功能(如 spring 数据 CRUD 存储库)按预期工作:

((CrudRepository<ActiveNamedEntity, UUID>) activeDao).existsById(UUID.randomUUID());
// -> Hibernate: select count(*) as col_0_0_ from named_entity activename0_ where activename0_.state='active' and activename0_.id=?
// Discriminator column is checked as expected

我尝试引入与子类之一保持一对多关系的实体:

@Entity
@Table(name = "collection_holder")
@Data
public class CollectionHolderEntity {
    @Id
    private UUID id = UUID.randomUUID();
    @EqualsAndHashCode.Exclude
    @ToString.Exclude
    @OneToMany(mappedBy = "otmCollection", fetch = FetchType.EAGER) // Eager to avoid transactions in tests
    private List<ActiveNamedEntity> oneToManyCollection = new ArrayList<>(); // ActiveNamedEntity is subclass with corelated state = "active"
}

以及一旦尝试获取集合字段,生成的语句似乎会忽略鉴别器列: 意外状态对于此子类

collectionHolderDao.findById(collectionHolderEntity.getId()) // reloading entity
                .orElseGet(() -> Assertions.fail("Expected to find holder " + collectionHolderEntity));
// -> Hibernate: select collection0_.id as id1_0_0_, onetomanyc1_.collection_holder_id as collecti4_1_1_, onetomanyc1_.id as id2_1_1_, onetomanyc1_.id as id2_1_2_, onetomanyc1_.name as name3_1_2_, onetomanyc1_.collection_holder_id as collecti4_1_2_, onetomanyc1_.state as state1_1_2_ from collection_holder collection0_ left outer join named_entity onetomanyc1_ on collection0_.id=onetomanyc1_.collection_holder_id where collection0_.id=?
// join contains only id reference, but not state check:
// left outer join named_entity onetomanyc1_ on collection0_.id=onetomanyc1_.collection_holder_id

其中将请求预期行为,其中包含连接的状态检查:左外连接named_entity onetomanyc1_ on collection0_.id=onetomanyc1_.collection_holder_id 和 onetomanyc1_.state="active"

我是否缺少规范的某些部分?

也许我应该在某个地方明确指定它应该向生成的请求引入鉴别器列。如果是这样 - 预计如何处理多对多关系?

到目前为止,我尝试:

  1. 将拥有子类关系的字段(本例中的ActiveNamedEntity)移动,但似乎没有任何变化。
  2. 切换获取类型也得到相同的结果

在这个例子中我使用了org.springframework.boot:spring-boot-starter-data-jpa:2.4.6 with 与 org.hibernate:hibernate-core:5.4.31.Final 相关联

Problem: one-to-many collection field ignores discriminator column and fetches all entries instead of dedicated subclass.

I am having base super-class with inheritance strategy SINGLE_TABLE.

@DiscriminatorColumn(name = "state")
@Data
@Table(name = "named_entity", indexes = @Index(columnList = "state"))
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Entity
public class BaseNamedEntity {
    @Id
    private UUID id = UUID.randomUUID();
    @Column(insertable = false, updatable = false)
    @Setter(AccessLevel.PROTECTED)
    @Enumerated(EnumType.STRING)
    private EntityState state; // declared for jpql purposes
    private String name;
    @ManyToOne 
    @JoinColumn(name = "collection_holder_id", referencedColumnName = "id")
    private CollectionHolderEntity otmCollection; // field will be important later
}

And two sub-classes for states 'active' and 'deleted':

@Entity
@DiscriminatorValue("active")
public class ActiveNamedEntity extends BaseNamedEntity {
}
@Entity
@DiscriminatorValue("deleted")
public class DeletedNamedEntity extends BaseNamedEntity {
}

Base functionality (like spring data crud repository) works as expected:

((CrudRepository<ActiveNamedEntity, UUID>) activeDao).existsById(UUID.randomUUID());
// -> Hibernate: select count(*) as col_0_0_ from named_entity activename0_ where activename0_.state='active' and activename0_.id=?
// Discriminator column is checked as expected

I tried to introduce entity that holds one-to-many relationship to one of the sub-classes:

@Entity
@Table(name = "collection_holder")
@Data
public class CollectionHolderEntity {
    @Id
    private UUID id = UUID.randomUUID();
    @EqualsAndHashCode.Exclude
    @ToString.Exclude
    @OneToMany(mappedBy = "otmCollection", fetch = FetchType.EAGER) // Eager to avoid transactions in tests
    private List<ActiveNamedEntity> oneToManyCollection = new ArrayList<>(); // ActiveNamedEntity is subclass with corelated state = "active"
}

And it is seems like generated statements ignores discriminator columns once it tries to fetch collection field:
unexpected state for this sub-class

collectionHolderDao.findById(collectionHolderEntity.getId()) // reloading entity
                .orElseGet(() -> Assertions.fail("Expected to find holder " + collectionHolderEntity));
// -> Hibernate: select collection0_.id as id1_0_0_, onetomanyc1_.collection_holder_id as collecti4_1_1_, onetomanyc1_.id as id2_1_1_, onetomanyc1_.id as id2_1_2_, onetomanyc1_.name as name3_1_2_, onetomanyc1_.collection_holder_id as collecti4_1_2_, onetomanyc1_.state as state1_1_2_ from collection_holder collection0_ left outer join named_entity onetomanyc1_ on collection0_.id=onetomanyc1_.collection_holder_id where collection0_.id=?
// join contains only id reference, but not state check:
// left outer join named_entity onetomanyc1_ on collection0_.id=onetomanyc1_.collection_holder_id

Where expected behavior would be request, that contains state check for join: left outer join named_entity onetomanyc1_ on collection0_.id=onetomanyc1_.collection_holder_id and onetomanyc1_.state="active"

Am I missing some part of specification?

Maybe I should specify somewhere explicitly that it should introduce discriminator column to generated request. If so - what expected to do with many-to-many relationships?

So far I tried:

  1. to move field that owns a relationship to sub-class (ActiveNamedEntity in this example) but doesn't seems like anything changes.
  2. Switching fetch type with also gets same results

In this example I used org.springframework.boot:spring-boot-starter-data-jpa:2.4.6
with correlates to org.hibernate:hibernate-core:5.4.31.Final

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

遗弃M 2025-01-17 06:28:46

我仍然不认为这是预期的行为,但这里有一些东西可以让它开箱即用:

  1. 添加@org.hibernate.annotations.Where(clause)对于具有相关查询的每个子类:
@Entity
@DiscriminatorValue("active")
@Where(clause = "state='active'")
public class ActiveNamedEntity extends BaseNamedEntity { }

@Entity
@DiscriminatorValue("deleted")
@Where(clause = "state='deleted'")
public class DeletedNamedEntity extends BaseNamedEntity { }

或者直接对于集合属性:

/*...*/
    @Where(clause = "state='active'")
    private List<ActiveNamedEntity> oneToManyCollection = new ArrayList<>();

第一个似乎更可取,因为它将普遍工作。

  1. 添加@org.hibernate.annotations.Filter(和相应的filterDef)并为每个会话启用它。更多内容请参见此讨论
    我对这种方法没有任何运气,但理论上它应该有效。

I still don't think it is a expected behavior but here is few things to get it out of the box:

  1. Adding @org.hibernate.annotations.Where(clause) to each sub-class with correlated query:
@Entity
@DiscriminatorValue("active")
@Where(clause = "state='active'")
public class ActiveNamedEntity extends BaseNamedEntity { }

@Entity
@DiscriminatorValue("deleted")
@Where(clause = "state='deleted'")
public class DeletedNamedEntity extends BaseNamedEntity { }

Or to collection attribute directly:

/*...*/
    @Where(clause = "state='active'")
    private List<ActiveNamedEntity> oneToManyCollection = new ArrayList<>();

First one is seems more preferable since will be work universally.

  1. Adding @org.hibernate.annotations.Filter (and corresponding filterDef) and enable it for each session. More of that in this discussion.
    I didn't have any luck with this method but theoretically it should work.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文