Hibernate : GenericGenerator Details - java

I am learning Hibernate ....
#Id
#GeneratedValue(generator="foreign")
#GenericGenerator(name="foreign", strategy="foreign", parameters={
#Parameter(name="property" ,value="company")
})
public Long getId() {
return id;
}
In the above code i understand most of the things except these lines
parameters={
#Parameter(name="property" ,value="company")
}
Please help

For every GenericGenerator, you can pass a list of key/value (parameters) regarding your strategy.
A GenericGenerator using the strategy "foreign" expects one parameter called "property" and the expected value is an entity name. This means your entity's ID will be the same as the linked entity.
For example:
Author entity:
#Entity
#Table(name="authors")
public class Author {
#Id
#GeneratedValue
private Integer id;
private String name;
#OneToOne(mappedBy="author", cascade=CascadeType.ALL)
private Biography biography;
}
Biography entity:
#Entity
#Table(name="biographies")
public class Biography {
#Id
#Column(name="id")
#GeneratedValue(generator="gen")
#GenericGenerator(name="gen", strategy="foreign",
parameters=#Parameter(name="property", value="author"))
private Integer id;
#OneToOne
#PrimaryKeyJoinColumn
private Author author;
}
In that case, every Biography ID will have the same ID as the Author's ID.

Related

#GeneratedValue doesn't work at non id field

I would like to make a unique field "number" with autogeneration(autoincrement, last number + 1). But it is not an id field. How can i reach that? #GeneratedValue doesn't work. Only id was generated. My code doens't work.
My entity
#Entity
#Table(schema = "public")
public class Policeman implements Serializable {
#Id
#GeneratedValue
private Long id;
#Column
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long number;
#Column
private String fam;
#Column
private String name;
#Column
private String otch;
//setters getters
}
This SO question looked the same: Link1
It says that the #GeneratedValue annotation is only used in conjunction with #Id to create auto-numbers. It cannot be used with non-id columns. However, there is a workaround that suggests to create a separate entity with a generated Id, something like this:
#Entity
public class GeneralSequenceNumber {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long number;
}
#Entity
#Table(schema = "public")
public class Policeman implements Serializable {
#Id
#GeneratedValue
private Long id;
#OneToOne(...)
private GeneralSequnceNumber myVal;
#Column
private String fam;
#Column
private String name;
#Column
private String otch;
//setters getters
}
You can also refer to the following link for more details on this work-around:Link2
I hope it helps.

How to setup JPA Entity classes?

I am struggling with how to setup my JPA entity classes and which annotations should go where
I have the following tables:
Table Customer {
id: primary key,
name
}
Table CustomerDimension {
id: primary key, foreign key(Customer.id),
detail
}
Currently I have the following entity classes:
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#OneToOne
private CustomerDimension customerDimension;
}
public class CustomerDimension {
// ? what is meant to go here?
private long id;
#Column(name = "detail")
private String detail;
}
What annotation is meant to go on CustomerDimension.id to allow me to insert a new Customer that has a new CustomerDimension?
Should CustomerDimension also have a reference back to Customer?
Table Customer {
id: primary key,
name
}
Table CustomerDimension {
id: primary key,
foreign key(Customer.id),
detail
}
CustomerDimension is the owning side. so, the #OneToOne mapping should be like
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
}
public class CustomerDimension {
#Id
private long id;
#Column(name = "detail")
private String detail;
#OneToOne
private Customer customer;
}
You have the following problems :
Customer and CustomerDimension need the annotation #Entity.
In your DDL, the table CustomerDimension has a foreign key on Customer. Hence, the #OneToOne relationship should be declared on CustomerDimension's side.
Still in the DDL, your foreign key does not have an explicit name. I will assume it is customer_id and use it to declare the #JoinColumn (see below)
#Column annotations are required only if you need the column to have a name which is different from the attribute's name (but you can keep them for clarity).
Here is how I would map it.
#Entity
#Table(name = "Customer") //Optional
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "name") //Optional
private String name;
}
And for CustomerDimension :
#Entity
#Table(name = "CustomerDimension") //Optional
public class CustomerDimension {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "detail") //Optional
private String detail;
#OneToOne
#JoinColumn(name = "customer_id") //NOT optional
private Customer customer
}
EDIT (answer to your comment) :
If you really want your FK to be the primary key, you can do it like this :
#Entity
#Table(name = "CustomerDimension") //Optional
public class CustomerDimension {
#Column(name = "detail") //Optional
private String detail;
#Id
#OneToOne
#JoinColumn(name = "id") //NOT optional
private Customer customer
}
I still wonder why you do not put all information in the same table. It would save you a SQL join.
What you have here is a OneToMany biidirectional relationship with a foreign key instead of a join table. A join table seems to be preferred by vendors, but it's OK.
So, you have a list (or set) of CustomerDimensions in Customer, but with the mappedBy value set.
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy="customer")
List<CustomerDimensions> dimensions;
}
and
public class CustomerDimension {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "detail")
private String detail;
#ManyToOne
Customer customer;
}
It's natural that Customers have a set of dimensions. By having a bidirectional mapping, if you have a dimension, then you can look up the customer easy (just reference the customer field)
EDIT: Since the CustomerDimension table has a Customer id reference, you can select many CustomerDimensions for one Customer, hence a OneToMany relationship. In order to set the CustomerDimension.customer_id field, simply put a CustomerDimension in the Customers list of dimensions.

