*** 错误设置多对多关系 Spring JPA
Posted
技术标签:
【中文标题】*** 错误设置多对多关系 Spring JPA【英文标题】:*** Error Setting up Many-to-Many Relationship Spring JPA 【发布时间】:2017-05-24 18:26:06 【问题描述】:上下文:在用户和事件之间建立多对多关系。下面是我的 application.properties 文件中的数据库配置。我的应用程序是一个 Springboot 项目。我会在某个时候从 h2 迁移到 postgreSQL。我的事件和用户存储库只是实现了 JPArepositories。到目前为止我读到的是***问题主要是由一些无限循环问题引起的,我可以看到当我从用户表中获取所有内容时,它会不断重复用户和事件之间的一种组合连接。在网址:http://localhost:8090/members/all
我明白了: 然后它永远不会结束。
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')
实体: 事件.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;
用户.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
]
]
【问题讨论】:
一个用户有事件;一个事件有用户。你必须打破这个循环。 我不确定 spring/jpa 中打破循环的语法。最终,我想要一些方法来生成一个关联表,该关联表将多对多关系与事件/用户的各种组合联系起来。你有什么建议如何打破这个循环,同时仍然保持这种多对多的关系。我认为 User.java 中的这一行就是这样做的。 @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name = "attendee",joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "event_id", referencedColumnName = " id")) 就像你说的我假设发生的事情是它不只是输出两个表的总组合,而是不断递归搜索用户->事件->用户...我假设在我的数据库中runner,因为我只有用户->事件,并且在该事件中没有用户不再向下迭代。我在事件和用户中重载了两个构造函数,这样他们就不需要维护一组其他的了。 请将我的答案标记为正确 一旦我测试它并且它有效,我肯定会。我不想提前关闭线程,以防我有后续问题。到早上我应该要么接受答案,要么提供额外的反馈。感谢您帮助我。 【参考方案1】:您的问题在于序列化。 所以你可以使用@JsonIgnore注解,如果你使用的是Jackson Json provider。
@JsonIgnore
@ManyToMany(mappedBy = "events")
public Set<User> getUsers()
return users;
【讨论】:
但是如果你需要用户列表,你需要教杰克逊应该如何表现。一个例子是使用 @JsonSerializer,所以不要重复 Event 属性。见davismol.net/2015/06/05/…以上是关于*** 错误设置多对多关系 Spring JPA的主要内容,如果未能解决你的问题,请参考以下文章
Spring数据JPA-休眠多对多关系在链接实体表中插入null
Spring Boot JPA多对多关系-Rest Web Service无法返回子对象