Save entity with realtion - spring

I have two entities with one-to-mane relationship:
#Entity
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
#JsonManagedReference
private List<RealEstate> realEstates = new ArrayList<>();
#Entity
public class RealEstate implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
#JsonBackReference
private User user;
I try to save realEstate entity with this code:
realEstate.setUser(user);
realEstateService.saveRealEstate(realEstate);
And this response:
[
{
"id": 1,
"name" : "Bueno",
"user" : 1
}
]
By all I have is creating new record in user table and relation with this new ID.
What I do wrong? What I need to read about this?

You first need to save User entity record and then RealEstate entity record.
Please read this article to implement One To Many relationship. I am sure your issue will be resolved.
https://attacomsian.com/blog/spring-data-jpa-one-to-many-mapping

Related

Is there a way to self-reference an entity using Spring JPA

I'm using Spring JPA and MySQL as the database. I have trouble with self-referencing its own entity.
I know the code below would do self-referencing, but it actually creates a new table to do so.
#Getter
#Entity
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseTimeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "member_id")
private Long id;
#ManyToMany
#JoinColumn(name = "followings_id")
private List<Member> followings = new ArrayList<Member>();
#ManyToMany
#JoinColumn(name = "followers_id")
private List<Member> followers = new ArrayList<Member>();
#ManyToMany
#JoinColumn(name = "blocked_id")
private List<Member> blocked = new ArrayList<Member>();
...
}
Question: I'm wondering if I can do this in a single table(which would be the member table) without creating a new table to do many-to-many self-referencing.
It is possible,
Instead of using the #ManyToMany annotation, you can use the #OneToMany and #ManyToOne annotations to create the self-referencing relationship
#Getter
#Entity
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseTimeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "member_id")
private Long id;
#OneToMany(mappedBy = "follower")
private List<Follow> followings = new ArrayList<>();
#OneToMany(mappedBy = "following")
private List<Follow> followers = new ArrayList<>();
#OneToMany(mappedBy = "blocker")
private List<Block> blocked = new ArrayList<>();
}
#Entity
#Getter
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Follow {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "follower_id")
private Member follower;
#ManyToOne
#JoinColumn(name = "following_id")
private Member following;
}
#Entity
#Getter
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Block {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "blocker_id")
private Member blocker;
#ManyToOne
#JoinColumn(name = "blocked_id")
private Member blocked;
}
Now Follow and Block entities represent the many-to-many relationships between Member entities and follower and following properties in the Follow entity represent the two sides of the many-to-many relationship, and the same is for blocked and blocker.

JPA onetomany mapping showing nested data many times

