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
Related
I have the class SWEntity that is central to the problem. I want set of classes SWEntityRow that is a detail of the SWEntity (one entity has many rows). The SWentity has in the key two other classes in the embeddedId Area and Procedure. When I try to map SWEntity with SWEntityRow using SWEntityRowId I take differents errors.
Some idea how I can map SWEntityRowId with SWEntity?
This is a simplified picture of the ER: https://i.stack.imgur.com/pMJzh.png
And this are my simplified classes:
SWentity
-----------
#Entity
public class SWEntity {
#EmbeddedId
private SWEntityId id;
[...]
}
SWEntityId
-------------
#Embeddable
public class SWEntityId implements Serializable{
private static final long serialVersionUID = 1L;
#NotNull
private String name;
#NotNull
private int version;
#ManyToOne
#JoinColumn(name = "areaName", nullable = false)
#JsonIgnore
private Area area;
#ManyToOne
#JoinColumn(name = "procedureName", nullable = false)
#JsonIgnore
private Procedure procedure;
}
SWEntityRow
---------------
#Entity
public class SWEntityRow{
#EmbeddedId
private SWEntityRowId sWEntityRowId;
}
SWEntityRowId
---------------
#Embeddable
public class SWEntityRowId implements Serializable {
private static final long serialVersionUID = 1L;
private String rowName;
//SWEntityId
#ManyToOne
#JoinColumns({
#JoinColumn(name="name_row", referencedColumnName="name"),
#JoinColumn(name="version_row", referencedColumnName="version"),
#JoinColumn(name="area_row", referencedColumnName="area_name"),
#JoinColumn(name="procedure_row", referencedColumnName="procedure_name"
})
}
This resolve my question
# JoinColumns({
#JoinColumn(name="entityname", referencedColumnName="name"),
#JoinColumn(name="entityversion", referencedColumnName="version"),
#JoinColumn(name="entityarea", referencedColumnName="AreaName"),
#JoinColumn(name="entityprocedure", referencedColumnName="ProcedureName")
})
The difference is in referencedColumnName="AreaName" not referencedColumnName="area_name" and the same for procedure.
Thanks!
Just one change required
#Entity
public class SWEntity {
#Id
#EmbeddedId
private SWEntityId id;
[...]
}
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.
when I test some things about mapping relationship of #OneToOne in Hibernate, and I use spring-data-jpa to query. For the bidirectional relationship of the #OneToOne, when I query an entity, it will occurred two conditions:
when no data in two tables, no errors;
when data is stored in two tables, just StackOverflowError;
the related code in the next:
#Entity
public class Person {
#Id
#GeneratedValue
private Integer personId;
private String name;
#OneToOne
private IdCard idCard;
// setter&getter
}
#Entity
public class IdCard {
#Id
#GeneratedValue
private Integer number;
private String area;
#OneToOne(mappedBy="idCard")
private Person person;
}
PersonDao:
#Transactional
#Repository
public interface PersonDao extends CrudRepository<Person, Integer> {
public Person findByPersonId(Integer personId);
}
IdCardDao:
#Transactional
#Repository
public interface IdCardDao extends CrudRepository<IdCard, Integer> {
public IdCard findByNumber (Integer number);
}
test code:
Person person = personDao.findByPersonId(1);
System.out.println(person);
IdCard idCard = idCardDao.findByNumber(123);
System.out.println(idCard);
I search some answers in the website, find a related question, StackOverFlowError while doing a One-To-One relationship in GAE Datastore using JPA 2.0
but I did not instantiate the entity explicitly, so no recurses. use jpa 2.1
Any solutions?
I had the same problem in #OneToOne relationship, and the solution for the java.lang.StackOverflowError: null is to use fetch LAZY in the owing side of the relationship.
#Entity
public class Person {
#Id
#GeneratedValue
private Integer personId;
private String name;
#OneToOne (fetch = FetchType.LAZY)
private IdCard idCard;
// setter&getter
}
#Entity
public class IdCard {
#Id
#GeneratedValue
private Integer number;
private String area;
#OneToOne(mappedBy="idCard")
private Person person;
}
Try like this, you can map with one end., for OneToOne and ManyToOne at the receiving end you don't need to mention,
#Entity
public class Person {
#Id
#GeneratedValue
private Integer personId;
private String name;
#OneToOne
private IdCard idCard;
// setter&getter
}
#Entity
public class IdCard {
#Id
#GeneratedValue
private Integer number;
private String area;
private Person person;
}
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.
I have the next relationship:
Currently, I have the next code:
#Embedded
public class StockPK implements Serializable {
private int storeId;
private int productId
}
#Entity
public class Stock implements Serializable {
#EmbeddedId
private StockPK id;
private int cantidad;
#ManyToOne
private Store store;
#ManyToOne
private Product product;
}
But the DDL generated (I'm using OpenJPA in TomEE) adds two aditional fields.
CREATE TABLE STOCK (
productId INTEGER NOT NULL,
storeId INTEGER NOT NULL,
quantity INTEGER NOT NULL,
PRODUCT_ID INTEGER ,
STORE_ID INTEGER ,
PRIMARY KEY (productId, storeId)
)
How should specify this relationship?
Thanks JBNizet :) — The solution was as follows:
#Embeddable
public class StockPK implements Serializable {
#Column(name = "store_id")
private int storeId;
#Column(name = "product_id")
private String productId;
// Getters, setters, hashCode, equals
}
#Entity
#Table(name = "stock")
public class Stock implements Serializable {
#EmbeddedId
private StockPK id;
#MapsId("storeId")
#ManyToOne
private Store store;
#MapsId("productId")
#ManyToOne
private Product product;
#Column(nullable = false)
private int quantity;
// Getters, setters
}
#Entity
#Table(name = "store")
public class Store implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
// Other fields, getters, setters ...
}
#Entity
#Table(name = "product")
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
// Other fields, getters, setters ...
}