Is unique=true required in bi-directional one-to-one mapping in the owner of the relationship?
#Entity
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
#OneToOne(cascade={CascadeType.PERSIST})
#JoinColumn(name="passport_id", unique=true) //is unique=true required for bi-directional one-to-one mapping
private Passport passport;
public Passport getPassport() {
return passport;
}
}
#Entity
public class Passport {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name="passport_number")
private String passportNumber;
#OneToOne(mappedBy="passport")
private Customer customer;
public Customer getCustomer() {
return customer;
}
}
Hibernate documentation says that FK column in the database should be constrained unique to simulate one-to-one multiplicity, but it doesn't add the unique=true in the bi-directional mapping.
That's because it's not mandatory to use the Hibernate auto DDL feature. You can have incremental schema update scripts and the schema related annotations would be useless. Frankly, we kinda use those for in memory integration testing.
As you pointed out, the JoinColumn should state the uniqueness constraint.
Related
Background: I load up a mysql instance to run DB tests and I create my schema using Hibernate (spring-data-jpa) and run some tests against the DB. All my Entities are created via annotation and loaded in a spring context.
Tables: I have 2 tables:
MainTable:
- id (PK)
- customerId
...
ThirdParty:
- id (PK)
- customerId (FK: MainTable.customerId)
- serviceId
This is a one-to-one mapping as I don't want to add serviceId to my MainTable.
My entities are setup as follows:
#Table
#Entity
public class MainTable {
#Id
#Column
private String id;
#Column(name = "CUSTOMER_ID")
private String customerId;
#OneToOne
#JoinColumn(name = "CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
private ThirdParty thirdParty;
}
#Table
#Entity
public class ThirdParty {
#Id
#Column
private String id;
#Column(name = "CUSTOMER_ID")
private String customerId;
#Column(name = "SERVICE_ID")
private String serviceId;
}
I want MainTable.thirdParty to be nullable.
Whenever Hibernate creates the schema, it creates a FK relationship from MainTable.CUSTOMER_ID on ThirdParty.CUSTOMER_ID meaning I get a ref integrity problem when trying to persist MainTable with null thirdParty.
I just really want to be able to store an instance of MainTable which may be with or without ThirdParty data.
I don't want Hibernate to create the MainTable with a FK relation on ThirdParty.customerId
I can't understand how works oneToMany and manyToOne in JPA. For a sample I have to entity.
#Entity
public class Customer {
#Id
#GeneratedValue
private long id;
private String name;
private List<Skills> skillList
}
and another one
#Entity
public class SkillList {
private String skillName;
private byte skillLevel;
}
How to correct link this entities? Also If anyone can explain it in an accessible way.
In database one to many relationship is achieved by foreign key.
In order to link two entities in Java according to JPA specification you should use #ManyToOne annotation or both #ManyToOne and #OneToMany if you need bidirectional association.
#Entity
public class Customer {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany(mappedBy = "customer")
private List<Skill> skills;
}
#Entity
public class Skill {
#Id
#GeneratedValue
private Long id;
private String skillName;
private byte skillLevel;
#ManyToOne
private Customer customer;
}
It will generate two tables in the database. Table SKILL has column CUSTOMER_ID which relates to CUSTOMER table.
I am a new bee in Hibernate and I am using PostgreSQL 9.3, JDK 1.7, Hibernate 4.0.2
I am trying to save a Customer who Has-a relationship with Address i.e., One-To-Many Relation.
While saving the Customer i am getting the Exception:
javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.cust.entities.Address
Customer Entity:
#Entity
#Table(name="customer")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "CustomerIdSeq", sequenceName = "c_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CustomerIdSeq")
#Column (name="c_id")
private Long cId;
#Column(name="cname")
private String cname;
//bi-directional many-to-one association to Address
#OneToMany(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn(name="c_id")
private List<Address> address;
//getters and setters
}
Address Entity:
#Entity
#Table(name="address")
public class Address {
#Id
#Column(name="c_id")
private Long cId;
#ManyToOne
#PrimaryKeyJoinColumn(name="c_id", referencedColumnName="c_id")
private Customer customer;
#Column(name="street")
private String street;
#Column (name="city")
private String city;
//getters and setters
public void setCustomer(Customer customer) {
this.customer= customer;
this.cId= customer.getCId();
}
}
I had tried some thing which is similar to Java Persistence/Identity & Sequencing
I suspect that the Address record doesn't have an ID when calling save().
You're missing the #GeneratedValue tag in that class, and if not specified, it defaults to "assigned" value.
If you're not assigning a value to Address.cId before calling save(), you'll see this problem. Post all relevant code if this isn't the cause of the issue.
EDIT: Looking at your table structure, Address should really have it's own ID in the schema design, and have a foreign key(FK) reference to Customer.ID.
Form the comments to the previous answer and from your existing table structure, you may want to consider mapping Address as an Embeddable rather than as an Entity:
This is similar to a OneToMany, except the target object is an
Embeddable instead of an Entity. This allows collections of simple
objects to be easily defined, without requiring the simple objects to
define an Id or ManyToOne inverse mapping. ElementCollection can also
override the mappings, or table for their collection, so you can have
multiple entities reference the same Embeddable class, but have each
store their dependent objects in a separate table.
http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection
The mappings would then be as follows. Address will have no persistent identity of its own and can only exist as part of an Entity - currently customer but no reason you cannot use it with other entities requiring an address.
Customer:
#Entity
#Table(name="customer")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "CustomerIdSeq", sequenceName = "c_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CustomerIdSeq")
#Column (name="c_id")
private Long cId;
#Column(name="cname")
private String cname;
#ElementCollection
#CollectionTable(name = "customer_address", joinColumns = #JoinColumn(name = "c_id")
private List<Address> addresses;
}
Address:
#Embeddable
public class Address {
#Column(name="street")
private String street;
#Column (name="city")
private String city;
}
I am trying to use Hibernate annotation for writing a model class for my database tables.
I have two tables, each having a primary key User and Question.
#Entity
#Table(name="USER")
public class User
{
#Id
#Column(name="user_id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name="username")
private String username;
// Getter and setter
}
Question Table.
#Entity
#Table(name="QUESTION")
public class Questions extends BaseEntity{
#Id
#Column(name="question_id")
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#Column(name="question_text")
private String question_text;
// Getter and setter
}
And I have one more table, UserAnswer, which has userId and questionId as foreign keys from the above two tables.
But I am unable to find how I can reference these constraints in the UserAnswer table.
#Entity
#Table(name="UserAnswer ")
public class UserAnswer
{
#Column(name="user_id")
private User user;
//#ManyToMany
#Column(name="question_id")
private Questions questions ;
#Column(name="response")
private String response;
// Getter and setter
}
How can I achieve this?
#Column is not the appropriate annotation. You don't want to store a whole User or Question in a column. You want to create an association between the entities. Start by renaming Questions to Question, since an instance represents a single question, and not several ones. Then create the association:
#Entity
#Table(name = "UserAnswer")
public class UserAnswer {
// this entity needs an ID:
#Id
#Column(name="useranswer_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToOne
#JoinColumn(name = "question_id")
private Question question;
#Column(name = "response")
private String response;
//getter and setter
}
The Hibernate documentation explains that. Read it. And also read the javadoc of the annotations.
There are many answers and all are correct as well. But unfortunately none of them have a clear explanation.
The following works for a non-primary key mapping as well.
Let's say we have parent table A with column 1
and another table, B, with column 2 which references column 1:
#ManyToOne
#JoinColumn(name = "TableBColumn", referencedColumnName = "TableAColumn")
private TableA session_UserName;
#ManyToOne
#JoinColumn(name = "bok_aut_id", referencedColumnName = "aut_id")
private Author bok_aut_id;
#JoinColumn(name="reference_column_name") annotation can be used above that property or field of class that is being referenced from some other entity.
I am new to Hibernate / Spring, trying to map legacy database while creating a little web utility, which should ease some work for the colleagues. As I had mapped the entities and have access to the underlying data, I have some issues further down the road. To make long story short, I have two entites, Customer
#Entity
public class Customer implements Serializable{
#Id
#Column(name = "RecordID")
private Integer id;
#Column(name = "CUSTOMERNAME1")
private String name;
#OneToMany
#JoinColumn(name="CUSTOMER1", referencedColumnName="CUSTOMERNAME1")
private List<Contract> contracts;
}
and Contract:
#Entity
public class Contract implements Serializable {
#Id
#Column(name = "RECORDID") //RecordID
private Integer id;
#Column(name = "CONTRACTID1") //ContractID1
private String contractId;
#Column(name = "CUSTOMER1") //Customer1
private String customerName;
//#ManyToOne
//private Customer customer; // how can I write the reverse mapping?
}
The mapping from Customer to Contracts works (one customer can have many contracts, I can get them all using List contracts field in customer, but my question is, how can I achieve the reverse - that is, get the customer, to which to contract is mapped?
The Java API has some examples of how to use the ManyToOne annotation:
http://java.sun.com/javaee/6/docs/api/javax/persistence/ManyToOne.html
something like the below:
Customer class:
#OneToMany(mappedBy="customer", cascade=CascadeType.ALL)
private List<Contract> contracts;
Contract class:
#ManyToOne
#JoinColumn(name="customer_id", nullable=false)
private Customer customer;