JPA-EntityManager的find方法返回重复项 [英] JPA - EntityManager find method returns duplicates

查看:312
本文介绍了JPA-EntityManager的find方法返回重复项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个子实体列表的实体.调用EntityManager.find()时,它基于两个列表的乘法返回重复项.

I have entity with two Lists of children entities. When calling EntityManager.find() it returns duplicates based on multiplication of two lists.

我在Hibernate和SQL Server中使用Spring,Jackson和JPA.

I'm using Spring, Jackson and JPA with Hibernate and SQL Server.

在对具有第一个子实体的 N 个元素和第二个子实体的 M 个元素的父对象进行测试时,它总是返回两个实体的 N * M 个元素

When testing with parent that has N elements of first and M of second child entity it always returns N*M elements of both entities.

例如,下面有 3 任务 5 注释,JPA返回 15 " (任务列表5份,评论列表3份)

For example below there are 3 tasks and 5 comments and JPA returns 15 for both lists. (5 copies of task list, and 3 copies of comment list)

控制器的输出为:

Comments 15
Tasks 15

其余代码在下面.

controller.java

@RequestMapping(method = RequestMethod.GET)
public String listAll(Model model) {

    Goal goal = new Goal();

    goal = service.getGoalById(25);

    System.out.println("Comments " + goal.getComments().size());
    System.out.println("Tasks " + goal.getTasks().size());

    return "home";
}

service.java

@Transactional
public Goal getGoalById(int goalId) {
    Goal goal = em.find(Goal.class, goalId);

    return goal;
}

goal.java

@Entity
@Table(name = "goal")
public class Goal {

@Id
@GeneratedValue
private int id;

@JsonManagedReference
@OneToMany(mappedBy = "tasksGoal", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
private List<Task> projectTasks = new ArrayList<Task>();

@JsonManagedReference
@OneToMany(mappedBy = "commentsGoal", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
private List<Comment> goalComments = new ArrayList<Comment>();

...

}

task.java

@Entity
@Table(name="projectTask")
public class Task {

@Id
@GeneratedValue
private int id;

@JsonBackReference
@ManyToOne (fetch = FetchType.LAZY)
@JoinColumn(name = "task_goal_id")
private Goal tasksGoal;

...

}

comment.java

@Entity
@Table (name="goalComment")
public class Comment {

@Id
@GeneratedValue
private int id;

@JsonBackReference
@ManyToOne (fetch = FetchType.LAZY)
@JoinColumn(name = "goal_id")
private Goal commentsGoal;

...

}

persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit"
    transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServer2008Dialect" />
        <property name="hibernate.hbm2ddl.auto" value="update" />
        <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
        <property name="hibernate.connection.charSet" value="UTF-8" />

        <!-- Hibernate prints SQL -->
        <property name="hibernate.show_sql" value="true" />

    </properties>
</persistence-unit>

推荐答案

这是因为您的抓取= FetchType.EAGER. 他想让Hibernate一目了然,即对链接到主"对象的元素的每个条目使用一个查询. Hibernate创建JOIN并尝试通过一个查询获取所有集合.

This is because of your fetch = FetchType.EAGER. he Hibernate tries to get everything in one shot, i.e. using one single query for each entry of element linked to a "master" object. Hibernate creates JOINs and tries to get all your collections with one query.

如果将@Fetch(FetchMode.SELECT)批注添加到集合中,则可以以N + 1查询的代价成功解决此问题.

This problem can be successfully solved at a cost of N+1 query, if you add the @Fetch (FetchMode.SELECT) annotation to your collection.

如果您确实需要FetchType.EAGER并且不想用Set替换您的集合,则可以对集合使用@Fetch(FetchMode.SELECT)批注: @JsonManagedReference @OneToMany(mappedBy ="tasksGoal",级联= CascadeType.PERSIST,提取= FetchType.EAGER) @Fetch(FetchMode.SELECT) 私有列表projectTasks = new ArrayList();

If you really need FetchType.EAGER and don't want to replace your collection with Set you can use @Fetch (FetchMode.SELECT) annotation for your collection: @JsonManagedReference @OneToMany(mappedBy = "tasksGoal", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) @Fetch (FetchMode.SELECT) private List projectTasks = new ArrayList();

@JsonManagedReference
@OneToMany(mappedBy = "commentsGoal", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@Fetch (FetchMode.SELECT)
private List<Comment> goalComments = new ArrayList<Comment>();

这篇关于JPA-EntityManager的find方法返回重复项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