how to save foreign key entities using spring DAO - java

public class Customer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idCustomer")
private Integer idCustomer;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "idCustomer")
private Collection<Login> loginCollection;
}
public class Login implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idLogin")
#JoinColumn(name = "idCustomer", referencedColumnName = "idCustomer")
#ManyToOne(optional = false)
private Customer idCustomer;
}
//trying to save the customer and login in the database
ArrayList<Login> logins = new ArrayList<Login>();
Login log = new Login();
log.setIdCustomer(cust);
logins.add(log);
cust.setLoginCollection(logins);
cust = custRepo.save(cust); //failed
//Login log = new Login();
//log.setUName(user);
//log.setPassword(pass);
//log.setIdCustomer(cust);
//cust = custRepo.save(cust);
//logRepository.save(log); //failed too.
I'm using spring data in my project. I have 2 model classes Customer and Login. My login class has a foreign key idCustomer in the database. When I try to save the customer without a login, it works fine but the problem is that I can't save a login object in the database.
I'm getting an error saying
Unknown column 'id_customer' in 'field list'
the jpa entities are generated.
Here is an image actual database.

Too many idCustomers in your example.
Try the code below.
I have changed a bit the annotated members #OneToMany and #ManyToOne,
following the tips established here JPA JoinColumn vs mappedBy
Also I have included idLogin in Login class. I don't know if this was a typo in your code.
public class Customer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idCustomer")
private Integer idCustomer;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "customer")
private Collection<Login> loginCollection;
}
public class Login implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idLogin")
private Integer idLogin;
#ManyToOne
#JoinColumn(name="idCustomer", insertable=false, updatable=false)
private Customer customer;
}

You need to you annotation
#JoinColumn
please go through these
https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinColumns.html
http://docs.oracle.com/javaee/6/api/javax/persistence/JoinColumn.html

Related

Hibernate OneToMany returning two objects when there is only one in the database

I'm working on a project with Hibernate and I'm having a pretty weird behaviour. In my database there are two entities Worksheet and WorksheetField. Saved in the database I have one worksheet and one field linked to it. When I get this entry from the database it comes with 2 fields.
My Entities:
#Entity
#Table(name = "worksheet")
public class Worksheet implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false, updatable = false)
private Long id;
// .......
#OneToMany(targetEntity = WorksheetField.class,
mappedBy = "worksheet",
cascade = CascadeType.ALL
)
private List<WorksheetField> fields;
// .......
}
#Entity
#Table(name = "worksheet_field")
public class WorksheetField implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
// .......
#ManyToOne
#JoinColumn(name="worksheet_id",nullable = false)
private Worksheet worksheet;
// .......
}
Repository:
public interface WorksheetRepository extends JpaRepository<Worksheet, Long>, JpaSpecificationExecutor<Worksheet> {
List<Worksheet> findAllByWorksheetType(Worksheet.Type type);
#Override
#Modifying
#Transactional
Worksheet save(Worksheet worksheet);
#Override
#Transactional
Worksheet findOne(Long id);
}
The #Transactional on findOne is just an attempt at fixing this, don't worry about that. And I fetch this entry by using findOne.
Looking at these, is it possible to identify what I'm doing wrong?

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;
}

how to use hibernate versioning in bidirectional association Spring data JPA?

Lets say I have bidirectional one-to-many association between Parent-Child, mapped as follows:
TradingAccount.java
public class TradingAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "tradingAccount", cascade = CascadeType.ALL, orphanRemoval = true)
private List<UnderlyingPerTradingAccount> underlyingPerTradingAccounts;
#Version
private Long version;
}
UnderlyingPerTradingAccount.java
public class UnderlyingPerTradingAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(cascade = {CascadeType.PERSIST})
private TradingAccount tradingAccount;
private Boolean enableBuy;
private Boolean enableSell;
}
this code work, but the problem after saving or updating Trading Account I found new three trading account in the database (primary key + null in all other columns)

Persist Nested Entity Spring Rest Data

I have a User Class
#Entity(name = "users")
#Table(name = "users")
public class User implements UserDetails {
static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id", nullable = false)
private Long id;
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
private String password;
}
Tied to a simple Repository
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
}
And I have an Instructor Class that has a nested User object
#Entity
#Table(name = "instructors")
public class Instructor {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "instructor_id", nullable = false, updatable = false)
private Long id;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private User user;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "course_id")
private List<Course> courses;
}
It is saved with the following repository
public interface InstructorRepository extends PagingAndSortingRepository<Instructor, Long> {
}
The JSON I am posting
{
"user": {
"id": 1
}
}
When I try to do a POST to /instructors . User is coming in null. Is there something I am missing to get JPA to tie the two together? I have tried adding CascadeType.ALL onto the field and that only throws a detached persist exception.
Leave the CascadeType.ALL to Instructor like you already tried:
#ManyToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
#JoinColumn(name = "user_id")
private User user;
In addition add the following to User. Seems to work with me. It provides the mapping information and makes JPA treat User managed
#OneToMany(mappedBy="user")//, cascade=CascadeType.ALL)
private List<Instructor> instructors = new ArrayList<>();
I have commented out the cascadeType in the above but it might be useful if you want to persist User wit all of its Instructors.

JPA refresh entity

I have two tables in my database USERS and ADDRESSES, each user can have many addresses.
I have build entity classes with NetBeans wizard, and it create the classes well:
#Entity
#Table(name = "USERS")
#XmlRootElement
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private Integer id;
// Some fields.......
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private Collection<Address> addressCollection;
public User() {
}
// Getters and Setters.......
}
#Entity
#Table(name = "ADDRESSES")
#XmlRootElement
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected AddressPK addressPK;
// Some fields.......
#JoinColumn(name = "USER_ID", referencedColumnName = "ID", insertable = false, updatable = false)
#ManyToOne(optional = false)
private User user;
public Address() {
}
// Getters and Setters.......
}
#Embeddable
public class AddressPK implements Serializable {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private int id;
#Basic(optional = false)
#NotNull
#Column(name = "USER_ID")
private int userId;
public AddressPK() {
}
}
In the session I save the User instance of the current logged in user. But the User's addressCollection never updates when I change the database like:
Address newAddr = new Address();
// Sets values to newAddr......
AddressFacade addrDao = new AddressFacade();
addrDao.create(newAddr); // Succeeded
LoginManager.getCurrentUser().getAddressCollection(); // Returns the old address list.
How can I refresh the current user's instance to get the correct addressCollection?
First, when you have a bidirectional relationship, JPA requires that you keep both sides of the relationship in synch with each other. This allows caching entities and other performance enhancements to be enabled by many providers. In this case, when you set the USER_ID field, you should update the User's addressCollection that is affected by the change so that your object model stays in synch with what you are committing to the database.
An alternative is to force a refresh manually on the User instance. This can be done with a em.refresh(user) call, or through provider specific options and query hints. This is usually the least performant option though as it requires a database hit that isn't needed.

Categories

Resources