I have two table user(id,name) and user_mails(id,email,user_id) user to user_mails have one to many relation.
I have created following entity in spring boot
User
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "name", nullable = false)
private String name;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private Set<UserMail> userMails =new HashSet<UserMail>(0);
//Getter setter and constructor
}
UserMail
#Entity
#Table(name = "user_mails")
public class UserMail {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "email", nullable = false)
private String name;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id")
private User user;
It is showing following output on calling controller
[{"id":1,"name":"Ram","userMails":[{"id":2,"name":"ram#b.com","user":{"id":1,"name":"Ram","userMails":[{"id":2,"name":"ram#b.com","user":{"id":1,"name":"Ram","userMails":[{"id":2,"name":"ram#b.com","user":{"id":1,"name":"Ram","userMails":[{"id":2,"name":"ram#b.com","user":{"id":1,"name":"Ram","userMails":[{"id":2,"name":"ram#b.com","user":{"id":1,"name":"Ram","userMails":[{"id":2,"name":"ram#b.com","user":{"id":1,"name":"Ram","userMails":
and more
I want to access all users with all mail ids also want to acces mail id with user details
What changes should I do to get proper result

access many to many relation in spring

I have a class called Tag:
#Entity
#Table(name = "tags")
public class Tag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "tags")
private Set<Post> posts = new HashSet<>();
...
}
And a class called Post
#Entity
#Table(name = "posts")
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "post_tags",
joinColumns = { #JoinColumn(name = "post_id") },
inverseJoinColumns = { #JoinColumn(name = "tag_id") })
private Set<Tag> tags = new HashSet<>();
...
}
It creates another table named post_tags.
How can I write a Controller to access that table as it is not similar a repository?
Is there more easy and convenient way to implement ManyToMany relationship ?
My pom.xml
You don't need to access that relation table manually. You can load load all Tag entities, and then load all the referenced Post entities.
The relation table is enterily managed by your ORM frameork.
But, if you still want to access the relation table, you can use native queries in your Spring Data JPA repository, e.g.
#Query(value="select post_id, tag_id from post_tags", nativeQuery=true)
List<PostTag> loadPostTags();
PostTag class is not a jpa-managed entity and must match the structue of the returned table:
public class PostTag {
private long postId;
private long tagId;
// getter, setter
}
Use this way
#Entity
#Table(name = "tags")
public class Tag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "post_tags",
joinColumns = { #JoinColumn(name = "id") },
inverseJoinColumns = { #JoinColumn(name = "post_id") })
private Set<Post> posts = new HashSet<>();
...
}
#Entity
#Table(name = "posts")
public class Post {
#Id
#Column(name = "post_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long postId;
...
}

#ManyToMany with extra column - how to load via Spring Data?

I have many to many relation between User and Event. I need to have extra column in relational table. I did id:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToMany(mappedBy="user")
private Set<EventUser> eventUsers = new HashSet<>();
//
}
#Entity
public class Event {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private long id;
#OneToMany(mappedBy="event")
private Set<EventUser> eventUsers = new HashSet<>();
//
}
#Entity
#Table(name = "Event_User")
public class EventUser {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private long id;
private String reaction;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "event_id")
private Event event;
//
}
But now... I don't know how to load all events where user has concrete email. Before it I used method:
findByUsersEmail(String email);
Now I can't do this, because Event doesn't have Set users field.
Any ideas ?
What you need here is property-expressions.
Just a quick idea to start:
findByEventUsers_UserEmail(String email);
Note: Dont forget that creating queries by method names is a very limited approach and only used by trivial cases. In any other case, don't be afraid of using the #Query annotation on the method or write JPQL/Criteria API manually.

Register data into Many-to-Many Relation Table

I have 'Course' and 'Student' entities. They have many-to-many relation. So, i have COURSE_STUDENT(contains 'student_id' and 'course_id' columns) table. I want to register students to courses with a button.(For example; a student lists courses and click Register button to register a specific course).
When i want to create new courses, i use courseRepository and courseMapper which comes from JHipster by default.
But i don't have repository and mapper files for COURSE_STUDENT. Because it is not actually a main entity. It is created for many-to-many relation.
How can i register students to courses?
Git repo:https://github.com/canberkizgi/monolithic-mucs
My course entity:
#Entity
#Table(name = "course")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Course implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Column(name = "title", nullable = false)
private String title;
#Column(name = "description")
private String description;
#ManyToOne
private Instructor instructor;
#ManyToMany(fetch = FetchType.EAGER)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "course_student",
joinColumns = #JoinColumn(name="courses_id", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="students_id", referencedColumnName="id"))
private Set<Student> students = new HashSet<>();
Student entity:
#Entity
#Table(name = "student")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne
#JoinColumn(unique = true)
private User user;
#ManyToMany(fetch = FetchType.EAGER,mappedBy = "students")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Course> courses = new HashSet<>();
For example; Createcourse function with Mapper and Repository
#PostMapping("/courses")
#Timed
public ResponseEntity<CourseDTO> createCourse(#Valid #RequestBody CourseDTO courseDTO) throws URISyntaxException {
log.debug("REST request to save Course : {}", courseDTO);
if (courseDTO.getId() != null) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new course cannot already have an ID")).body(null);
}
Course course = courseMapper.toEntity(courseDTO);
course = courseRepository.save(course);
CourseDTO result = courseMapper.toDto(course);
return ResponseEntity.created(new URI("/api/courses/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
.body(result);
}
The relationship is owned by the course entity. Thats because on the student side the #ManyToMany annotation has a mappedBy attribute. This means, that the database will reflect the set in the course. You need to add students to that set to save the relationship. That change needs to be done within a transaction.
That being said it would probably be best to follow DDD here. I would create a registerTo method in the student class that would take the course as a parameter. I would then call this.courses.add(course) and course.getStudents().add(this) in that method.

Resources