Hibernate Many-to-many with extra column do not insert children - java

I have an issue with my Hibernate app,
I have model as below:
Team.java
#Entity
#Table(name = "TEAM")
public class Team implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GenericGenerator(name = "antony", strategy = "increment")
#GeneratedValue(generator = "antony")
#Column(name = "TEAM_ID")
int id;
#Column(name = "TEAM_NAME")
String name;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.team")
#Column(name="TEAM_ID")
private Set<TeamMatchReference> teamMatchs = new HashSet<TeamMatchReference>(0);
Match.java
#Entity
#Table(name = "MATCHS")
public class Match implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GenericGenerator(name = "antony", strategy = "increment")
#GeneratedValue(generator = "antony")
#Column(name = "MATCH_ID")
int id;
//........
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.match")
#Column(name="MATCH_ID")
private Set<TeamMatchReference> teamMatchs = new HashSet<TeamMatchReference>(0);
TeamMatchId.java
#Embeddable
public class TeamMatchId implements Serializable {
private static final long serialVersionUID = 1L;
#ManyToOne
private Team team;
#ManyToOne
private Match match;
TeamMatchReference .java
#Entity
#Table(name = "team_match_reference")
#AssociationOverrides({
#AssociationOverride(name = "pk.team", joinColumns = #JoinColumn(name = "TEAM_ID")),
#AssociationOverride(name = "pk.match", joinColumns = #JoinColumn(name = "MATCH_ID")) })
public class TeamMatchReference implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private TeamMatchId pk;
#Column(name = "BET")
private float bet;
#Column(name = "SCORE")
private Integer score;
Then, I try to add new or update an Match object. The match was updated but its children - TeamMatchReference - were not updated, they're not inserted or deleted when I add or remove from the match.teamMatchReferenceSet.
Please help to make my code will update - insert and delete - the children when I update and save the match object.

You need to use cascade
#OneToMany(cascade={CascadeType.ALL})
There are different cascade type. You can select the one that fits your requirement.

Related

How to add movie_id and user_id in "movie_added_by" table

I have already a user model.
Now I have created a movie model, my requirement is that whenever any existing user is going to add any movie, at that time user_id and movie_id will be store in the movie_added_by table.
Here user model needs to map one to many to movie_added_by and similarly, the movie will be mapped to movie_added_by.
For better understanding, you can refer to the DB diagram.
I really don't know how can I do by using hibernate annotation
The user model is like this:
#Getter
#Setter
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id", unique = true, nullable = false)
private Integer user_id;
private String name;
}
The movie model is like this:
#Getter
#Setter
public class Movie implements Serializable
{
private static final long serialVersionUID = -6790693372846798580L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id", unique = true, nullable = false)
private Integer movie_id;
private String movie_name;
}
You probably want to create a #ManyToMany relationship between the entities. There are 2 ways of doing it (with intermediary table created explicitly or by Hibernate.
In simple approach your entities would look as following:
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id", unique = true, nullable = false)
private Integer user_id;
private String name;
#ManyToMany(cascade = CascadeType.Persist)
#JoinTable(name="user_movie",
joinColumns = {#JoinColumn(name="user_id")},
inverseJoinColumns = {#JoinColumn(name="movie_id)})
private Set<Movie> movies = new HashSet<>();
}
public class Movie implements Serializable
{
private static final long serialVersionUID = -6790693372846798580L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id", unique = true, nullable = false)
private Integer movie_id;
private String movie_name;
#ManyToMany(cascade = CascadeType.Persist, mappedBy = "movies" //field from the user class responsible for mapping)
private Set<User> users = new HashSet<>()
}
So basically here you tell Hibernate to create an intermediary table and keep there correlated id's of those 2 entities. Couple of other notes here:
a) you might want to change the id variable type from Integer to Long in case your entities grow;
b) If you have annotated a column with #Id, you don't have to use unique=true and nullable = false in the column annotation;
c) remember about implementing no-args constructor;
d) remember to exclude relationship fileds from the equals(), hashCode() and the toString() methods;
There is another way, where you explicitly create a model for the table keeping relationships. This might become handy, when it turns out that You need to keep more data in the 'relationship table'. In that case, Your entities would look as following:
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id", unique = true, nullable = false)
private Integer user_id;
private String name;
#OnetToMany(cascade = CascadeType.PERSIST, mappedBy = "user")
private Set<AddedMovie> addedMovies = new HashSet<>()
}
public class Movie implements Serializable
{
private static final long serialVersionUID = -6790693372846798580L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id", unique = true, nullable = false)
private Integer movie_id;
private String movie_name;
#OneToMany(cascade = CascadeType.PERSIST, mappedBy = "movie")
private Set<AddedMovie> moviesAddedByUser = new HashSet<>();
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Entity
public class AddedMovie{
#Id
#GeneratedValue
private Long id;
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "movie_id")
private Movie movie;
// sine this entity has now its own lifecycle, you can add more fields here
private Integer rating;
private LocalDateTime movieAddedOn;
}

