I want use custom class like ID
#javax.persistence.Embeddable
class ObjectID impements Serializable{
private Long value;
//setters, getters and other
}
Here is mapped class
#Entity
#IdClass(ObjectID.class)
public class Country implements Serializable
{
#Id
#AttributeOverride(name = "value", column = #Column(name = "id"))
#SequenceGenerator(name = "CountrySequenceGenerator",
sequenceName = "lab_country_seq")
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "CountryCountryGenerator")
private ObjectID value;
// setters, getters, fields
}
Doesn't work. Value wasn't generated. Any ideas, how can I generate ID for composite-id?
Id class has to be Serializable and implements hashCode and equals
Related
I was following MappedSuperclass - Change SequenceGenerator in Subclass to move id field up to the AbstractEntity from all the child entity classes but also keeping their distinct sequences.
All entities extend a superclass called AbstractEntity like this:
#MappedSuperclass
#EntityListeners(RecordAuditorListener.class)
public class AbstractEntity implements Serializable {
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ID_GEN")
protected Integer id;
...
The child entity named Product:
#Entity
#SequenceGenerator(name = "ID_GEN", sequenceName = "SQ_PRODUCT", allocationSize = 1)
#Table(name = "PRODUCT")
#EntityListeners({OnProductChangeSyncRequestCreatorListener.class})
#XmlRootElement
public class Product extends AbstractEntity implements Attributable {
//This id field was removed from here
// #Id
// #Column(name = "ID", nullable = false)
// #GeneratedValue(generator = "SQ_PRODUCT")
// #SequenceGenerator(name = "SQ_PRODUCT", sequenceName = "SQ_PRODUCT", allocationSize = 1)
// private Integer id;
...
The child entity named Partner:
#Entity
#SequenceGenerator(name = "ID_GEN", sequenceName = "SQ_PARTNER", allocationSize = 1)
#Table(name = "PARTNER")
#EntityListeners({OnProductChangeSyncRequestCreatorListener.class})
#XmlRootElement
public class Partner extends AbstractEntity implements Attributable {
//This id field was removed from here
// #Id
// #Column(name = "ID", nullable = false)
// #GeneratedValue(generator = "SQ_PARTNER")
// #SequenceGenerator(name = "SQ_PARTNER", sequenceName = "SQ_PARTNER", allocationSize = 1)
// private Integer id;
...
When running the application I get this error message.
Exception Description: Conflicting annotations with the same name [ID_GENERATOR] were found. The first one [#javax.persistence.SequenceGenerator({allocationSize=1, name=ID_GENERATOR, sequenceName=sq_PARTNER})] was found within [...] and the second [#javax.persistence.SequenceGenerator({allocationSize=1, name=ID_GENERATOR, sequenceName=sq_PR_PRODUCT})] was found within [...]. Named annotations must be unique across the persistence unit..
In the related question it says that this is an incorrect solution in eclipselink 2.6.2. I am using eclipselink 2.6.9. is there a way that it can be done?
so I searched for the answers for my problem on the internet but didn't find something that helped, basically a need to have a ManyToOne Relationship between two classes, of which one of them has an EmbeddedId, I'm going to leave the code here and the error message that it gives (I'm using wildfly to run the server).
public class InventoryPK implements Serializable {
#ManyToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private Item itemId;
#ManyToOne
#JoinColumn(name="CD_EMPRESA")
private Company company;
}
#Entity
#Table(name = "inventario", schema = "mxnextmob")
public class Inventory extends BaseModel {
#EmbeddedId
private InventoryPK id;
#SequenceGenerator(schema = "mxnextmob", name = "inventory_sequence", sequenceName = "inventory_sequence", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "inventory_sequence")
private Integer inventory;
#Column
private BigDecimal quantity;
#Column
private BigDecimal weight;
}
public class Company extends BaseModel {
#Id
#SequenceGenerator(schema = "mxnextmob", name = "company_sequence", sequenceName = "company_sequence", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "company_sequence")
private Integer code;
#Column
private String name;
#OneToMany(mappedBy = "company")
private List<UserSeller> userSeller;
#OneToMany(mappedBy = "id.company")
private List<Inventory> inventories;
}
and the error is as follows:
service jboss.persistenceunit."mxnext-mobile.war#mxnextmobileDS":
org.hibernate.AnnotationException: mappedBy reference an unknown
target entity property:
br.com.maxiconsystems.mobile.model.Inventory.company in
br.com.maxiconsystems.mobile.model.Company.inventory
There are a few ways to map what you seem to have as a table, but I'd recommend Inventory be changed to something like:
public class Inventory extends BaseModel {
#Id
#SequenceGenerator(schema = "mxnextmob", name = "inventory_sequence", sequenceName = "inventory_sequence", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "inventory_sequence")
private Integer inventory;
#Embedded
private InventoryPK alternateKey;
#Column
private BigDecimal quantity;
#Column
private BigDecimal weight;
}
This allows you to use the inventory Integer as its primary key; this simplifies any future references you may need to add to Inventory, as foreign keys would be required in JPA to reference all its ID columns.
We create more than 100 tables in a schema in our application we used GenerationType.IDENTITY but this strategy does not support batching insert so we wanna switch to GenerationType.SEQUENCE.
#MappedSuperclass
public abstract class DataObject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgen")
#Column(name = "id")
private int id;
}
#Entity
#SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "entityaseq")
#Table(name = "entity_a")
public class EntityA extends DataObject {
}
#Entity
#SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "entitybseq")
#Table(name = "entity_b")
public class EntityB extends DataObject {
}
Reference:
https://hibernate.atlassian.net/browse/HHH-12329?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel
But this creates one table sequence for each table entity and this is very over.
Can there be any workaround to make a shared table for all entities?
Shared sequence for all Entities that extend DataObject:
First define the sequence in the MappedSuperclass:
#MappedSuperclass
public abstract class DataObject implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="idgen")
#SequenceGenerator(name="idgen", sequenceName="entity_seq", allocationSize=1)
#Column(name = "id")
private int id;
}
Then remove any annotations about sequence from your Entities:
#Entity
#Table(name = "entity_a")
public class EntityA extends DataObject {
}
#Entity
#Table(name = "entity_b")
public class EntityB extends DataObject {
}
This way suppose you save EntityA and gets id 1, a subsequent save to EntityB will use the same sequence and will get id 2.
Given a table (MY_TABLE_A) that automatically increments it's id upon each new insertion (i.e. the first record in the database has it's ID attribute 1, the second record has it's ID attribute set to 2, the third record has it's ID attribute set to 3). The ID I am talking about is the table's primary key.
I also have another table (MY_TABLE_B) that reference's the original table's primary key. When I try to persist both to my Oracle database, I get a org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save()
What I want to accomplish: Whenever I persist an object to MY_TABLE_A, I want MY_TABLE_B to insert an object with the same ID that MY_TABLE_A gets since it's auto incremented (wouldn't know what the next value is until it's inserted). To clarify, one id in Table A should have only one matching ID in Table B
Here are some snippets of my code below:
FirstClass:
#Entity
#Table(name = "MY_SCHEMA.MY_TABLE_A")
#Component
public class FirstClass implements Serializable {
#Id
#SequenceGenerator(name = "MY_SEQ", sequenceName = "MY_SCHEMA.MY_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MY_SEQ")
#Column(name = "MY_ID")
private Integer myId;
// more variables, getters/setters
}
SecondClass:
#Entity
#Table(name = "MY_SCHEMA.MY_TABLE_B")
#SecondaryTable(name = "MY_SCHEMA.MY_TABLE_A", pkJoinColumns = #PrimaryKeyJoinColumn(name = "MY_ID", referencedColumnName = "MY_ID"))
#Component
public class SecondClass {
#Id
#Column(name = "MY_ID")
private Integer myId;
// more variables, getters/setters
}
Service Layer snippet where I insert new entries for each in Oracle:
firstClassService.insert();
secondClassService.insert();
Details on insert() for firstClassService:
public void insert() {
FirstClass obj = new FirstClass();
getCurrentSession().persist(obj);
}
insert() for secondClassService:
public void insert() {
SecondClass obj = new SecondClass();
getCurrentSession().persist(obj);
}
UPDATE
What FirstClass looks like now:
#Entity
#Table(name = "MY_SCHEMA.MY_TABLE_A")
#Component
public class FirstClass implements Serializable {
#Id
#SequenceGenerator(name = "MY_SEQ", sequenceName = "MY_SCHEMA.MY_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MY_SEQ")
#Column(name = "MY_ID")
#OneToOne(mappedBy = "myId")
private Integer myId;
}
SecondClass:
#Entity
#Table(name = "MY_SCHEMA.MY_TABLE_B")
#SecondaryTable(name = "MY_SCHEMA.MY_TABLE_B", pkJoinColumns = #PrimaryKeyJoinColumn(name = "MY_ID", referencedColumnName = "MY_ID"))
#Component
public class SecondClass implements Serializable {
#Id
#JoinColumn(name = "MY_ID", referencedColumnName = "MY_ID")
#OneToOne
private Integer restRequestId;
}
Mappings should be as below:
#Entity
#Table(name = "MY_SCHEMA.MY_TABLE_A")
#Component
public class FirstClass implements Serializable {
#Id
#SequenceGenerator(name = "MY_SEQ", sequenceName = "MY_SCHEMA.MY_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MY_SEQ")
#Column(name = "MY_ID")
private Long myId;
#OneToOne(mappedBy = "firstClass", cascade = CascadeType.ALL)
private SecondClass secondClass;
}
#Entity
#Table(name = "MY_SCHEMA.MY_TABLE_B")
#Component
public class SecondClass implements Serializable {
#Id
#JoinColumn(name = "MY_ID", referencedColumnName = "MY_ID")
#OneToOne
private FirstClass firstClass;
}
With the Cascade option set then you you will only need to make the call to save firstClass: the associated secondClass will be persisted automatically - assuming you set both sides of the relationhsip in your in-memory model i.e.
firstClass.setSecondClass(secondClass);
secondClass.setFirstClass(firstClass);
Add #GeneratedValue(strategy=GenerationType.IDENTITY) to the id of second class.
#Id
#Column(name = "MY_ID")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer myId;
// more variables, getters/setters
From your description it seems like you have a ManytoOne relation, as your table B references table A, then it's logic to say A has a list of Bs somewhat, so why not take advantage of what ORM actually is and why not keep a reference in A such as:
#OneToMany(mappedBy="aa")
private List<B> bs;
and use the annotation in the other entity:
#ManyToOne
#JoinColumn(name = "myId" , referencedColumnName = "id")
private A aa;
That in combination to what Jens suggested, see OracleDialect does not support identity key generation
I have class for ID
#org.hibernate.annotations.AccessType("property")
public class ObjectID implements java.io.Serializable
{
private long value;
long getValue()
{
return value;
}
void setValue(Long id)
{
value = id != null ? id : 0L;
}
// equals, hash, contructor
}
And have mapped class (Patient) that used this ID-class. I want generate long value in ObjectID class. help me.
I tried
public class Patient implements Serializable
{
#javax.persistence.Id
#javax.persistence.Column(name = "aa_id")
#org.hibernate.annotations.Formula("case when aa_id is null then patient_seq.nextval else aa_id end")
#javax.persistence.AttributeOverride(name = "value", column = #Column(name = "aa_id"))
private ObjectID id;
}
and
public class Patient implements Serializable
{
#javax.persistence.Id
#javax.persistence.SequenceGenerator(name = "PatientSequenceGenerator",
sequenceName = "patient_seq")
#javax.persistence.GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "PatientSequenceGenerator")
#javax.persistence.AttributeOverride(name = "value", column = #Column(name = "aa_id"))
private ObjectID id;
}
But there are not helpful
One of resolves of this situation is to write custom userType for ObjectID and write custom ID-generator.
compositeIds are normally assigned by the program and i do not know if there is even a possibility to set it (or parts of it) through a databasesequence out of the box.
first you could try to set it this way to see if it works:
public class Patient implements Serializable
{
#Id
#SequenceGenerator(name = "PatientSequenceGenerator", sequenceName = "lab_patient_seq")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PatientSequenceGenerator")
private Long id;
}