Unknown Entity Error With ManyToOne Relationship

OK, so I've designed a basic CRUD an an exercise. It has 2 tables Jobs and Employees. I'm trying to create a many to one relationship, but when I click the link to go to the Employee Entry page it throws an error that kicks off with the #ManyToOne referencing an Unknown Entity.
Here is what I've got in my Employees.java
String jobName;
#ManyToOne(fetch=FetchType.EAGER)
#Fetch(value = FetchMode.JOIN)
#JoinColumn(name = "Job_Name")
#Column (name='jobName')
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
Any idea what i"m doing wrong and how to resolve this?
As per your comment,i think you can define relationship between these two entities like below.
#Entity
#Table(name="employee")
class Employee{
#Id
#GeneratedValue
private Integer id;
#ManyToOne
#JoinColumn(name = "job_name")
private Job job;
// other column and getter and setter
}
#Entity
#Table(name="job")
class Job{
#Id
#GeneratedValue
private Integer id;
#Column(name="job_name")
private String jobName;
//provide other column and getter setter
}

Creating a table dynamicaly with hibernate

I am learning Hibernate ORM(v. 3 ) now and I've a got a question.
I have a table called USERS, created with annotations :
package com.hibernatedb.entities;
import javax.persistence.*;
#Entity
#Table(name = "USERS",uniqueConstraints = {#UniqueConstraint(columnNames={"USER_LOGIN", "USER_EMAIL"})})
public class User {
#Column(name = "USER_LOGIN", length=80, nullable=false)
private String login;
#Column(name = "USER_PASS", length=80, nullable=false)
private String password;
#Column(name = "USER_EMAIL", length=80, nullable=false)
private String email;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "USER_ID", nullable=false)
private Long id;
...
// some getters and setters, toString() and other stuff
...
}
And a Product entity :
#Entity
#Table(name = "PRODUCTS",uniqueConstraints = {#UniqueConstraint(columnNames={"PRODUCT_ID", "PRODUCT_NAME"})})
public class Product {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="PRODUCT_ID")
private long id;
#Column(name="PRODUCT_NAME", length=85, nullable=false)
private String name;
#Column(name="PRODUCT_DESCRIPTION", columnDefinition="mediumtext", length=1000)
private String description;
#Column(name="PRODUCT_COST", nullable=false)
private double cost;
So my question is : How can a create a table called like "USER +
User.getId()
BUYS", which contains a 2 foreign keys (USER_ID and PRODUCT_ID) for user in entity (table record) "User" without raw SQL table creation, but using Hibernate annotations or XML mapping.So i want to have something like
public class TransactionEntityBulider() {
public TransactionEntityBulder(User user)
// something that build me "USER + User.getId() BUYS" table and
}
public TransactionEntity getEntity() {
// something that return a "USER + User.getId() BUYS" table entity
}
Also i would like to see some another ways to solve my problem.
I think hibernate is not done for that kind of usage, because you would have to use dynamic mappings. Hibernate provide ways to specify mapping statically (xml and annotations).
I suggest you modify your approach. It normally should not be harmfull to have all the "USER_BUY" in the same table. Example :
#Entity
public class User {
...
#OneToMany(cascade=CascadeType.ALL, mappedBy="user")
List<UserBuys> buys = new ArrayList<UserBuys>();
...
}
#Entity
public class Product { ... }
#Entity
public class UserBuys {
...
#ManyToOne
Product product;
#ManyToOne
User user;
}

OneToOne with the same PrimaryKey and ForeignKey

Database
*user_account*
id (PK)
email
password
*user_detail*
id(PK)(FK)
name
city
Entities
#Table(name="user_detail")
public class UserDetail implementsSerializable{
#Id private Integer id;
...
#OneToOne
#JoinColumn(name="id")
private UserAccount userAccount;
}
#Table(name="user_account")
public class UserAccount implementsSerializable{
#Id private Integer id;
#OneToOne(mappedBy="userAccount")
private UserDetail userDetails;
}
Error
Exception Description: Multiple writable mappings exist for the field [user_detail.ID]. Only one may be defined as writable, all others must be specified read-only.
If the ID in UserAccount is both a primary key and a foreign key, then you should declare it as a single field and map it appropriately. Like this:
#Entity
public class UserAccount implements Serializable {
#Id
#OneToOne(mappedBy="userAccount")
private UserDetail userDetails;
}
Or else using #MapsId.
However, i suspect that what you really want is a single class spread over two tables:
#Entity
#Table(name = "user_account")
#SecondaryTable(name = "user_detail")
public class User implements Serializable {
#Id
private int id;
private String email;
private String password;
#Column(table = "user_detail")
private String name;
#Column(table = "user_detail")
private String city;
}
You cannot have both #Id private Integer id; and #JoinColumn(name="id"), you must remove one of them: I doubt that you really need a primary key in the details, so just remove the #Id line from there.

Categories