StackOverflow错误设置多对多关系Spring JPA

时间:2017-05-24 18:26:06

标签: java spring hibernate jpa h2

上下文:在用户和事件之间建立多对多关系。下面是我的application.properties文件中的数据库配置。我的应用程序是一个Springboot项目。我会在某些时候从h2迁移到postgreSQL。我的Event和User存储库只是实现了JPArepositories。到目前为止我所读到的是stackoverflow问题主要是由一些无限循环问题引起的,我可以看到,当我从users表中获取所有内容时,它会不断重复用户和事件之间的一个组合连接。在网址:http://localhost:8090/members/all

我明白了:Output on webpage然后它永远不会结束。

spring.datasource.url=jdbc:h2:file:./members.db
server.port = 8090

Gradle文件:

buildscript {
    ext {
        springBootVersion = '1.5.3.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()

}

dependencies {
    testCompile('org.springframework.boot:spring-boot-starter-test')
    compile('org.springframework.boot:spring-boot-starter-actuator')
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile (group: 'com.vividsolutions', name: 'jts', version: '1.13')
    compile (group: 'org.orbisgis', name: 'h2gis', version: '1.3.1')
    compile (group: 'org.hibernate', name: 'hibernate-core', version: '5.2.10.Final')
    compile (group: 'org.hibernate', name: 'hibernate-entitymanager', version: '5.2.10.Final')
    compile (group: 'org.hibernate', name: 'hibernate-spatial', version: '5.2.10.Final')
    runtime('com.h2database:h2')
    //  runtime('org.postgresql:postgresql')
}

实体: Event.java

package com.alex_donley.event_mapper.Entities;

import com.vividsolutions.jts.geom.Geometry;

import javax.persistence.*;
import java.util.Date;
import java.util.Set;

/**
 * Created by indycorps on 5/24/2017.
 */
@Entity
public class Event {

    private long id;
    private String name;
    private String address;
    private String city;
    private String state;
    private Set<User> users;
    @Column(columnDefinition="Geometry")
    private Geometry location;
    private double price;
    private Date eventTime;
    private String category;
    private long secretCode;

    public Event(String name, String address, String city, String state, Geometry location, double price, Date eventTime, String category, long secretCode) {
        this.name = name;
        this.address = address;
        this.city = city;
        this.state = state;
        this.location = location;
        this.price = price;
        this.eventTime = eventTime;
        this.category = category;
        this.secretCode = secretCode;
    }

    public Event(String name, String address, String city, String state, Set<User> users, Geometry location, double price, Date eventTime, String category, long secretCode) {
        this.name = name;
        this.address = address;
        this.city = city;
        this.state = state;
        this.users = users;
        this.location = location;
        this.price = price;
        this.eventTime = eventTime;
        this.category = category;
        this.secretCode = secretCode;
    }

    public Event(){}

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @ManyToMany(mappedBy = "events")
    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public Date getEventTime() {
        return eventTime;
    }
    public void setEventTime(Date eventTime) {
        this.eventTime = eventTime;
    }
    public String getCategory() {
        return category;
    }
    public void setCategory(String category) {
        this.category = category;
    }
    public long getSecretCode() {
        return secretCode;
    }
    public void setSecretCode(long secretCode) {
        this.secretCode = secretCode;
    }
}

User.java

package com.alex_donley.event_mapper.Entities;


import com.vividsolutions.jts.geom.Geometry;

import javax.persistence.*;
import java.util.Set;

/**
 * Created by Indycorps on 5/11/2017.
 */
@Entity
public class User {

    private long id;
    private String firstName;
    private String lastName;
    private Set<Event> events;
    @Column(columnDefinition="Geometry")
    private Geometry location;

    public User(String firstName, String lastName, Geometry location) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.location = location;
    }

    public User(String firstName, String lastName, Set<Event> events, Geometry location) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.events = events;
        this.location = location;
    }

    public User(){}

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "attendee",joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "event_id", referencedColumnName = "id"))
    public Set<Event> getEvents() {
        return events;
    }

    public void setEvents(Set<Event> events) {
        this.events = events;
    }

    //Create getters and setters for location to actually output stuff
//    public Geometry getLocation() {
//        return location;
//    }
//
//    public void setLocation(Geometry location) {
//        this.location = location;
//    }
}

CommandLineRunner填充H2 DB

package com.alex_donley.event_mapper;

import com.alex_donley.event_mapper.Entities.Event;
import com.alex_donley.event_mapper.Entities.User;
import com.alex_donley.event_mapper.Repositories.EventRepository;
import com.alex_donley.event_mapper.Repositories.UserRepository;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.transaction.Transactional;
import java.util.*;

