Cannot delete or update a parent row HIBERNATE one to many - spring

I'm getting this error when I try to delete a pet. This pet, has visits (child) but I have defined CASCADE.ALL in pet entity. Any idea ?
ERROR:
Cannot delete or update a parent row: a foreign key constraint fails (web_customer_tracker.visits, CONSTRAINT visits_ibfk_1 FOREIGN KEY (pet_id) REFERENCES pets (pet_id))
#Entity
#Table(name = "pets")
public class Pet {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "pet_id")
private int pet_id;
.....
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "visit_id")
private Set<Visit> visits;
Visit class:
#Entity
#Table(name = "visits")
public class Visit {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "visit_id")
private int visit_id;
#ManyToOne
#JoinColumn(name = "pet_id")
private Pet pet;
....

you are using mappedBy in a wrong way
the mappedBy refers to the object name in the opposite side
like this
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "pet")
private Set<Visit> visits;
or if you want to map it by the JoinColum try this
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "pet_id")
private Set<Visit> visits;

Related

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

I seem to need both #OneToOne and #OneToMany relationship

I'm writing an app to operate a collection of hardware that is supposed to be setup and shutdown repeatedly in different locations.
I want to track those installations so I've created separate entities for a physical object itself and the installation.
Station object needs to keep track of up to one (null while not installed) active installation information (so #OneToOne) but also all the previous installations (so #OneToMany)
#Entity
#Table(name = "station")
class Station{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(mappedBy = "stationInstallation", cascade = CascadeType.DETACH,
CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH)
#JoinColumn(name = "station_installation_id", nullable = true)
private StationInstallation activeStationInstallation;
...
#OneToMany(fetch = FetchType.Lazy, mappedBy = "station_id", cascade =
{CascadeType.DETACH, CascadeType.PERSIST,
CascadeType.MERGE, CascadeType.REFRESH })
private List<stationInstallation> stationInstallations;
...
}
The other entity will have the station id, location and date of the setup as well as the shutdownDateTime being null.
#Entity
#Table(name = "stationInstallation")
class StationInstallation{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(mappedBy ="stationInstallation", cascade - CascadeType.ALL)
private Station station;
#Column(name = "location")
private String location;
#Column(name = "setupDateTime")
private LocalDateTime setupDateTime;
#Column(name = "shutdownDateTime")
private LocalDateTime shutdownDateTime
}
Finally the shutdown method is supposed to unattach the entity from the Station entity by setting activeStationInstallation to null and setting shutdownDateTime to LocalDateTime.NOW.
...
stationInstallation.getStation().setActiveStationInstallation(null);
stationInstallation.setShotdownDateTime(LocalDateTime.NOW);
...
But that will obviously result in a growing number of StationInstallation "finished" objects, which would seem to require #ManyToOne relation with the Station all the while I want to keep #OneToOne relation with the activeStationInstallation.
What do?
I figured I could just make another entity calling it FinishedStationInstallation, remove shutdownDateTime from StationInstallation, make both immutable and instead of adding shutdownDateTime with a setter add it in the constructor while deleting the active version. And immutablity is an asset, ut at the same time I'd have to add several new tables to the db and keep track of and query two entities instead of one.
EDIT: I guess I could get rid of List stationInstallations from the 1st entity, since I don't really need to keep the track of it beyond db queries, but I added it for the clarity of the question.
I would model it this way:
#Entity
#Table(name = "station")
class Station{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.DETACH,
CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH)
#JoinColumn(name = "station_installation_id", nullable = true)
private StationInstallation activeStationInstallation;
...
#OneToMany(fetch = FetchType.Lazy, mappedBy = "station", cascade =
{CascadeType.DETACH, CascadeType.PERSIST,
CascadeType.MERGE, CascadeType.REFRESH })
private List<stationInstallation> stationInstallations;
...
}
#Entity
#Table(name = "stationInstallation")
class StationInstallation{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne(mappedBy ="stationInstallation", cascade = CascadeType.ALL)
private Station station;
#Column(name = "location")
private String location;
#Column(name = "setupDateTime")
private LocalDateTime setupDateTime;
#Column(name = "shutdownDateTime")
private LocalDateTime shutdownDateTime
}
The one-to-one relation from Station to installation has a FK => so no mapped by
The one-to-many relation from Station to installation is mapped by the station association on installation, which obviously has to be a many-to-one association, since the other side is a one-to-many

How do I map an #OneToMany and #ManyToOne relationship properly so that I can save and update the #OneToMany side with or without the #ManyToOne side

