How to put a property in a different table - java

I have a class:
#Entity
public class myClass {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
...
private String orderIndex;
}
I would like to put orderIndex in a different table, since only few entities will have this property. I would like the tables to looks like this:
table myClass:
id | name | ...
table myClass_orderIndex:
myClass_id | orderIndex
I could not find the annotations to do this in hibernate

Perhaps a one-to-one relation will fit your requirements. The one-to-one is guaranteed by a #JoinColumn(unique=true)
#Entity
#Table(name="myClass_orderIndex")
public class OtherClass {
private String orderIndex;
#ManyToOne
#JoinColumn(unique=true)
private MyClass myClass;
...
}
#Entity
public class MyClass {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(mappedBy="myClass", cascade = javax.persistence.CascadeType.ALL, orphanRemoval = true)
#Cascade(CascadeType.ALL)
private List<OtherClass> list;
#Transient
public String getOrderIndex() {
if (list != null && list.size() == 1) return list.get(0).getOrderIndex();
return null;
}
}
This will create two tables as per your requirement.

Related

Hibernate: EmbeddedId with auto increment

Suppose that I have a simple Hibernate entity with auto-incremented id.
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = IDENTITY)
private Long id;
private String name;
}
Is it possible to declare id as a type-safe variable? I could apply #EmbeddedId like this.
#Entity
#Table(name = "product")
public class Product {
#EmbeddedId
private ProductId id;
private String name;
#Embeddable
public static class ProductId implements Serializable {
#GeneratedValue(strategy = IDENTITY)
private Long id;
public Long getId() {
return id;
}
}
}
It works with client-generated IDs, but not with database-generated ones.
Has anyone solved similar problem? What are the possible approaches?
First, you need to annotate ProductId class with #Embeddable like this:
#Embeddable
public static class ProductId implements Serializable {
private Long id;
private String name;
}
And, when you save entity, you need to create an instance of ProductId with unique parameters (in your case it is "name" field) as well.
For more information, I suggest you to have a look at here

How to use child table column in org.hibernate.annotations.Formula

I need to concat some columns from both parent and child table using #Formula
Here is the Entities
#Entity
#Table(name = "parent1")
public class Parent1 implements Serializable {
#Id
private BigInteger id;
#Column(name = "childId")
private BigInteger childId;
#Column(name = "col1")
private String col1;
#Column(name = "col2")
private String col2;
#Formula("CONCAT_WS(' ',Parent2.child_colm,col1,col2)")
private String combinedName;
#OneToOne
#JoinColumn(name = "childId")
private Parent2 parent2;
}
#Entity
#Table(name = "parent2")
public class Parent2 implements Serializable {
#Id
#Column(name = "childId")
private BigInteger childId;
#Column(name = "child_colm")
private String child_colm;
}
While giving like this it returns Unknown column 'Parent2.child_colm'
I would suggest you instead of using #Formula here just write the following method:
import javax.persistence.Transient;
#Entity
#Table(name = "parent1")
public class Parent1 implements Serializable {
#Transient
public String getCombinedName() {
return Stream.of(parent2.child_colm, col1, col2)
.filter(s -> s != null && !s.isEmpty())
.collect(Collectors.joining(" "));
}
}
The #Transient annotation is used to specify that a given entity attribute should not be persisted.

What is the correct way to annotate a class with a foreign id using Hibernate?