/**
 * Created by DonleyAl on 5/12/2017.
 */
@Component
public class DatabaseSeeder implements CommandLineRunner {
    private UserRepository userRepository;
    private static final Logger logger = LoggerFactory.getLogger(DatabaseSeeder.class);

    @Autowired
    public DatabaseSeeder(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    private Geometry wktToGeometry(String wktPoint) {
    WKTReader fromText = new WKTReader();
    Geometry geom = null;
    try {
        geom = fromText.read(wktPoint);
    } catch (ParseException e) {
        throw new RuntimeException("Not a WKT string:" + wktPoint);
    }
    return geom;
    }
    @Override @Transactional public void run(String... strings) throws Exception {
        Event eventA = new Event("AppleBottom", "101 Funhouse", "Alexandria", "VA", wktToGeometry("POINT(-105 40)"), 0.0, new Date(12312), "Action", 102321);
        Event eventB = new Event("Bandman", "55 Flash", "Sterling", "VA", wktToGeometry("POINT(-40 10)"), 0.0, new Date(3542), "Action", 4231234);
        Event eventC = new Event("Carship", "1 Whitehouse", "DC", "Washington", wktToGeometry("POINT(123 124)"), 0.0, new Date(432), "Mystery", 3428);

        userRepository.save(new HashSet<User>(){{
            add(new User("Alex", "Donley", new HashSet<Event>(){{
                add(eventA);
                add(eventC);
            }}, wktToGeometry("POINT(-105 40)")));
            add(new User("Bob", "Builder", new HashSet<Event>(){{
                add(eventA);
                add(eventB);
            }}, wktToGeometry("POINT(-105 40)")));
        }});
    }
}

UserController,是在我建立多对多关系之前创建的

package com.alex_donley.event_mapper.Controllers;

import com.alex_donley.event_mapper.Entities.User;
import com.alex_donley.event_mapper.Repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * Created by Indycorps on 5/11/2017.
 */
@RestController
@RequestMapping(value = "/members")
public class UserController {
    private UserRepository userRepository;

    @Autowired
    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @RequestMapping(value = "/all", method = RequestMethod.GET)
    public List<User> getAll(){
        return userRepository.findAll();
    }
    @RequestMapping(value = "/filterby/{name}", method = RequestMethod.GET)
    public List<User> getName(@PathVariable String name) {
        return userRepository.findByFirstNameLike(name);
    }
    @RequestMapping(value = "/create", method = RequestMethod.POST)
    public List<User> create(@RequestBody User user){
        userRepository.save(user);
        return userRepository.findAll();
    }

    @RequestMapping(value ="/delete/{id}", method = RequestMethod.DELETE)
    public List<User> remove(@PathVariable long id){
        userRepository.delete(id);
        return  userRepository.findAll();
    }
}

EDIT-1解决方案:

使用@JSONIgnore这是我现在从控制器输出的。这来自:http://localhost:8090/members/all

的网址
[
  {
    "id": 1,
    "firstName": "Bob",
    "lastName": "Builder",
    "events": [
      {
        "id": 1,
        "name": "AppleBottom",
        "address": "101 Funhouse",
        "city": "Alexandria",
        "state": "VA",
        "price": 0,
        "eventTime": 12312,
        "category": "Action",
        "secretCode": 102321
      },
      {
        "id": 2,
        "name": "Bandman",
        "address": "55 Flash",
        "city": "Sterling",
        "state": "VA",
        "price": 0,
        "eventTime": 3542,
        "category": "Action",
        "secretCode": 4231234
      }
    ]
  },
  {
    "id": 2,
    "firstName": "Alex",
    "lastName": "Donley",
    "events": [
      {
        "id": 1,
        "name": "AppleBottom",
        "address": "101 Funhouse",
        "city": "Alexandria",
        "state": "VA",
        "price": 0,
        "eventTime": 12312,
        "category": "Action",
        "secretCode": 102321
      },
      {
        "id": 3,
        "name": "Carship",
        "address": "1 Whitehouse",
        "city": "DC",
        "state": "Washington",
        "price": 0,
        "eventTime": 432,
        "category": "Mystery",
        "secretCode": 3428
      }
    ]
  }
]

1 个答案:

答案 0 :(得分:1)

您的问题在于序列化。 所以你可以使用@JsonIgnore注释,如果你使用Jackson如何提供Json。

@JsonIgnore
@ManyToMany(mappedBy = "events")
public Set<User> getUsers() {
    return users;
}