【问题标题】:Spring Data one to many mappingSpring Data 一对多映射
【发布时间】:2015-07-01 21:29:15
【问题描述】:

我尝试在 Spring Data 项目中配置 OneToManyManyToOne 映射,但有一些问题。

所以我有两个实体:EmployerProject。一个雇主可以有很多项目。

实体类:

Employer.java

@Entity
@Table (name="Employer")
public class Employer {

    @Id
    @SequenceGenerator(name="my_seq", sequenceName="GLOBAL_SEQUENCE")
    @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="my_seq")
    @Column (name="employer_id")
    private int id;

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

    @JoinColumn (name="employer_id")
    @OneToMany(mappedBy = "employer", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<Project> project = new HashSet<Project>();

    ......................
}   

项目.java

@Entity
@Table (name="Project")
public class Project {

    @Id
    @SequenceGenerator(name="my_seq", sequenceName="GLOBAL_SEQUENCE")
    @GeneratedValue(strategy = GenerationType.SEQUENCE ,generator="my_seq")
    @Column (name="project_id")
    private int id;

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

    @ManyToOne
    @JoinColumn(name="employer_id", nullable = false)
    private Employer employer;
    ......................
}

存储库类:

public interface EmployerRepository extends JpaRepository<Employer, Integer> {
}

public interface ProjectRepository extends JpaRepository<Project, Integer> {
}

服务:

@Service
public class EmployerServiceImpl implements EmployerService {

    @Autowired
    private EmployerRepository employerRepository;

    @Override
    public List<Employer> getAllEmployers() {
        return employerRepository.findAll();
    }   
}

@Service
public class ProjectServiceImpl implements ProjectService {

    @Autowired
    private ProjectRepository projectRepository;

    @Override
    public List<Project> getAllProjects() {
        return projectRepository.findAll();
    }
}

控制器:

@Controller
public class MainController {

    private EmployerService employerService;

    private ProjectService projectService;

    @Autowired(required = true)
    @Qualifier(value = "employerService")
    public void setEmployerService(EmployerService employerService) {
        this.employerService = employerService;
    }

    @Autowired(required = true)
    @Qualifier(value = "projectService")
    public void setProjectService(ProjectService projectService) {
        this.projectService = projectService;
    }


    @RequestMapping(value="/employers", method=RequestMethod.GET)
    public @ResponseBody List<Employer> getEmployers(@RequestParam(value = "name", required = false) String name) {
        return employerService.getAllEmployers();        
    }
    ..............................
}

雇主表:

EMPLOYER_ID  .  NAME
......................
1            .  Google
2            .  Oracle
3            .  Facebook 

项目表:

PROJECT_ID .    NAME            . EMPLOYER_ID
.......................................
1          . Create web site    .  1
2          . Create reporting   .  2
3          . Create web service .  3
4          . Fixing web site    .  1        

我期待这样的事情:

[{"id":1,"name":"Google","project":[{"id":1,"name":"Create web site"}, {"id":4,"name":"Fixing web site"}},
 {"id":2,"name":"Oracle","project":{"id":2,"name":"Create reporting"}},
 {"id":3,"name":"Facebook","project":{"id":3,"name":"Create web service"}}]

但是来自controller 类的getEmployers 方法返回这个:

[{"id":1,"name":"Oracle","project":[{"id":4,"name":"Fixing web site",
"employer":{"id":1,"name":"Oracle","project":[{"id":4,"name":"Fixing web site",
"employer":{"id":1,"name":"Oracle","project":[{"id":4,"name":"Fixing web site",
"employer":{"id":1,"name":"Oracle","project":[{"id":4,"name":"Fixing web site",
"employer":{"id":1,"name":"Oracle","project":[{"id":4,"name":"Fixing web site",
"employer":{"id":1,"name":"Oracle","project":[{"id":4,"name":"Fixing web site","employer":
...................

如果这个问题讨论了很多次但我没有找到合适的答案,请见谅。

提前致谢!

【问题讨论】:

    标签: java spring hibernate spring-data-jpa


    【解决方案1】:

    Employers 和 Projects 之间存在双向关联。此外,您已将关联的双方配置为加载EAGERly(@ManyToOne 关联默认获取EAGERly,并且您已强制获取@OneToMany 一边EAGERly)。由于这种配置,当序列化框架加载Employers 时,它会找到有效的Projects,这些Projects 具有指向Employers 的反向链接并最终陷入循环循环。

    为了获得您想要的结果,您必须将要获取的@ManyToOne 一侧(在Project 实体上)标记为LAZYly 为@ManyTone(fetch = FetchType.LAZY)

    【讨论】:

    • 感谢重播。我将@ManyToOne(fetch = FetchType.LAZY) 添加到Project 实体但没有帮助,结果与第一个相同。
    • 杰克逊似乎最终也序列化了延迟加载的实体。 This post 有一些您可以尝试的选项。
    • 我将我的 OneToMany 映射更改为这个:@JsonInclude(JsonInclude.Include.NON_EMPTY) @OneToMany(fetch = FetchType.EAGER, mappedBy = ("employer"),cascade = CascadeType.ALL) private Set&lt;Project&gt; project = new HashSet&lt;Project&gt;(); 但它也无济于事
    • 您不需要对 employer.projects 属性进行任何配置,因为它已经被正确序列化了。您需要将@JsonIgnore 放在project.employer 上,这样序列化框架就不会尝试对其进行序列化。
    • 例如,查看this project from Github,以mvn clean tomcat7:run 运行它,然后将HTTP GET 请求发送到http://localhost:8080/companies,并将AcceptContent-Type HTTP 标头设置为@987654348 @。您将以 JSON 格式返回所需的输出。
    【解决方案2】:

    在关系的前向部分添加@JsonManagedReference(即User.java类):

    @Entity
    public class User implements Serializable {
    
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        private long id;
    
        @Column(name="name")
        private String name;
    
        @ManyToMany
        @JoinTable(name="users_roles",joinColumns=@JoinColumn(name = "user_fk"), inverseJoinColumns=@JoinColumn(name = "role_fk"))
        @JsonManagedReference
        private Set<Role> roles = new HashSet<Role>();
    
        ...
    

    在关系的后面部分添加@JsonBackReference(即Role.java类):

    @Entity
    public class Role implements Serializable {
    
        @Id 
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        private int id;
    
        @ManyToMany(mappedBy="roles")
        @JsonBackReference
        private Set<User> users = new HashSet<User>();
    
        ...
    

    这对我来说非常有效。 :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-30
      • 2021-09-15
      • 2021-05-17
      • 1970-01-01
      • 2016-12-18
      • 1970-01-01
      • 2019-03-27
      • 1970-01-01
      相关资源
      最近更新 更多