I am working on converting an existing project over to use Hibernate. I have a class like this:
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#Column(name = "group_id_user")
private Long groupId;
#Column(name = "name")
private String name;
...
// getters and setters....
}
and a class like this:
#Entity
#Table(name = "group")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "group_id")
private Long groupId;
#Column(name="group_name")
private String groupName;
...
// getters and setters....
}
The column named "group_id_user" in the user table is supposed to be a foreign key to the column named "group_id" in the group table.
Is it okay or "correct" to have the classes structured as shown above or should they be structured as shown below to make sure that the foreign key exists in the Database?
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#ManyToOne
#JoinColumn(name = "group_id_user")
private Group group;
#Column(name = "name")
private String name;
...
// getters and setters....
}
and
#Entity
#Table(name = "group")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "group_id")
private Long groupId;
#Column(name="group_name")
private String groupName;
...
// getters and setters....
}
I have tried using both formats but have had issues both ways. When I use the first format I have issues with the HQL syntax for joins while creating queries. When I try the second format I have issues with fetching just a User from the database without a Group, or adding a new User from a json object the has a groupId instead of a Group object. So before I spend anymore time switching back and forth between the two formats I want to know for sure which way should I be using the annotations to best fit industry standard?
I would try something like this if you could change the name of the columns too:
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY) //This means you will need the database to generate the ids, if you are using Oracle this won't work. You would need to use SEQUENCE.
private Long id;
#ManyToOne
#JoinColumn(name = "group_id") //There will be no need to specify the join column if you use group_id.
private Group group;
#Column(name = "name")
private String name;
...
// getters and setters....
}
#Entity
#Table(name = "groups")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="group_name")
private String groupName;
...
// getters and setters....
}
Also if you can I would change the name of the tables to plural.
Also I use something that helps me a lot. I have a super class called "Identifiable" which just has the id and it looks like this:
#MappedSuperclass
public class Identifiable implements Serializable {
private static final long serialVersionUID = -9027542469937539859L;
#Id
#Column(name = "ID")
#GeneratedValue
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Identifiable other = (Identifiable) obj;
if (id == null) {
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
With that you can extend all your classes with ids easily like:
#Entity
#Table(name = "users")
public class User extends Identifiable {
private static final long serialVersionUID = -90275424699375956859L;
#ManyToOne
#JoinColumn(name = "group_id") //There will be no need to specify the join column if you use group_id.
private Group group;
#Column(name = "name")
private String name;
...
// getters and setters....
}
However if you cannot change the names, let us know the issues you are having with the traces that are throwing and we might be able to help.
Thanks!

Remove redundant column for composite key in Hibernate

Hibernate creates empty "ID" column in case of code like in this post.
How tune it to not create "ID" column ("ID" is exact name of created column) or this can not be changed?
#Entity
#Table(name = "CATEGORY_RELATIONS")
public class CategoryRelations implements Serializable {
private CategoryRelationsPrimaryKey id;
#Id
#Column(name = "CATEGORY_RELATIONS_CATEGORY_ID")
private String categoryId;
#Id
#Column(name = "CATEGORY_RELATIONS_PARENT_ID")
private String parentId;
//getters and setters
#Entity
#IdClass(CategoryRelationsPrimaryKey.class)
public class CategoryRelationsPrimaryKey implements Serializable {
protected long categoryId;
protected long parentId;
//euqals, hashCode
}
}
1) #IdClass should stand at entity, not at composite id class;
2) If you already marked id properties by #Id, no separate id property is required:
#Entity
#Table(name = "CATEGORY_RELATIONS")
#IdClass(CategoryRelationsPrimaryKey.class)
public class CategoryRelations implements Serializable {
#Id
#Column(name = "CATEGORY_RELATIONS_CATEGORY_ID")
private String categoryId;
#Id
#Column(name = "CATEGORY_RELATIONS_PARENT_ID")
private String parentId;
//...
}
public class CategoryRelationsPrimaryKey implements Serializable {
protected String categoryId;
protected String parentId;
// ...
}
If you need some property named id, make it transient to avoid mapping to a DB table column.

Composite primary key, foreign key. Reference to object or key?

I have two classes Foo and Bar. The tables in the database look like this:
|Foo|
|id : INT (PK) | bar_id : INT (PK, FK) |
|Bar|
|id : INT (PK) |
Normally I would map it like this:
#Entity
public class Bar
{
#Id
#Column(name = "id")
private int id;
#OneToMany
private Set<Foo> foo;
}
#Entity
public class Foo
{
#EmbeddedId
private FooPK key;
#MapsId("barId")
#ManyToOne
#JoinColumn(name = "bar_id", referencedColumnName = "id")
private Bar bar;
}
#Embeddable
public class FooPK
{
#Column(name = "id")
private int id;
#Column(name = "bar_id")
private int barId;
}
However the id's in FooPK are loosely mapped and need to be connected manually. I would prefer a solution that maps using Objects in stead of loose ids.
I tried the following but (of course) it didn't work, but I think it gives an idea of what I would like to achieve:
#Entity
public class Bar
{
#Id
#Column(name = "id")
private int id;
#OneToMany
private Set<Foo> foo;
}
#Entity
public class Foo
{
#EmbeddedId
private FooPK key;
#MapsId("barId")
#ManyToOne
#JoinColumn(name = "bar_id", referencedColumnName = "id")
#Access(AccessType.FIELD)
private Bar getBar()
{
return key.getBar();
}
}
#Embeddable
public class FooPK
{
#Column(name = "id")
private int id;
#Transient
private Bar bar;
//....
#Column(name = "bar_id")
#Access(AccessType.PROPERTY)
private int getBarId
{
return bar.getId();
}
}
Another problem with the latter solution is that the getBarId() method in FooPK needs to have a setBarId(Int) method. Setting the Object using the ID can be done by accessing the data access layer, however this (in my opinion) violates the separation of business/domain/data layers.
So what to do? Go with the first solution and keep the ids in sync manually or is there another (best) practice?
Referring to the JPA 2: composite primary key classes discussion, make the following changes to the Foo and FooPK classes:
#Entity
public class Foo {
#EmbeddedId
private FooPK key;
#MapsId("barId") //references EmbeddedId's property
#JoinColumn(name = "bar_id", referencedColumnName = "id")
#ManyToOne
private Bar bar;
}
#Embeddable
public class FooPK {
#Column(name = "id")
private int id;
#Column(name = "bar_id")
private int barId;
}
I suggest first making it work with FIELD access and then apply PROPERTY access.
So what to do? Go with the first solution and keep the ids in sync
manually or is there another (best) practice?
Save yourself from pain - generate ids automatically.

Categories

Resources