I have this entity with four composite keys. Since Hibernate cannot generate entities with composite keys, I have to do it manually. That's the way I'm trying:
#Entity
#IdClass(ExamRequisitionPK.class)
#Table(name="ExamRequisitions")
#NamedQuery(name="ExamRequisition.findAll", query="SELECT er FROM ExamRequisition er")
public class ExamRequisition implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(unique=true, nullable=false)
private int id;
#Id
#Column(nullable=false)
#OneToOne
#JoinColumn(name="examId", nullable=false, insertable=false, updatable=false)
private Exam exam;
#Id
#Column(nullable=false)
#OneToOne
#JoinColumn(name="patientId", nullable=false, insertable=false, updatable=false)
private Patient patient;
#Id
#Column(nullable=false)
#OneToOne
#JoinColumn(name="doctorId", nullable=false, insertable=false, updatable=false)
private Doctor doctor;
With this entity mapped, what should I put in the IdClass (ExamREquisitionPK.class)?
I'm newbie with this, it would be great if someone could help me.
Basically, here are the rules:
A dependent entity might have multiple parent entities (i.e., a derived identifier might include multiple foreign keys).
If an entity class has multiple id attributes, then not only must it use an id class, but there must also be a corresponding attribute
of the same name in the id class as each of the id attributes in the
entity.
Id attributes in an entity might be of a simple type, or of an entity type that is the target of a many-to-one or one-to-one
relationship.
If an id attribute in an entity is of a simple type, then the type of the matching attribute in the id class must be of the same
simple type.
If an id attribute in an entity is a relationship, then the type of the matching attribute in the id class is of the same type as the
primary key type of the target entity in the relationship (whether the
primary key type is a simple type, an id class, or an embedded id
class).
I don't see the codes for the Exam, Patient and Doctor entity classes, but I'd like to make assumptions, by giving a sample code:
#Entity
public class Exam {
#Id
private String examId;
...
}
#Entity
public class Patient {
#Id
private Long patientId;
...
}
#Entity
public class Doctor {
#Id
private Integer doctorId;
...
}
Given the above code showing the type of each entity's primary key, here's what you should put in your ExamREquisitionPK.class:
public class ExamREquisitionPK {
private int id; // matches the name of ExamRequisition 1st #Id attribute
private String exam; // matches the name ExamRequisition 2nd #Id attribute but type should match with Exam's PK
private Long patient; // matches the name ExamRequisition 3rd #Id attribute but type should match with Patient's PK
private Integer doctor; // matches the name ExamRequisition 4th #Id attribute but type should match with Doctor's PK
}
Related
If I write this way
#Id
#OneToOne
#JoinColumn(name="Id")
private Region region;
it says
Composite-id class must implement Serializable: ....InPopulation
I don't want it be composite key, I just want id replaced by Region of appropriate id.
You use the MapsId annotation for that (i have assumed how the #Id is declared):
#Id
private Long id;
#JoinColumn(name = "Id")
#OneToOne
#MapsId
private Region region;
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;
}
As per Hibernate documentation, there are multiple annotations available if we want to use Map as an association between our entities. The doc says:
Alternatively the map key is mapped to a dedicated column or columns.
In order to customize the mapping use one of the following
annotations:
#MapKeyColumn if the map key is a basic type. If you don't specify the
column name, the name of the property followed by underscore followed
by KEY is used (for example orders_KEY). #MapKeyEnumerated /
#MapKeyTemporal if the map key type is respectively an enum or a Date.
#MapKeyJoinColumn/#MapKeyJoinColumns if the map key type is another
entity. #AttributeOverride/#AttributeOverrides when the map key is a
embeddable object. Use key. as a prefix for your embeddable object
property names. You can also use #MapKeyClass to define the type of
the key if you don't use generics.
By doing some examples I am able to understand that #MapKey is just used to map the key to a property of target entity and this key is used only for fetching records. #MapKeyColumn is used to map the key to a property of target entity and this key is used to save as well as fetching records. Please let me know if this is correct?
Also please let me know when I need to use #MapKeyJoinColumn/#MapKeyJoinColumns & #MapKeyEnumerated / #MapKeyTemporal
Thanks!
When you use a Map you always need to associate at least two entities. Let's say we have an Owner entity that relates to the Car entity (Car has a FK to Owner).
So, the Owner will have a Map of Car(s):
Map<X, Car>
#MapKey
The #MapKey will give you the Car's property used to group a Car to its Owner. For instance, if we have a vin (Vehicle Identification Number) property in Car, we could use it as the carMap key:
#Entity
public class Owner {
#Id
private long id;
#OneToMany(mappedBy="owner")
#MapKey(name = "vin")
private Map<String, Car> carMap;
}
#Entity
public class Car {
#Id
private long id;
#ManyToOne
private Owner owner;
private String vin;
}
#MapKeyEnumerated
The #MapKeyEnumerated will use an Enum from Car, like WheelDrive:
#Entity
public class Owner {
#Id
private long id;
#OneToMany(mappedBy="owner")
#MapKeyEnumerated(EnumType.STRING)
private Map<WheelDrive, Car> carMap;
}
#Entity
public class Car {
#Id
private long id;
#ManyToOne
private Owner owner;
#Column(name = "wheelDrive")
#Enumerated(EnumType.STRING)
private WheelDrive wheelDrive;
}
public enum WheelDrive {
2WD,
4WD;
}
This will group cars by their WheelDrive type.
#MapKeyTemporal
The #MapKeyTemporal will use a Date/Calendar field for grouping, like createdOn.
#Entity
public class Owner {
#Id
private long id;
#OneToMany(mappedBy="owner")
#MapKeyTemporal(TemporalType.TIMESTAMP)
private Map<Date, Car> carMap;
}
#Entity
public class Car {
#Id
private long id;
#ManyToOne
private Owner owner;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="created_on")
private Calendar createdOn;
}
#MapKeyJoinColumn
The #MapKeyJoinColumn requires a third entity, like Manufacturer so that you have an association from Owner to Car and car has also an association to a Manufacturer, so that you can group all Owner's Cars by Manufacturer:
#Entity
public class Owner {
#Id
private long id;
#OneToMany(mappedBy="owner")
#MapKeyJoinColumn(name="manufacturer_id")
private Map<Manufacturer, Car> carMap;
}
#Entity
public class Car {
#Id
private long id;
#ManyToOne
private Owner owner;
#ManyToOne
#JoinColumn(name = "manufacturer_id")
private Manufacturer manufacturer;
}
#Entity
public class Manufacturer {
#Id
private long id;
private String name;
}
Here's a working example of using #MapKey with #OneToMany with a composite #IdClass. It's obviously not the only way to accomplish the objective here, but I felt this was the most maintainable.
#Entity
#Table(name = "template_categories")
#IdClass(TemplateCategoryId.class)
public class TemplateCategory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
long orgId;
#Id
long templateId;
#OneToMany(targetEntity = TemplateEntry.class)
#JoinColumns( {
#JoinColumn(name = "orgId", referencedColumnName = "orgId"),
#JoinColumn(name = "templateId", referencedColumnName = "templateId")
}
)
#MapKey(name="key")
private Map<String, TemplateEntry> keyMap;
source code:
https://github.com/in-the-keyhole/jpa-entity-map-examples/blob/master/src/main/java/com/example/demo/mapkey/entity/TemplateCategory.java
I have three tables:
1. Catalog (PK: id, name, FK: genre_id, FK: type_id)
2. Type (PK: id, name)
3. Genre (PK: id, name)
How to use Hibernate to connect Genre and Type to Catalog by using annotation?
#Entity
#Table(name = "catalog")
public class Catalog implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "product_name")
private String productName;
private Genre genre; // to add
private Type type; // to add
...
}
If you want to connect Genre and Type to Catalog (is this what you mean?), you should include in both Genre and Type entities a Collection<Catalog>-typed field and annotate it with #OneToMany.
If not, the straightest way is to add the #ManyToOne annotation to Genre and Type fields in Catalog.
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.