How to save without using autogenerated in JPA? - java

I am using oracle database with JPA, I have an id column this is not auto generated type.
While performing saveAll() operation we are getting - ids for this class must be manually assigned before calling save():
This is Id i am getting form some other table
#Entity
#Table(name = "area_usr")
public class AreaUsr {
#Id
private Integer usrId;
private String area;
//getter setter
}
List<AreaUsr> au = xyzRepo.getAreaInfo();
areaUsrRepo.saveAll(au); // here i am getting the error

Because ids can't be null ,and since it's not auto generated ,it must be specified before getting persisted.

Related

JPA 2.1 persist string as enum postgres

I am using JPA 2.1 to perform CRUD operations on my DB. I generated entities from a pre-existing DB using JPA Tools -> Generate entities from Tables option. This created a Java entity named Item.
The DB table Item has a column of type enum item_status which was created as String type in the Java entity. Now I am trying to insert a column into table Item using the following method and got this error
ERROR: column "status" is of type item_status but expression is of type character varying. Hint: You will need to rewrite or cast the expression.
Item_Test_CRUD.java
// Here I am trying to test if I can insert into the DB
#Test
void test_insert_into_db() {
DBConnection conx = new DBConnection(); // here I get the message login successful, so I assume the connection to the DB is okay
Item it = new Item();
it.setStatus("Rework");
it.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
it.setMetadata("{}");
conx.insert(it);
}
// I am using EntityManager to connect to the DB
DBConnection.java
public void insert(Object obj) {
this.em.getTransaction().begin();
this.em.persist(obj);
this.em.getTransaction().commit();
}
// Entity generated by the JPA tool
Item.java
#Entity
#Table(name="\"Items\"")
#NamedQuery(name="Item.findAll", query="SELECT i FROM Item i")
public class Item implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Convert(converter=UUIDConverter.class)
private String id;
.
.
#Column(name="status")
private String status;
.
.
}
Any idea what mistake I am doing here ?
Resolved the issue by adding stringtype=unspecified to the connection string. I didn't have to change the java entity column's type to enum. Just left it as String type.
For more information : stackoverflow.com/a/43125099/270371
https://jdbc.postgresql.org/documentation/94/connect.html

Alternative to save in JPA/Hibernate with non autogenerated ID

I'm trying to insert a value into a database with type String in ID.
#Entity
#Table(name = "xpto_version_map")
public class XptoVersionMap implements Serializable {
#Id
#Column(name = "uniq_name", unique = true, nullable = false)
private String uniq_name;
...
When trying to save a new XptoVersionMap() like:
XptoVersionMap xptoVersionMap = new XptoVersionMap();
xptoVersionMap.setUniqName("XPTO-1");
xptoVersionMap.setValue("value2");
xptoVersionMapRepository.save(xptoVersionMap);
Will throw:
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find xxx.api.database.entity.XptoVersionMap with id XPTO-1; nested exception is javax.persistence.EntityNotFoundException: Unable to find xxx.api.database.entity.XptoVersionMap with id XPTO-1.
I've tried different solutions, but unless I can make a native query to insert the value, I can't have a way to tell Hibernate that I want to just check if the #Id (uniq_name) exists, if not insert the new value and not to throw an exception.
That's how Hibernate works by default. It assigns an automated generated ID when you do save method and ID is not set. If there is an ID it tries to update it (what happens in your case).
save Persists an entity. Will assign an identifier if one doesn't
exist. If one does, it's essentially doing an update. Returns the
generated ID of the entity.
You can do a workaround for example by using persist and #PrePersist
#PrePersist
void generateId() {
if (uniq_name == null) {
uniq_name = GENERATE_SOME_UNIQUE_ID_SO_IT_DOESN'T_BREAK();
}
}
And then use xptoVersionMapRepository.persist(xptoVersionMap);
Or you can write your own generator with something like that:
#GenericGenerator(name = "my_generator", strategy = "package.CustomGenerator")
#GeneratedValue(generator = "my_generator")
And then create a class CustomGenerator that implements IdentifierGenerator and create the required methods.

Mapping a Transient Property to an Alias - Spring JPA

Is it possible in Spring JPA to map a Transient property of an Object to an alias like so?
Native Query
SELECT *, 1 AS liked FROM User WHERE user_id = 123 // + logic to determine if liked
Class
#Entity
public class User {
#Id
private Long userId;
#Column(name = "displayName")
private String displayName;
#Transient
private int liked; // not tied to any column
}
I've tried to implement this but liked always returns 0 where it should be 1 (and null if I defined the field as an Object type)
Any help is appreciated!
You should use #Formula annotation for the field (see the example)
The #Formula annotation to provide an SQL snippet which Hibernate will execute when it fetches the entity from the database. The return value of the SQL snippet gets mapped to a read-only entity attribute.

JPA, change field value using java on UPDATE/merge

I have an entity with a field updatedUser which keeps track of the user who updated the row values.
When the entity is created this field is null but it should be set when a change is made to the entity and merge is used.
Is there some way, through java, to fill this value only when the entity has been updated? IE: should not be changed if it is created or retrieve from db.
#Entity
#Table(name="employees", uniqueConstraints= {
#UniqueConstraint(columnNames="idEmployees"),
#UniqueConstraint(columnNames="idCardNumber"),
#UniqueConstraint(columnNames="niNumber")
})
public class Employee {
#Id
#GeneratedValue
#Column(unique=true, nullable=false, updatable=false)
private int idEmployees;
//other class variables
#ManyToOne(cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
#JoinColumn(name="updatedEmployeeId")
private Employee updatedEmployee;
//constructors, getters and setters
}
Updating a value is possbile by using the javax.persistence.PreUpdate annotation. But there is no way to inject the current user. Maybe it is possible to read the user from ThreadLocal and then set the user, but that is not a really clean solution as it must be set before when entering your business code or so ..