Sping Data return List of null elements, but List has much elements

i have a problem
I have two entities:
Entity ALBERO
#Entity
#IdClass(Albero.class)
#Table(schema="organo", name = "albero")
public class Albero implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JoinColumn(name = "cmu")
#OneToOne
private Struttura cmu;
#Id
#JoinColumn(name = "padre")
#NotFound(action = NotFoundAction.IGNORE)
#ManyToOne
private Struttura padre;
#Column(name = "div")
private Date div;
#Column(name = "dfv")
private Date dfv;
#Column(name = "cso", length=15)
private String cso;
... get and set methods
and Entity STRUTTURA
#Entity
#Table(schema="organo", name="strutture")
#SqlResultSetMapping(
name = "Albero",
classes = #ConstructorResult(
targetClass = Albero.class,
columns = {
#ColumnResult(name="cmu", type=String.class),
#ColumnResult(name="padre", type=String.class)
}
)
)
public class Struttura implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "cmu")
private String cmu;
#Column(name = "nome", length=512)
private String nome;
#Column(name = "tipologia")
private String tipologia;
#Column(name = "data_creazione")
private Date data_creazione;
...get and set methods
I have a Repository AlberoRepository with the method:
public List<Albero> findByDfvIsNull();
and other method with native query:
String QUERY = "SELECT a.* FROM ALBERO a WHERE DFV IS NULL";
#Query(nativeQuery = true, value = QUERY)
public List<Albero> findAllWithDfvIsNull();
La query on Oracle DB, give me a result with 802 record.
Each record are full; they have the values.
Instead, the methods Java, give me a List of 802 object
BUT THESE OBJECTS ARE NULL.
Why ?
Can you help me ?
Thank you very much
The problem in #IdClass annotation.
You need a special class for PK:
public class AlberPK implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JoinColumn(name = "cmu")
#OneToOne
private Struttura cmu;
#Id
#JoinColumn(name = "padre", nullable = true)
#NotFound(action = NotFoundAction.IGNORE)
#ManyToOne
private Struttura padre;
}
... and change a little in Albero.class:
#Entity
#IdClass(AlberPK.class)
#Table(schema = "organo", name = "albero")
public class Albero implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Struttura cmu;
#Id
private Struttura padre;
...
}
That have to work.
I am really don't understand - why you used complex PK? Re-mind your DB structure if possible. It will help you a lot in future.

How create a constraint with Hibernate?

How can I create a constraint with Hibernate? I'm mapping two classes, "Team" and "Match", but I want that a match JUST can happens if the teams are from the same League. The way that I'm doing right now I can create a match with teams from differents leagues (which isn't interesting in this case).
Is there some annotation that "wraps" my teams, home and away, just being from one league? Or I have to do this in my system?
Thanks.
#Table(name = "match")
#Entity
public class Match implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#ManyToOne
#JoinColumn(name = "id_league")
private League league;
#ManyToOne
#JoinColumn(name = "id_home", referencedColumnName="id")
private Team home;
#ManyToOne
#JoinColumn(name = "id_away", referencedColumnName="id")
private Team away;
#Column
private Integer goalsHome;
#Column
private Integer goalsAway;
#Temporal(value = TemporalType.DATE)
private Date matchDate;
and
#Table(name="team")
#Entity
public class Team implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(length = 55)
private String name;
#ManyToOne
#JoinColumn(name = "id_league")
private League league;
#OneToMany
private List<Match> match;

JPA : OneToMany, get set of children of the owner entity

I have those two entities :
#Entity
#Table(name = "commande")
public class Commande implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "commande")
#JsonIgnore
private Set<Piece> pieces = new HashSet<>();
#Entity
#Table(name = "piece")
public class Piece implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "ref")
private String ref;
#ManyToOne
private Commande commande;
When I load the entity Commande, I would like its property pieces not to be empty if there are pieces linked to this commande.
How can I achieve that?
Thank you.

.IdentifierGenerationException: null id generated for:class

