Is it possible to save an object while saving another object? - spring

public class RexorDTO {
private Rexor rexor; //an object without an id, I create it in the usual way via save
private Transit transit; //without id
private Service service;
}
#Entity
#Table(name = "rexor_srv")
public class RexorSrv {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
private Service service;
#OneToOne
private Transit transit;
#ManyToOne(fetch = FetchType.LAZY)
#JsonIgnore
private Rexor rexor;
}
Can I, after saving rexor, save transit while saving rexorsrv?
rexor = rexorRepository.save(rexor);
rexorSrvRepository.save(
new RexorSrv(
rexorDTO.getService(),
rexorDTO.getTransit(),
rexor)
);
object references an unsaved transient instance - save the transient instance before flushing

Related

update or delete on table "sessions" violates foreign key constraint "session_schedule_session_id_fkey"

I have to entities modeled Session and Speaker, with ManyToMany relationship, and I wanted to delete an instance of Session, but in the DB it is the foreign key of another table. Below is the entity model
#Entity(name = "sessions")
public class Session {
// attributes do not respect camel case notations because they
// need to match table notations in order to auto bind without annotations
// otherwise that is done with #Column annotation
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long session_id;
private String session_name;
private String session_description;
private String session_length;
#OnDelete(action = OnDeleteAction.CASCADE)
#ManyToMany()
#JoinTable(
name = "session_speakers",
joinColumns = #JoinColumn(name = "session_id"),
inverseJoinColumns = #JoinColumn(name = "speaker_id")
)
private List<Speaker> speakers;
public Session() {
}
I tried to use OnDelete Cascade, but it still didn't work. (I did read that it is not advised to use on ManyToMany relationship)
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public void delete(#PathVariable Long id){
sessionRepo.deleteById(id);
}
EDIT:
here is also the Speaker entity
#Entity(name = "speakers")
public class Speaker {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long speaker_id;
private String first_name;
private String last_name;
private String title;
private String company;
private String speaker_bio;
#Lob
#Type(type = "org.hibernate.type.BinaryType")
private Byte[] speaker_photo;
public Byte[] getSpeaker_photo() {
return speaker_photo;
}
public void setSpeaker_photo(Byte[] speaker_photo) {
this.speaker_photo = speaker_photo;
}
#ManyToMany(mappedBy = "speakers")
#JsonIgnore// added to resolve serialization issues
private List<Session> sessions;

Why I can't delete data in cascade way?

The problem is when I want to delete user I'm getting error in Spring Boot like that:
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (32506632_pam.badge, CONSTRAINT FK4aamfo6o0h5ejqjn40fv40jdw FOREIGN KEY (user_id) REFERENCES user (id))
I'm guessing that I need to delete data in cascade way. So I've placed CascadeType.REMOVE value to #OneToOne annotation like that, but it doesn't work:
badge entity
#Entity
#Data
#Table(name = "badge")
#AllArgsConstructor
#NoArgsConstructor
public class Badge {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonManagedReference
#ManyToMany(mappedBy = "badges", fetch = FetchType.LAZY)
private List<Reader> readers;
#OneToOne(cascade = CascadeType.REMOVE, orphanRemoval=true)
#JoinColumn(name = "user_id")
private User user;
private String number;
#Lob
#Basic(fetch = FetchType.LAZY)
private byte[] photo;
}
user entity
#Entity
#Data
#Table(name = "user")
#AllArgsConstructor
#NoArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String lastname;
private String pesel;
private String email;
private String telephone;
private Integer age;
private String gender;
}
reader entity
#Entity
#Data
#Table(name = "reader")
#AllArgsConstructor
#NoArgsConstructor
public class Reader {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonBackReference
#ManyToMany(fetch = FetchType.LAZY)
private List<Badge> badges;
private String department;
private String room;
private Boolean status;
}
Class which loads initial data
#Component
public class DataLoader implements ApplicationRunner {
#Autowired
private UserService userService;
#Autowired
private BadgeService badgeService;
#Autowired
private ReaderService readerService;
#Override
public void run(ApplicationArguments args) throws Exception {
User user1 = new User(null, "Jan", "Kowal", "11111111111", "jan#kowal.pl", "+48111111111", new Integer(23), "male");
userService.saveUser(user1);
Reader reader1 = new Reader(null, null, "Warehouse", "207A", new Boolean("true"));
Badge badge1 = new Badge(null, Arrays.asList(reader1), user1, "738604289120", null);
badgeService.saveBadge(badge1);
reader1.setBadges(Arrays.asList(badge1));
readerService.saveReader(reader1);
}
}
Endpoint for deleting user - it uses repository which extends CrudRepository and uses default delete behavior.
#DeleteMapping("/deleteUserById/{id}")
private void deleteUserById(#PathVariable Long id) {
userService.deleteUserById(id);
}
Database structure in phpmyadmin
My goal is to delete user and associated badge with him, then to delete row in reader_badges table.

JPA one to many, fetch children with specific column value

I have two entities in one to many relationship in my spring-data-jpa project.
Parent entity -
#Entity
#Table(name = "code_group")
public class CodeGroup implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#NaturalId
#Column(nullable = false)
private String entityId;
#OneToMany
#JoinColumn(name = "codeGroupId", referencedColumnName = "entityId")
private List<SystemCode> systemCodes;
// .. getters setters
}
Child entity -
#Entity
#Table(name = "system_code")
public class SystemCode implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Column(nullable = false)
private String codeGroupId;
#Column(nullable = false)
#Enumerated(EnumType.STRING)
private ActiveOrInactive status;
// getters and setters
}
status column is of enum type, it can only have Active or Inactive value.
My existing code works fine. It is fetching code group with associated system codes. I want to filter system code with status='Active'. How to do this?
Try like this:
#OneToMany
#JoinColumn(name = "codeGroupId", referencedColumnName = "entityId")
#Where(clause = "status= 'Active'")
private List<SystemCode> systemCodes;
You can create such methods in your repo:
List<CodeGroup> getAllBySystemCodes_Status(ActiveOrInactive status);
default List<CodeGroup> getAllActive() {
return getAllBySystemCodes_Status(ActiveOrInactive.Active);
}
default List<CodeGroup> getAllInactive() {
return getAllBySystemCodes_Status(ActiveOrInactive.Inactive);
}

Return an empty list on #OneToMany SpringBoot - Hibernate

I am getting null when using relationship in hibernate.
Here is my code
User entity
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private long userId;
#OneToMany(mappedBy="user",targetEntity=LoginHistory.class, fetch=FetchType.LAZY,cascade = CascadeType.ALL)
private List<LoginHistory> loginHistory = new ArrayList<LoginHistory>();
LoginHistory Entity
#Entity
#Table(name = "login_history")
public class LoginHistory {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(cascade = CascadeType.DETACH)
#JoinColumn(name="userId",referencedColumnName="id")
private User user;
To get login history details
#Override
public List<LoginHistory> getLoginHistory(User user) {
List<LoginHistory> lst = user.getLoginHistory();
return lst;
}
I am getting an empty list. Please help
it is working as designed as you are accessing an entity which is lazy loaded.Use the below like code to get the login history if you continue to keep the lazy loading on.
User user = getByKey(id);
if(user!=null){
Hibernate.initialize(user.getUserProfiles());
}

#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.

Resources