How to change Hibernate Mapping , without crashing the Database - java

I have two Entitys.
#Entity
#Table(name = "EX.EXAMPLE")
public class Entity
{
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private long id;
#OneToOne
private Entity2 stuff1;
#OneToOne
private Entity2 stuff2;
#OneToOne
private Entity2 stuff3;
}
And the second is the following
#Entity
#Table(name = "EX.EXAMPLE2")
public class Entity2
{
#Id
private long stuff;
}
Know i need to change the current id (Stuff) to a new One. I added a new columne ID to table. How to change/migrate the foreign Keys and make the new Columne ID a uniqe Key ?
Is it possibe to do it with Hibernate ? or is there a way with MYSQL ?

you are not allowed to modify the primary key. do it in a different approach. and why you have created three #OneToOne relations with the same entity? this is redundant and they are the same. it's not necessary to make relation for each object

Related

JPA not saving foreign key in one-to-many relation

I have 2 tables with one-to-many relation on the owner class (Person) and many-to-one on the child class (Email)
My problem is that in the child class' foreign key is (person_id) is always null when I want to save my Person object. I tried different things using other questions' answers, but no luck.
I would like to solve this in an annotation approach, if it is possible.
Person Class:
#Entity
#Table(name="PERSON")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_PERSON")
#SequenceGenerator(name="SEQ_PERSON", sequenceName="SEQ_PERSON", allocationSize=1)
#Column(name = "person_id")
private Long personId;
#OneToMany(mappedBy="person", cascade=CascadeType.ALL)
private List<Email> email;
// getters and setters
}
Email class:
#Entity
#Table(name="EMAIL")
public class Email{
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_EMAIL")
#SequenceGenerator(name="SEQ_EMAIL", sequenceName="SEQ_EMAIL", allocationSize=1)
#Column(name = "email_id")
private Long emailId;
#ManyToOne
#JoinColumn(name="person_id", referencedColumnName="person_id", insertable = true)
private Person person;
// getters and setters
}
I get no exception / errors when I use this.
When I change the JoinColumn to #JoinColumn(name="person_id", referencedColumnName="person_id", nullable = false, updatable = false, insertable = true) then I get this error: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.test.Email.person
I tried to change the Person's email setter like this, nothing changed:
public synchronized void setEmail(List<Email> email) {
this.email=email;
for(Email em: email) {
em.setPerson(this);
}
}
source
I have a Person object, with 2 emails (as a test object to save, every column is filled, except the FK in Email table), do I have to set the FK everytime manually? (it doesn't look good, if I have multiple one-to-many variables)
Edit: I tried this Which is working, but my problem with that if I have a very deep data structure with a lot of One-To-Many relations, I have to implement this to every variable and then save.. So, is there a better solution with pure annotations / getters-setters ?

Troubles in annotation mapping hibernate with Spring MVC

Can someone please explain to me how to declare annotations on entities correctly?
There are two tables in the database. One table has a foreign key to a id of another one (#ManyToOne binding), both IDs are of Integer. And I created two entities to represent them in code.
How can I map these entities to DB? I had realized recently that Hibernate refers to classes. I mean that in #JoinColumn("???") I have to write the name of a column in DB, isn't it? What if the ID field's name in the entity is the same as in the DB? Thanks everyone in advance! Regards.
#Entity
#Table(name = "stat")
public class Statistic {
#Id
#Column( name = "statisticId")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long statisticsId;
...............
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn (name="userId") //<------------ The same name.
private User userStat;
//getters and setters + constr + overriding of ToString()
}
#Entity
#Table(name = "usser")
public class User {
#Id
#Column(name = "userId")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;`enter code here`
................
#OneToOne(mappedBy = "userStat")
private Statistic statisticUser;
}

Do we have to define one-to-many relationship natively in a db if we use #OneToMany annotation

I'm using hibernate 3.3.1 along with PostgreSQL 9.3 and I've written the following mapping:
#Entity
#Table(name = "player_account")
public class PlayerAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#ManyToOne(targetEntity = Player.class, fetch = FetchType.EAGER)
#JoinColumn(name="player_id")
private Player player;
//GET, SET methods
}
The question is do we actual have to specify that many-to-one raltionship in the database when we're creating a table? I mean to define a references in the following way:
CREATE TABLE player_account (
SERIAL UNIQUE,
player_id integer REFERENCES players
);
No you don't need to define in database; but that foreign key column should be present in table. i.e. player_id should be present in player_account table.

Hibernate #Version causing database foreign key constraint failure

I have two hibernate/JPA entities
#Entity
#Table(name = "conference_room", uniqueConstraints = #UniqueConstraint(columnNames = "code"))
class ConferenceRoom {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#Column(name = "code", unique = true, length = 20)
private String code;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "conferenceRoom")
#Cascade({CascadeType.ALL})
private Set<Person> people = new HashSet<Person>();
// Appropriate getters and setters
}
#Entity
#Table(name = "person")
class Person {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "conference_room_code", referencedColumnName = "code")
private ConferenceRoom conferenceRoom ;
// Appropriate getters and setters
}
More over in my database schema I have foreign key contraint on person.conference_room_code that references conference_room.code column.
With in a spring #Transactional method if I do following
public ConferenceRoom getNewConferenceRoom(Person p) {
ConferenceRoom r = new ConferenceRoom();
r.setCode("MyUniqueGeneratedCode");
r.getPeople().add(p);
// sessionFactory is spring injected member
sessionFactory.getCurrentSession().merge(r);
}
Everything is saved correctly, the row for person is updated properly and new conference_room row is added.
But then I tried to add support for optimistic locking db updates to Person class on Date field, so new Person class
#Entity
#Table(name = "person")
class Person {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "conference_room_code", referencedColumnName = "code")
private ConferenceRoom conferenceRoom ;
#Version
#Column(name = "updated", length = 19)
private Date updated;
// Appropriate getters and setters
}
This new 'updated' column in MYSQL timestamp column with default value of current_timestamp on insert and updates.
Now if the above method is executed I get
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Cannot add or update a child row: a foreign key constraint fails (`schema`.`person`, CONSTRAINT `fk_room_code` FOREIGN KEY (`conference_room_code`) REFERENCES `conference_room` (`code`) ON DELETE NO ACTION ON UPDATE NO ACTION)
....
I tried adding a #Version field to ConferenceRoom, but that didn't work.
I can't understand why adding #Version messes things up.
If I remove foreign key constraint or the newly added #Version field, code again starts working, without any exceptions.
I don't want to drop the foreign key constraint. Is there any other way around this problem.
First:
More over in my database schema I have foreign key contraint on person.conference_room_code that references conference_room.code column.
Your FK should reference the PK of the referenced entity. In the instant case, you should have person.conference_room_id which references conferenceroom.id. If you want your code to be the identifying field for the ConferenceRoom entity, then don't use a surrogate key. If the code column isn't a PK candidate, then it is also not an FK candidate.
Second:
Merge:
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge"
Persist:
Make a transient instance persistent. This operation cascades to associated instances if the association is mapped with cascade="persist"
I think you have confused merge with persist. From what I can tell by the provided code, you are creating a new ConferenceRoom and not modifying an existing one. Therefore, merge is not going to do what you want it to do. Try changing your (provided) method to the following:
public ConferenceRoom getNewConferenceRoom(Person p) {
ConferenceRoom r = new ConferenceRoom();
r.setCode("MyUniqueGeneratedCode");
r.getPeople().add(p);
// sessionFactory is spring injected member
sessionFactory.getCurrentSession().persist(r);
}
These things should fix the issues you have raised.

