Hibernate: 如何在实体内部的 Set 中获取特定列的数据?

huangapple go评论53阅读模式
英文:

Hibernate: How do I fetch specific columns of entities in a Set within an entity?

问题

我有一个名为User的实体,其中包含一个relatedUsers(Set)属性,在获取用户时,我不想加载relatedUsers中实体的所有属性,只想加载它们的id。
我一直在尝试使用实体图来实现这一目标,但没有成功。这是我的实体:

@Entity
@Table(name = "USERS")
@NamedEntityGraph(
        name = "User.users",
        attributeNodes = {
                @NamedAttributeNode(value = "users", subgraph = "usersSubgraph")
        },
        subgraphs = {
                @NamedSubgraph(name = "usersSubgraph", attributeNodes = {
                        @NamedAttributeNode("id")
                })
        }
)
public class User {
    public User() {}

    @Id
    @Column(name = "id", unique = true)
    Long id;
    
    @Column(name = "xpto")
    String xpto;
    
    @Column(name = "xpto2")
    String xpto2;
    
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "USERS_USERS",
            joinColumns = @JoinColumn(name = "User_id"),
            inverseJoinColumns = @JoinColumn(name = "users_id"))
    Set<User> users;

    // ... 其余部分是getter和setter
}

这是查询:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);

EntityGraph<?> eg = entityManager.getEntityGraph("User.users");

Root<User> root = cq.from(User.class);

Predicate predicate = cb.or(cb.equal(root.get("id"), 1L));

cq.select(root).distinct(true).where(predicate);

TypedQuery<User> tq = entityManager.createQuery(cq);

return tq.setHint("jakarta.persistence.fetchgraph", eg).getSingleResult();

这个查询并不按我期望的方式执行(假设我理解了实体图的能力),因为似乎实体图什么也没做,relatedUsers的实体仍然完全加载,而不仅加载id。我正在尝试的事情是否可能?如果可能的话,我应该如何实现它?

英文:

I have a User entity with a relatedUsers (Set&lt;User&gt;) property within, and when fetching a User I don't want to load all properties of the entities within relatedUsers, just their id.
I've been trying to accomplish this using an entity graph but with no success. This is my entity:

@Entity
@Table(name = &quot;USERS&quot;)
@NamedEntityGraph(
        name = &quot;User.users&quot;,
        attributeNodes = {
                @NamedAttributeNode(value = &quot;users&quot;, subgraph = &quot;usersSubgraph&quot;)
        },
        subgraphs = {
                @NamedSubgraph(name = &quot;usersSubgraph&quot;, attributeNodes = {
                        @NamedAttributeNode(&quot;id&quot;)
                })
        }
)
public class User {
    public User() {}

    @Id
    @Column(name = &quot;id&quot;, unique = true)
    Long id;
    
    @Column(name = &quot;xpto&quot;)
    String xpto;
    
    @Column(name = &quot;xpto2&quot;)
    String xpto2;
    
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = &quot;USERS_USERS&quot;,
            joinColumns = @JoinColumn(name = &quot;User_id&quot;),
            inverseJoinColumns = @JoinColumn(name = &quot;users_id&quot;))
    Set&lt;User&gt; users;

    // ... the rest are the getters and setters
}

And this is the query:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery&lt;User&gt; cq = cb.createQuery(User.class);

EntityGraph&lt;?&gt; eg = entityManager.getEntityGraph(&quot;User.users&quot;);

Root&lt;User&gt; root = cq.from(User.class);

Predicate predicate = cb.or(cb.equal(root.get(&quot;id&quot;), 1L));

cq.select(root).distinct(true).where(predicate);

TypedQuery&lt;User&gt; tq = entityManager.createQuery(cq);

return tq.setHint(&quot;jakarta.persistence.fetchgraph&quot;, eg).getSingleResult();

This query isn't executing as I expected (assuming i understood what the entity graph is capable of), as it seems the entity graph did nothing, since the entities of relatedUsers are still being fully loaded instead of just loading the ids.
Is what i'm trying to do even possible? If so how can i accomplish it?

答案1

得分: 0

在Hibernate中,总是会获取整个实体对象,无法只获取实体的部分属性并仍然得到该类型的实体。但是,如果你只想获取特定的字段,你可以创建一个DTO投影,在其中封装你想要返回的数据。

public class UserIdProjection {
    private Long id;

    public UserIdProjection(Long id) {
        this.id = id;
    }

    // getter
}

并修改你的查询:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<UserIdProjection> cq = cb.createQuery(UserIdProjection.class);

Root<User> root = cq.from(User.class);

Predicate predicate = cb.or(cb.equal(root.get("id"), 1L));

cq.select(cb.construct(UserIdProjection.class, root.get("id"))).distinct(true).where(predicate);

TypedQuery<UserIdProjection> tq = entityManager.createQuery(cq);

List<UserIdProjection> results = tq.getResultList();

这样应该会返回一个包含UserIdProjection对象的列表,以及它们相关联的用户ID。原始实体不会以这种方式被获取。

英文:

In Hibernate, the whole entity object is always fetched, it's not possible to only fetch a subset of the properties of an entity and still get an entity of that type. However, if you want only some particular fields, you can create a DTO projection in which you can encapsulate the data you want to return.

public class UserIdProjection {
    private Long id;

    public UserIdProjection(Long id) {
        this.id = id;
    }

    // getter
}

And modify your query:

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery&lt;UserIdProjection&gt; cq = cb.createQuery(UserIdProjection.class);

Root&lt;User&gt; root = cq.from(User.class);

Predicate predicate = cb.or(cb.equal(root.get(&quot;id&quot;), 1L));

cq.select(cb.construct(UserIdProjection.class, root.get(&quot;id&quot;))).distinct(true).where(predicate);

TypedQuery&lt;UserIdProjection&gt; tq = entityManager.createQuery(cq);

List&lt;UserIdProjection&gt; results = tq.getResultList();

This should return a list of UserIdProjection objects, with their related user id's. The original entity won't be fetched this way.

huangapple
  • 本文由 发表于 2023年5月29日 18:47:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76356681.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定