I have an app with Angular front end and Spring backend. The two classes in question here are (backend):
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "tournament_games")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class TournamentGame {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "code", foreignKey = #ForeignKey(name = "code_fk"))
private TournamentCode code;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "type", foreignKey = #ForeignKey(name = "game_type_fk"))
private GameType type;
#Column(name = "home_score")
private int home_score;
#Column(name = "away_score")
private int away_score;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "result_type", foreignKey = #ForeignKey(name = "result_type_fk"))
private ResultType result_type;
#Column(name = "status")
private boolean status;
#Column(name = "round")
private int round;
#Column(name = "locked")
private boolean locked;
#OneToMany(mappedBy = "game", fetch = FetchType.EAGER)
private List<TournamentGamesPlayers> players = new ArrayList<>();
}
and
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "tournament_games_players")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "game")
public class TournamentGamesPlayers implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#ManyToOne
#JoinColumn(name = "tournament_game_id")
private TournamentGame game;
#Id
#ManyToOne
#JoinColumn(name = "playerid")
private Player player;
#Column(name = "home")
private boolean home;
}
I need help figuring out how to persist the List<TournamentGamesPlayers> when I save and/or update a TournamentGame object. I generate 45 games. The first 30 games have known players, and so I set them before saving. The last 15 do not have entries for the TournamentGamesPlayers join table, because I need to add them later.
I am able to get some results with CascadeType.ALL on the #OneToMany side when I initially generate the games, but it fails when I try to update a game with a seemingly infinite recursion/stack overflow.
If I omit any cascade type, the games side get generated, but the join table #ManyToOne side does not get entered.
I ended up just putting the players back into the game table to make my life easier.
try putting CascadeType.MERGE, CascadeType.ALL "delete parent and orphans" (JPA CascadeType.ALL does not delete orphans).
Also, defining the relationship as EAGER and not ignoring the JSON property can have problems. I would add #JsonIgnore to one of the parts of the relationship

How to link two tables by third?

I have three tables:
1) book: id (primary), name
2) shop: code (unique, not primary), name
3) book_shop: book_id, shop_id (code), price
I want to get shops in book like
book.getShop();
How to link this entities?
I tried:
#Data
#NoArgsConstructor
#Entity
#Table(name = "book", schema = "example")
#EntityListeners(AuditingEntityListener.class)
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<BookShop> bookShop;
}
.
#Data
#NoArgsConstructor
#Entity
#Table(name = "shop", schema = "example")
#EntityListeners(AuditingEntityListener.class)
public class Shop {
#Id
private int code;
private String name;
#OneToMany(mappedBy = "shop", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<BookShop> bookShop;
}
.
#Data
#NoArgsConstructor
#Entity
#Table(name = "book_shop", schema = "example")
public class BookShop implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Id
#ManyToOne
#JoinColumn(name = "book_id")
private Book book;
#Id
#ManyToOne
#JoinColumn(name = "shop_id")
private Shop shop;
#Column(name = "price")
private int fromDate;
}
This code return empty set: Book book = bookRepostiory.getById(1).get().getBookShop()
Try the many to many mapping implement like as below remove your book_shop table,
add this code to shop entity,
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
#JoinTable(name = "book_shop",
joinColumns = {#JoinColumn(name = "book_id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "shop_id", nullable = false)})
private Set<Book> bookList = null;
add this code to book entity,
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL,
mappedBy ="bookList")
private Set<Shop> shopList=null;
if any issue inform!!
I would suggest, first - initialize the set in the entity
private Set<BookShop> bookShop = new HashSet<>();
Second, add fetch = FetchType.EAGER to your association, for e.g.
#OneToMany(fetch = FetchType.EAGER, mappedBy = "book", cascade = CascadeType.ALL)

Spring JPa Id empty

I have an entity who own many object
#Entity
public class Lodger implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long lodgerId;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "lodger")
private List<IdentityCard> identityCardList;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "lodger")
private List<Phone> phoneList;
...
}
#Entity
public class IdentityCard {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long identityCardId;
private String identyCardValue;
#OneToOne
#JoinColumn(name = "identity_card_type_id") //without -> identity_card_type_identityCardTypeId
private IdentityCardType identityCardType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lodger_id")
private Lodger lodger;
}
When i save my lodger, all my object is saved (identiyCard, phone), but their field lodger_id is null.
I was thinking it was supposed to be done automatically when we use cascadeType.all.
The owner side of the bi-directioinal associations are in IdentityCard and Phone entities, this is the same as saying that the mappedBy is in Lodger's associations.
So for the persistence of the links you must set the lodger attribute in IdentityCard and Phone entities. Isn't necessary to add this entities to the Lodger's collections but it is fine because you want to save this entities along with Lodger using cascade option.

Resources