can someone please explain me #MapsId in hibernate?

Can someone please explain to me #MapsId in hibernate? I'm having a hard time understanding it.
It would be great if one could explain it with an example and in what kind of use cases is it most applicable?
Here is a nice explanation from Object DB.
Designates a ManyToOne or OneToOne relationship attribute that provides the mapping for an EmbeddedId primary key, an attribute within an EmbeddedId primary key, or a simple primary key of the parent entity. The value element specifies the attribute within a composite key to which the relationship attribute corresponds. If the entity's primary key is of the same Java type as the primary key of the entity referenced by the relationship, the value attribute is not specified.
// parent entity has simple primary key
#Entity
public class Employee {
#Id long empId;
String name;
...
}
// dependent entity uses EmbeddedId for composite key
#Embeddable
public class DependentId {
String name;
long empid; // corresponds to primary key type of Employee
}
#Entity
public class Dependent {
#EmbeddedId DependentId id;
...
#MapsId("empid") // maps the empid attribute of embedded id
#ManyToOne Employee emp;
}
Read the API Docs here.
I found this note also useful: #MapsId in hibernate annotation maps a column with another table's column.
It can be used also to share the same primary key between 2 tables.
Example:
#Entity
#Table(name = "TRANSACTION_CANCEL")
public class CancelledTransaction {
#Id
private Long id; // the value in this pk will be the same as the
// transaction line from transaction table to which
// this cancelled transaction is related
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID_TRANSACTION", nullable = false)
#MapsId
private Transaction transaction;
....
}
#Entity
#Table(name = "TRANSACTION")
#SequenceGenerator(name = "SQ_TRAN_ID", sequenceName = "SQ_TRAN_ID")
public class Transaction {
#Id
#GeneratedValue(generator = "SQ_TRAN_ID", strategy = GenerationType.SEQUENCE)
#Column(name = "ID_TRANSACTION", nullable = false)
private Long id;
...
}
IMHO, the best way to think about #MapsId is when you need to map a composite key in a n:m entity.
For instance, a customer can have one or more consultant and a consultant can have one or more customer:
And your entites would be something like this (pseudo Java code):
#Entity
public class Customer {
#Id
private Integer id;
private String name;
}
#Entity
public class Consultant {
#Id
private Integer id;
private String name;
#OneToMany
private List<CustomerByConsultant> customerByConsultants = new ArrayList<>();
public void add(CustomerByConsultant cbc) {
cbc.setConsultant(this);
this.customerByConsultant.add(cbc);
}
}
#Embeddable
public class CustomerByConsultantPk implements Serializable {
private Integer customerId;
private Integer consultantId;
}
#Entity
public class CustomerByConsultant{
#EmbeddedId
private CustomerByConsultantPk id = new CustomerByConsultantPk();
#MapsId("customerId")
#JoinColumn(insertable = false, updatable = false)
private Customer customer;
#MapsId("consultantId")
#JoinColumn(insertable = false, updatable = false)
private Consultant consultant;
}
Mapping this way, JPA automagically inserts Customer and Consultant ids in the EmbeddableId whenever you save a consultant. So you don't need to manually create the CustomerByConsultantPk.
As he explained Vladimir in his tutorial, The best way to map a #OneToOne relationship is to use #MapsId. This way, you don’t even need a bidirectional association since you can always fetch the Child entity by using the Parent entity identifier.
MapsId lets you use the same primary key between two different entities/tables. Note: when you use MapsId, the CASCADE.ALL flag becomes useless, and you will need to make sure that your entities are saved manually.

Categories