java Hibernate的@Filter被忽略

sz81bmfz  于 2023-03-28  发布在  Java
关注(0)|答案(2)|浏览(150)

这是我的模式x1c 0d1x
我有很多文章包含标题和内容栏,它们与翻译键有一对一的关系。翻译键有很多值(每种语言一个)
我尝试使用Hibernate @Filter从数据库中获取只有一种语言的帖子。
translations键和translations值实体以经典的方式Map。但是translation值不直接Map到post实体(没有外键)
post实体的Map如下所示:

@Entity
@Data
@Table(name = "posts")
@NamedQuery(name = "Post.findAll", query = "SELECT p FROM Post p")
@FilterDef(name = "langfilter", defaultCondition = "language = :langid", parameters = @ParamDef(name = "langid", type = Integer.class))
public class Post implements Identifiable, Serializable {

    private static final long serialVersionUID = 1L;

    @Column
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer identifier;

    // ID of the TranslationKey
    @Column
    private Integer name;

    @OneToMany(fetch = FetchType.EAGER)
    @Filter(name = "langfilter")
    @JoinColumn(name = "key", referencedColumnName = "name", insertable = false, updatable = false)
    @JsonView(View.class)
    private List<TranslationValue> nameTranslations;

    // Content column is not mapped for testing

}

我用来测试的代码是这样的:

EntityManager entityManagerLocal = entityManagerFactory.createEntityManager();
Session session = entityManagerLocal.unwrap(Session.class);
session.enableFilter("langfilter").setParameter("langid", 3);
System.out.println(session.find(Post.class, 1));
System.out.println(entityManagerLocal.find(Post.class, 1));

生成的SQL查询为:

SELECT p1_0.`identifier`,
       p1_0.`name`,
       n1_0.`key`,
       n1_0.`identifier`,
       n1_0.`language`,
       n1_0.`value`
FROM   `posts` p1_0
       LEFT JOIN `translations_values` n1_0
              ON p1_0.`name` = n1_0.`key`
WHERE  p1_0.`identifier` =?

正如你所看到的,过滤器被完全忽略了。
我哪里做错了?
附加问题:由于关系总是只产生一个结果(或者根本不产生结果),是否可以用@ManyToOneMap它?
我正在使用:spring-boot-starter 3.0.5(Hibernate ORM核心版本6.1.7.Final)

编辑

转换值Map

@Entity
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Table(name = "translations_values")
@NamedQuery(name = "TranslationValue.findAll", query = "SELECT t FROM TranslationValue t")
public class TranslationValue implements Identifiable, Serializable {

    private static final long serialVersionUID = 1L;

    @Column(name = "identifier")
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonView(View.class)
    private Integer identifier;

    @Column(name = "key", insertable = false, updatable = false)
    private Integer keyIdentifier;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "key")
    private TranslationKey key;

    @Column(name = "language", insertable = false, updatable = false)
    private Integer languageIdentifier;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "language")
    private Language language;

    @Column(name = "value")
    @Lob
    private String value;

    // Getters & Setters
    
}

转换键Map

@Entity
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Table(name = "translations_keys")
@NamedQuery(name = "TranslationKey.findAll", query = "SELECT t FROM TranslationKey t")
public class TranslationKey implements Identifiable, Serializable {

    private static final long serialVersionUID = 1L;

    @Column(name = "identifier")
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Integer identifier;

    @CriteriaParticipant
    @Column(name = "constraint")
    private Integer metadata;

    @OneToMany(mappedBy = "key")
    @Fetch(FetchMode.SELECT)
    @BatchSize(size = 1000)
    private List<TranslationValue> values;

    // Getters and Setters

}
k97glaaz

k97glaaz1#

基本上,@Filter@FilterDef功能将过滤器定义应用于实体类Map的表的Map列。幸运的是,它也适用于关联表,但需要一些修改。
使用@FilterJoinTable注解指定关联的过滤器。

@Entity
@FilterDef(name = "langfilter", parameters = {
        @ParamDef(name = "langid", type = Integer.class)
)}
public class Post implements Identifiable, Serializable {

    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer identifier;

    // ...

    @OneToMany(fetch = FetchType.EAGER)
    @FilterJoinTable(name = "langFilter", condition = "language = :langid")
    @JoinColumn(name = "key", referencedColumnName = "name", insertable = false, updatable = false)
    private List<TranslationValue> nameTranslations;

    // ...

}
u0sqgete

u0sqgete2#

Hibernate使用不同的抓取策略来检索实体。
在这种情况下,重要的策略是 * 直接获取 * 和 * 实体查询 *。
由于@Filter特性的限制,Hibernate只对 * 实体查询 * 应用过滤器。

entityManager
    .unwrap(Session.class);
    .enableFilter("langfilter")
    .setParameter("langid", 3);

// Using direct fetching strategy - filter won't apply
var post = entityManager.find(Post.class, 1));

要应用过滤器实体查询策略,应使用。

entityManager
    .unwrap(Session.class);
    .enableFilter("langfilter")
    .setParameter("langid", 3);

// Using entity queries strategy - filter will apply
var post = entityManager.createQuery("select p from Post p where id = :id")
    .setParameter("id", 1)
    .getSingleResult();

相关问题