manyToMany,设置了“CascadeType.PERSIST”,无法级联存储
来源:互联网 发布:上海博科资讯java待遇 编辑:程序博客网 时间:2024/05/18 00:23
我在学生类里的课程集合上设置了CascadeType.PERSIST,但存储学生对象时无法自动存储级联的课程对象,
除非将CascadeType.PERSIST改成CascadeType.ALL,但ALL里面包含了REMOVE操作,我又不想要这个REMOVE操作。
(我舍去注解的形式采用hbm配置文件重新配置了一遍,在Student.hbm.xml文件里的课程集合上配置了cascade="save-update",然后存储学生对象时就能自动存储级联的课程对象,为什么配置文件形式就可以,而注解形式就不行?)
为了表述的更加清楚,请看以下代码:
学生类:
package
my.bean;
import
java.util.Set;
import
javax.persistence.CascadeType;
import
javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.Id;
import
javax.persistence.JoinColumn;
import
javax.persistence.JoinTable;
import
javax.persistence.ManyToMany;
import
javax.persistence.SequenceGenerator;
@Entity
public
class
Student {
private
int
id;
private
String sname;
private
Set<Course> courses;
@Id
@SequenceGenerator
(name=
"idGenerator"
, sequenceName=
"seq_student_id"
)
@GeneratedValue
(generator=
"idGenerator"
)
public
int
getId() {
return
id;
}
public
void
setId(
int
id) {
this
.id = id;
}
public
String getSname() {
return
sname;
}
public
void
setSname(String sname) {
this
.sname = sname;
}
@ManyToMany
(cascade={CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REFRESH})
@JoinTable
(name=
"student_course"
,
joinColumns={
@JoinColumn
(name=
"student_id"
)},
inverseJoinColumns={
@JoinColumn
(name=
"course_id"
)})
public
Set<Course> getCourses() {
return
courses;
}
public
void
setCourses(Set<Course> courses) {
this
.courses = courses;
}
}
课程类:
package
my.bean;
import
java.util.Set;
import
javax.persistence.CascadeType;
import
javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.Id;
import
javax.persistence.ManyToMany;
import
javax.persistence.SequenceGenerator;
@Entity
public
class
Course {
private
int
id;
private
String cname;
private
Set<Student> students;
@Id
@SequenceGenerator
(name=
"idGenerator"
, sequenceName=
"seq_course_id"
)
@GeneratedValue
(generator=
"idGenerator"
)
public
int
getId() {
return
id;
}
public
void
setId(
int
id) {
this
.id = id;
}
public
String getCname() {
return
cname;
}
public
void
setCname(String cname) {
this
.cname = cname;
}
@ManyToMany
(cascade={CascadeType.PERSIST, CascadeType.MERGE,
CascadeType.REFRESH}, mappedBy=
"courses"
)
public
Set<Student> getStudents() {
return
students;
}
public
void
setStudents(Set<Student> students) {
this
.students = students;
}
}
测试类:
package
my.test;
import
java.util.HashSet;
import
java.util.Set;
import
my.bean.Course;
import
my.bean.Student;
import
my.util.HibernateSessionFactory;
import
org.hibernate.HibernateException;
import
org.hibernate.Session;
import
org.hibernate.Transaction;
import
org.hibernate.cfg.Configuration;
import
org.hibernate.tool.hbm2ddl.SchemaExport;
public
class
Test {
public
static
void
main(String[] args) {
cascadeSave();
}
public
static
void
cascadeSave() {
Student s1 =
new
Student();
s1.setSname(
"zhangsan"
);
s1.setCourses(
new
HashSet<Course>());
Course c1 =
new
Course();
c1.setCname(
"c++"
);
c1.setStudents(
new
HashSet<Student>());
Course c2 =
new
Course();
c2.setCname(
"java"
);
c2.setStudents(
new
HashSet<Student>());
Session session =
null
;
Transaction transaction =
null
;
try
{
session = HibernateSessionFactory.getSession();
transaction = session.beginTransaction();
s1.getCourses().add(c1);
s1.getCourses().add(c2);
session.save(s1);
//存储student对象时,无法自动存储级联的course对象,why?
transaction.commit();
}
catch
(HibernateException e) {
e.printStackTrace();
if
(transaction !=
null
) transaction.rollback();
}
finally
{
if
(session !=
null
) session.close();
}
}
}
解:@OneToMany(cascade = {CascadeType.PERSIST}),发现级联不起作用,如果更改为Hibernate的注解 @Cascade({org.hibernate.annotations.CascadeType.PERSIST}),依然不起作用,但改为 @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})之后,注解生效。
原因如下:
如果使用javax.persistence.*里面的注解,只有调用相应的方法才生效,如PERSIST,只有调用persist方法才生效,Hibernate的注解也是如此。
查看我的代码,我保存对象用的是save方法,因此要用SAVE_UPDATE,级联才能生效。
2、使用方法
如果在ManyToOne的一端使用,如下(Vote类):
@ManyToOne
@Cascade({CascadeType.SAVE_UPDATE})
private VoteSubject voteSubject;
那么在保存该Vote对象时,如果对象的voteSubject属性是一个新对象,则会在保存Vote对象时,顺便把voteSubject对象保存;反之,如果one2Many的一端如果没有设置关联,则one的一端保存时,不会保存集合中的新对象。
也就是说在哪个对象中的相应属性中设置了级联,那么在操作该对象时级联生效。
如果想让有关系的双方同时级联生效,那么级联要在两个对象中同时设置。
@ManyToOne(cascade = { CascadeType.PERSIST,CascadeType.MERGE})
@JoinColumn(name = "HOSPITAL_ID")
改为:
@ManyToOne()
@Cascade(value={CascadeType.SAVE_UPDATE})
@JoinColumn(name = "HOSPITAL_ID")
并把
import javax.persistence.CascadeType;
import javax.persistence.Cascade;
改成
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
I have three entities (taken from the Spring Data REST Exporter Example): Person, Address and Profile. A Person can have addresses and profiles.
@Entitypublic class Person { @Id @GeneratedValue private Long id; private String name; @Version private Long version; @OneToMany private List<Address> addresses; @OneToMany private Map<String, Profile> profiles; // getters and setters}
In the client side I use Spring's RestTemplate. I added the Jackson2HalModule to the ObjectMapper used by the MappingJackson2HttpMessageConverter used by my RestTemplate.
Since Address and Profile do not have references to other entities I can POST them to my Spring Data REST server, and they are successfully saved:
final ResponseEntity<Resource<Address>> response = restTemplate.postForEntity("http://localhost:8080/addresses", addressInstance, AddressResource.class);
where AddressResource extends org.springframework.hateoas.Resource<Address>
.
But when I try to POST a Person instance
final ResponseEntity<Resource<Person>> response = restTemplate.postForEntity("http://localhost:8080/people", personInstance, PersonResource.class);
I get a org.springframework.web.client.HttpClientErrorException: 400 Bad Request
and I think the cause is the associated Address
es and Profile
s are serialized as normal POJOs instead as their resource URIs.
Here is the actual body of the POST request:
{ "id":null, "name":"Jongjin Han", "version":null, "addresses":[ { "id":1, "lines":[ "1111", "coder's street" ], "city":"San Diego", "province":"California", "postalCode":"60707" }, { "id":2, "lines":[ "1111", "coder's street" ], "city":"San Diego", "province":"California", "postalCode":"60707" } ], "profiles":{ "key1":{ "type":"a type of profile", "url":"http://www.profileurl.com" }, "key2":{ "type":"a type of profile", "url":"http://www.profileurl.com" } }}
I think it should be --> EDIT: It should be
{ "id":null, "name":"Jongjin Han", "version":null, "addresses":[ "http://localhost:8080/addresses/1", "http://localhost:8080/addresses/2" ], "profiles":{ "key1":"http://localhost:8080/profiles/1", "key2":"http://localhost:8080/profiles/2" }}
in fact the response body from the server is
{ "cause" : { "cause" : { "cause" : { "cause" : null, "message" : "Cannot resolve URI id. Is it local or remote? Only local URIs are resolvable." }, "message" : "Failed to convert from type java.net.URI to type org.springframework.data.rest.example.model.Address for value 'id'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI id. Is it local or remote? Only local URIs are resolvable." }, "message" : "Failed to convert from type java.net.URI to type org.springframework.data.rest.example.model.Address for value 'id'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI id. Is it local or remote? Only local URIs are resolvable. (through reference chain: org.springframework.data.rest.example.model.Person[\"addresses\"]->java.util.ArrayList[1])" }, "message" : "Could not read document: Failed to convert from type java.net.URI to type org.springframework.data.rest.example.model.Address for value 'id'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI id. Is it local or remote? Only local URIs are resolvable. (through reference chain: org.springframework.data.rest.example.model.Person[\"addresses\"]->java.util.ArrayList[1]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Failed to convert from type java.net.URI to type org.springframework.data.rest.example.model.Address for value 'id'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI id. Is it local or remote? Only local URIs are resolvable. (through reference chain: org.springframework.data.rest.example.model.Person[\"addresses\"]->java.util.ArrayList[1])"}
The possible solution I'd like to implement
Since I can access the REST repositories from the client side I am looking for a way to customize the Jackson Json Serializer in order to:
- check if the object I am serializing is a REST exported entity (easy with reflection, if only I could know where to put the code) and
- If I am serializing an entity, serialize the non-association fields as usual (e.g. person's name) and the association fields as their Resource URI (e.g. person's addresses) (with reflection it should be easy to convert from an entity to its resource URI, but I do not know where to put the code once again)
I tried with Jackson's JsonSerializer and PropertyFilters for Address and Profile, but I want a serializer which serialize them as resource URI only when they are in an association.
Any hint or aternative solution will be helpful.
- manyToMany,设置了“CascadeType.PERSIST”,无法级联存储
- CascadeType.PERSIST无法级联保存
- jpa级联操作详解1-级联保存(CascadeType.PERSIST)
- jpa级联操作详解1-级联保存(CascadeType.PERSIST)
- 关于JPA cascade = CascadeType.PERSIST级联保存的笔记
- CascadeType.PERSIST不起作用的原因
- CascadeType级联关系
- cascade=CascadeType.MERGE,PERSIST,REFRESH,REMOVE,DETACH,ALL
- JPA级联操作详解——级联删除(CascadeType.REMOVE)
- jpa级联操作详解2--级联删除(CascadeType.REMOVE)
- jpa级联操作详解3--级联删除(2)(CascadeType.REMOVE)
- hibernate的级联(hibernate注解的CascadeType属性)
- Hibernate cascade级联属性的CascadeType的用法
- 解决redis磁盘满了无法持久化错误not able to persist on disk
- ManyToMany
- @ManyToMany
- manytomany
- Hibernate ManytoMany 标注级联增删改查完整操作
- SQL笔试题
- 综合实践求税收
- find命令之xargs与exec
- QT - qss(一)按钮及关联菜单
- sql优化in语句
- manyToMany,设置了“CascadeType.PERSIST”,无法级联存储
- 如何理解HTML结构的语意化
- maven配置其他源下载jar包(详细)
- Glide的使用
- eclipse下生成Java类图和时序图,生成UML图
- 每日一个js实例8--通过面向对象实现拖拽
- QT - qss(二)组合框QComboBox的定制
- SharedUserId 简单 实现两个程序间的通信
- 如何实现字符串的反转及替换?