Hibernate error: ids for this class must be manually assigned before calling save():

Caused by: org.springframework.orm.hibernate3.HibernateSystemException: ids for this class must be manually assigned before calling save(): com.rfid.model.Role; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.rfid.model.Role
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:676)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:748)
at com.wfos.engine.wrapper.domain.impl.WrapperImpl.save(WrapperImpl.java:159)
... 47 more
Caused by: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.rfid.model.Role
at org.hibernate.id.Assigned.generate(Assigned.java:53)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:685)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:673)
at org.springframework.orm.hibernate3.HibernateTemplate$16.doInHibernate(HibernateTemplate.java:751)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
... 50 more
WARN [21:14:21] (CommonsLoggingOutput.java:59): - --Erroring: batchId[1] message[java.lang.reflect.UndeclaredThrowableException]
My class is like this:
#Entity
#javax.persistence.Table(name="Role")
#Table(appliesTo = "Role")
public class Role {
#Id
#Column(name="U_id")
public String U_id;
public String U_pwd;
public String U_account;
public String U_mode;
public String U_status;
public String getU_pwd() {
return U_pwd;
}
public void setU_pwd(String u_pwd) {
U_pwd = u_pwd;
}
public String getU_account() {
return U_account;
}
public void setU_account(String u_account) {
U_account = u_account;
}
public String getU_id() {
return U_id;
}
public void setU_id(String u_id) {
U_id = u_id;
}
public String getU_mode() {
return U_mode;
}
public void setU_mode(String u_mode) {
U_mode = u_mode;
}
public String getU_status() {
return U_status;
}
public void setU_status(String u_status) {
U_status = u_status;
}
}
Your #Entity class has a String type for its #Id field, so it can't generate ids for you.
If you change it to an auto increment in the DB and a Long in java, and add the #GeneratedValue annotation:
#Id
#Column(name="U_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long U_id;
it will handle incrementing id generation for you.
Resolved this problem using a Sequence ID defined in Oracle database.
ORACLE_DB_SEQ_ID is defined as a sequence for the table. Also look at the console to see the Hibernate SQL that is used to verify.
#Id
#Column(name = "MY_ID", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "id_Sequence")
#SequenceGenerator(name = "id_Sequence", sequenceName = "ORACLE_DB_SEQ_ID")
Long myId;
For hibernate it is important to know that your object WILL have an id, when you want to persist/save it. Thus, make sure that
private String U_id;
will have a value, by the time you are going to persist your object. You can do that with the #GeneratedValue annotation or by assigning a value manually.
In the case you need or want to assign your id's manually (and that's what the above error is actually about), I would prefer passing the values for the fields to your constructor, at least for U_id, e.g.
public Role (String U_id) { ... }
This ensures that your object has an id, by the time you have instantiated it. I don't know what your use case is and how your application behaves in concurrency, however, in some cases this is not recommended. You need to ensure that your id is unique.
Further note: Hibernate will still require a default constructor, as stated in the hibernate documentation. In order to prevent you (and maybe other programmers if you're designing an api) of instantiations of Role using the default constructor, just declare it as private.
Here is what I did to solve just by 2 ways:
make ID column as int type
if you are using autogenerate in ID dont assing value in the setter of ID. If your mapping the some then sometimes autogenetated ID is not concedered. (I dont know why)
try using #GeneratedValue(strategy=GenerationType.SEQUENCE) if possible
I got same error for different scenario. In my case my primary key of table is a VARCHAR value, so in the entity class(Entity1) ID is a String value, can't set it to auto generate. Also this entity join with another entity(Entity2).
When I set value of Entity1 to empty in updating Entity2 and calling save(), it's throw this exception. There setting empty string for id not work.
Entity2 e2 = new Entity2();
Entity1 e1 = new Entity1();
e1.setId("");
e2.setEntity1(e1);
session.update(e2);
Also setting null for id not work.
Entity2 e2 = new Entity2();
Entity1 e1 = new Entity1();
e1.setId(null);
e2.setEntity1(e1);
session.update(e2);
This way it's work.
Entity2 e2 = new Entity2();
e2.setEntity1(null);
session.update(e2);
Got this error with H2 database when mismatched type for numerical id value. Generated and populated table via number of sql statements and set id to be INT. Later created Entity Java class and set id to be Long. Issue was resolved after adjusting type of id in Java class.
if you want to give id's value manually like JSON or other way you can add #JsonProperty(" U_id") notation before your U_id variable
FROM UI you have to pass the ID (primary Key) Then observer you are saving or updating
if you are saving use save method or use saveOrUpdate method
change class field value in your entity.hbm.xml to identity or sequense like
<hibernate-mapping>
<class name="models.Manager" table="Managers">
<id name="id">
<generator class="identity"></generator>
</id>
<property name="name"></property>
<property name="surname"></property>
<property name="department"></property>
<property name="project_id"></property>
</class>
and add if you still dont have these code for your entity id:
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
that worked for me
I got this problem because I had 2 Id's annotations inside my entity class, one above my id field and one above my getter method
so make sure that there is only one Id annotation above your id field

Categories