I have the following tables :
#Entity
#Table(name = "CUSTOMER")
public class Customers implements Serializable {
private static final long serialVersionUID = -5419345600310440297L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cust")
#SequenceGenerator(name = "cust", sequenceName = "cust_ID_SEQ")
#Column(name = "CUSTOMER_ID")
private Long id;
#Column(name = "NAME")
private String name;
#OneToMany(mappedBy = "customer", cascade = CascadeType.PERSIST)
private Set<CustomerDeal> customerDeals;
//getters and setters goes here ....
}
#Entity
#Table(name = "DEALS")
public class Deals implements Serializable {
private static final long serialVersionUID = -7197428343863081750L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "deals_seq")
#SequenceGenerator(name = "deals_seq", sequenceName = "DEALS_SEQ")
#Column(name = "DEAL_ID")
private Long dealId;
#Column(name = "DEAL_NAME")
private String dealColName;
//getters setters
}
#Entity
#Table(name = "CUSTOMER_DEALS")
public class CustomerDeals implements Serializable {
private static final long serialVersionUID = -4249326793843278525L;
#EmbeddedId
private CustomerDealId customerDealId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "CUSTOMER_ID", insertable = false, updatable = false)
private Customers customers;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "DEAL_ID", insertable = false, updatable = false)
private Deals deals;
//getters setters
}
#Embeddable
public class CustomerDealId implements Serializable {
private static final long serialVersionUID = 9086627167426987610L;
#Column(name = "DEAL_ID")
private Long dealId;
#Column(name = "CUSTOMER_ID")
private Long customerId;
}
however when I try to create a new customer
Customer cust - new Customer ()
cust.setName("Foo")
CustomerDeals custDeals = new CustomerDeals()
Set<CustomerDeal> custDealsSet = new HashSet<CustomerDeal>
CustomerDeal custDealsSet1 = new CustomerDeal()
CustomerDeal custDealsSet2 = new CustomerDeal()
custDealsSet1.setDeals(dealsRepository.findOne(1))//getting existing deal
custDealsSet1.customers(cust)
custDealsSet2.setDeals(dealsRepository.findOne(2))//getting existing deal
custDealsSet2.customers(cust)
custDealsSet.add(custDealsSet1)
custDealsSet.add(custDealsSet2)
cust.setCustomerDeals(custDealsSet)
customerRepository.saveAndFlush(cust)
customerRepository.saveAndFlush(cust)
I am getting
org.hibernate.id.IdentifierGenerationException: null id generated
for:class CustomerDeal
This is not duplication of this question
Your code that throws exception does not make sense so I guess it is not real code.
CustomerDeal has composite key, so you would not be able to retrieve it with dealsRepository.findOne(1), which means that you probably were retrieveing Deal not CustomerDeal but then the part would never compile:
Set<CustomerDeal> custDealsSet = new HashSet<CustomerDeal>();
custDealsSet.add(dealsRepository.findOne(1))
So, apart from that, I guess you were retrieving the existing deals. And you made a new customer. As the key of CustomerDeal depeneds on both customer and deal, both custumer and deal have to be set before persisting it which you probably forgot to do (and you got your exception). So it should look like:
Customer cust - new Customer ();
cust.setName("Foo");
CustomerDeals custDeal = new CustomerDeals();
custDeal.setCustomer(cust);
custDeal.setDeal(dealsRepository.findOne(1));
cust.getCustomerDeals().add(custDeal);
custDeal = new CustomerDeals();
custDeal.setCustomer(cust);
custDeal.setDeal(dealsRepository.findOne(2));
cust.getCustomerDeals().add(custDeal);
customerRepository.saveAndFlush(cust);
Now you are probably still in trouble. If you override the equals and hash on CustomerDeal so they are ID based (which typical code generator for entities does), both new CustomerDeals instances have them as null, so when you add them to the set the second one will override the first inserted (as null ids will be equals).
You also need to inform JPA that the ID will come from the relations.
In your CustomerDea you need to add #MapsId annotation (on both joins), like:
#MapsId("customerId")
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "CUSTOMER_ID", insertable = false, updatable = false)
private Customers customers;
Finally, unless your CustomerDeal table contains additional apart from CUSTOMER_ID and Deal_ID, then, it is a simple joint table and should not be mapped at all. That way you will save yourself a lot of trouble.
The reason why you got the error mentioned above is due to a mapping issue(I cant figure out what exactly is wrong though). As a completely different approach, I have modified your mappings. I have tested this and it is working fine. The advantage for you with this mapping is that it makes the CustomerDeals class redundant. Please note that I have removed the sequences as I am using MySQL.
#Entity
#Table(name = "CUSTOMERS")
public class Customer implements Serializable {
private static final long serialVersionUID = -5419345600310440297L;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "CUSTOMER_ID")
private Long id;
#Column(name = "NAME")
private String name;
#ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinTable(
name="CUSTOMER_DEALS",
joinColumns = #JoinColumn( name="CUSTOMER_ID"),
inverseJoinColumns = #JoinColumn( name="DEAL_ID")
)
private Set<Deals> deals = new HashSet<Deals>();
//Setters and Getters to follow
}
The Deals Class will be
#Entity
#Table(name = "DEALS")
public class Deals implements Serializable {
private static final long serialVersionUID = -7197428343863081750L;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "DEAL_ID")
private Long dealId;
#Column(name = "DEAL_NAME")
private String dealColName;
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "deals")
private Set<Customer> customers = new HashSet<Customer>(0);
//Setters and Getters here
}
Finally the main method which does the insert.
Customer customer = new Customer();
customer.setName("NewCust2");
Deals deals = new Deals();
deals.setDealColName("Deal2");
customer.getDeals().add(deals);
customerRepository.save(customer);

Categories

Resources