JPA/Hibernate primary key value sequence using current year - java

I am using Spring 3 and Hibernate 4
I have the following in Entity class
#Id
#Column(name = "PROJECT_NO")
private String projectNumber;
When I insert values into database table, is it possible to insert PROJECT_NO value which is the Primary key in the following format
20131 where 2013 is the current year and next character should be incremental by one. i.e. next value to be inserted should be 20132
How can I achieve this using JPA/Hibernate

You have to look at #GeneratedValue and #GenericGenerator annotation.
There are several possibilities to generate value. In your case I believe the you need to create something like the following:
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "year_gen")
#GenericGenerator(name = "year_gen", strategy = "com.example.generator.CustomGenerator")
#Column(name = "PROJECT_NO")
private String projectNumber;
And CustomGenerator should implement org.hibernate.id.IdentifierGenerator

What about putting the JPA annotation on the getter and using the getter method to format the data as you like?
#Entity
public class MyClass {
private String projectNumber;
#Column(name = "PROJECT_NO")
public String getProjectNumber(){
return doSomeFormatting(this.projectNumber);
}
}
Something like that should work.

Related

idMoneda property not updated in DB with #Transient directive

I have this entity, in which I have made a PUT and POST method, which do not give an error but nevertheless the idMoneda, which is a property calculated with #Transient because it is the ID of the moneda(where there is a 1 to 1 relationship with another table), it does not update me, when I look at the database it remains null even though in the POST request I put a value. I don't know if it's because the setter is wrong, or just that something else needs to be added that I don't see right now.
#Entity
#Table(name = "REMESA")
public class Remesa {
#Id
#SequenceGenerator(name = "remesa_sequence", sequenceName = "remesa_sequence", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "remesa_sequence")
#Column(name = "ID")
private Long id;
#OneToOne
#JoinColumn(name = "moneda", nullable = true)
#JsonIgnore
private Moneda moneda;
#Transient
#JsonProperty("moneda")
private Long idMoneda;
public Long getIdMoneda() {
return this.moneda.getId();
}
public void setIdMoneda(Long idMoneda) {
this.idMoneda = idMoneda;
}
}
#Transient in JPA means: do not save this field in DB. A column named "moneda_id" will automatically be generated by your relationship if it's well-defined
Java's transient keyword is used to denote that a field is not to be serialized, whereas JPA's #Transient annotation is used to indicate that a field is not to be persisted in the database, i.e. their semantics are different. Because they have different meanings.
So try to remove the transient annotation and run your code .

How to provide Initial value OR Increment ID with JPA GenerationType.AUTO

I am using following code to define MyEntity,
#Entity
#Table(name = "MY_TABLE")
public class MyEntity {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "MY_TABLE_ID")
private Integer myTableId;
#Column(name = "MY_TABLE_NM")
private String myTableName;
//Getters Setters
}
For the first POST after my application starts, I create MyEntity everything works fine, MY_TABLE_ID starts with 1 and works as expected.
My issue is, If somebody inserts data manually before I do my POST then I get duplicate key exception as myTableId is entered as 1 which is already present.
My main problem is I can't create database sequence for using GenerationType.SEQUENCE now to resolve this as database can't be altered now.
I have tried various combinations of GenerationType, TableGenerator but I am unable to successfully tackle it.
Setting initialValue to some larger number to avoid duplicate values can temporarily resolve my problem but I am unable to do it too.
If someone can help me with initialValue with AUTO or give me some other better solution without database changes will be great :)
As MY_TABLE_ID is an identity column, following annotations will work.
#Entity
#Table(name = "MY_TABLE")
public class MyEntity {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY) // <-- IDENTITY instead of AUTO
#Column(name = "MY_TABLE_ID")
private Integer myTableId;
#Column(name = "MY_TABLE_NM")
private String myTableName;
//Getters Setters
}
The identity column will automatically assign an value as soon as the transaction is committed. You are not to set any values for an identity column, as its the job of the database to assign the values. Therefore you also don't need to think about any initial values (forget them completely for identity columns)
I tried various options in answers provided here and for similar questions on stackoverflow and other forums,
I had few limitations,
I couldn't create database sequence as my database changes were freezed.
I didn't want to introduce new Custom IdGenerator class because it would add confusion to other people working with me.
It was resolved using following change:
Adding GenericGenerator with increment strategy helped me, I made following changes to my code.
#Entity
#Table(name = "MY_TABLE")
public class MyEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator="seq")
#GenericGenerator(name = "seq", strategy="increment")
#Column(name = "MY_TABLE_ID")
private Integer myTableId;
#Column(name = "MY_TABLE_NM")
private String myTableName;
//Getters Setters
}
It helped me because,
From Hiberbate DOCs
increment
An IdentifierGenerator that returns a long, constructed by counting
from the maximum primary key value at startup. Not safe for use in a
cluster!
Since, it was incrementing already existing myTableId even if it was manually inserted, this resolved my issue.
You can also implement your own generator if you need more control.
See this interface IdentifierGenerator.
So you can get the count of records, for example through a #NamedQuery.
Then you can generate an identifier yourself.
public class MyEntityKeyGenerator implements IdentifierGenerator {
#Override
public Serializable generate(SessionImplementor session, Object object) {
// SELECT count(ent) from MyEntity ent;
Long count = (Long) session.getNamedQuery("count-query").uniqueResult();
// calc and return id value
}
}
Entity:
class MyEntity {
#Id
#GenericGenerator(name = "my_generator",
strategy = "org.common.MyEntityKeyGenerator")
#GeneratedValue(generator = "my_generator")
private Long id;...
Just do not forget about the lock.
I use the generation type Identity, which basically means that the db, takes care of Id generation.
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#MappedSuperclass
#EntityListeners(EntityListener.class)
#EqualsAndHashCode(of = {"id", "createdAt"})
public abstract class AbstractEntity<ID extends Serializable> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private ID id;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATED_AT", updatable = false)
private Date createdAt;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATED_AT")
private Date updatedAt;
}
You can also use, Sequence generation:
#Entity
#SequenceGenerator(name="seq", initialValue=1, allocationSize=100)
public class EntityWithSequenceId {
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
#Id long id;
}

How to create hibernate composite key and get values from table

I am trying to use hibernate annotations for getting data from a MySQL database table which doesn't have a primary key defined.
However the fact is 2 columns of that table together are unique in the table. How can I achieve the same using hibernate annotation?
This is my code
#Entity
#Table(name = "coc_order_view")
public class CoCOrderDetailsTest {
#EmbeddedId
private MyJoinClassKey key;
#Column(name = "coupon_code")
private String couponCode;
some other columns and their getters and setters .....
#Embeddable
public class MyJoinClassKey implements Serializable {
private static final long serialVersionUID = -5L;
#Column(name = "product_id")
private int productId;
#Column(name = "order_id")
private int orderId;
gettes and setters....
And here is my criteria query
Criteria criteria = getHibernatetemplate().getSession().createCriteria(CoCOrderDetailsTest.class);
criteria.add(Restrictions.eq("status", "New"));
ArrayList<CoCOrderDetailsTest> orderDet = (ArrayList<CoCOrderDetailsTest>) getHibernatetemplate().get(criteria);
I am unable to get all the values from db. Kindly suggest some solutions.
After reading through your question again not sure this will help. You can't have a table without primary key(s). Read the first couple of paragraphs in this article
That said, if you can alter the table and add primary keys on those fields you need to add #IdClass annotation to your class signature for CoCOrderDetailsTest and then get rid of the #embeddable and #embeddedId notation in your classes.
Another alternative, if you can add a field to the table, would be to use an #GeneratedValue on that added primary key field and of course annotate it with #Id.
If you can't alter the table then you can't use JPA and you'll have to use JDBC.
See http://docs.oracle.com/javaee/5/api/javax/persistence/IdClass.html
A working example:
#Entity
#Table(name = "player_game_log")
#IdClass(PlayerGameLogId.class)
public class PlayerGameLog {
#Id
#Column(name = "PLAYER_ID")
private Integer playerId;
#Id
#Column(name = "GAME_ID")
private String gameId;
....
and the id class (note there are no annotations on the id class)....
public class PlayerGameLogId implements Serializable {
private static final long serialVersionUID = 1L;
private Integer playerId;
private String gameId;
Try:
String hql = "FROM CoCOrderDetailsTest WHERE status = :status";
Query query = session.createQuery(hql);
query.setParameter("status","New");
List results = query.list();
I usually use EntityManager rather than session so I'm not familiar with this syntax - and I have typically added a type to the list to be returned - like:
List<CoCOrderDetailsTest> results = query.list();

Hibernate Criteria select using embedded object (tuple)

In my case I have a SQL query which looks like:
select * from event_instance where (object_id, object_type) in
(<LIST OF TUPLES RETRIEVED FROM SUBQUERY>);
I want to map this on Hibernate Entities and I have a problem with this query. My mapping looks like that:
#Entity
#Table(name="event_instance")
public class AuditEvent {
<OTHER_FIELDS>
#Column( name = "object_type", nullable = false)
private String objectType;
#Column( name ="object_id" , nullable = false)
private Integer objectId;
}
and second entity:
#Entity
#Table(schema = "els" ,name = "acg_objects")
public class AcgObject implements Serializable{
#Id
#Column(name = "acg_id")
private String acgId;
#Id
#Column(name="object_type")
private String objectType;
#Id
#Column(name="object_id")
private Integer objectId;
<OTHER FIELDS>
}
I already run query for getting AcgObjects and for my DAO I'm getting List only thing I want to do is query a touple using criteria like:
crit.add(Restrictions.in("objectType,objectId",<List of tuples>);
Is it possible? I was trying to use #Embedded object but don't know how exactly construct a query for it. Please help
You can do that not in standard SQL nor using criteria; you have to split in two distinct restrictions or using a Session.SQLQuery() if you want to use specific RDBMS (look at SQL WHERE.. IN clause multiple columns for an explanation)

Autoincrement column in oracle using hibernate

I am using hibernate annotations. I want to make a column as autoincremented. I have created a sequence in database(oracle) and mapped that sequence in java POJO class. Do I need to create trigger for that sequence too? I want to know how we can make a column autoincremented while using hibernate anotation? What changes i have to do in java and as well as database side? Please help me in this. Following is the part of code where I have mapped the sequence.
public class SimRuns implements Serializable {
private static final long serialVersionUID = 8698324570356602407L;
#Id #Column(name = "RUN_ID")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_run_id")
#SequenceGenerator(name="seq_run_id", sequenceName="seq_run_id")
private Long runId;
}
This works for me:
#Id
#GeneratedValue(generator = "nosicSeq")
#SequenceGenerator(name = "nosicSeq", sequenceName = "NOSIC_SEQ", allocationSize = 1)
#Column(name = "SID")
private BigDecimal sid;
no triggers in DB needed, just sequence.
Try removing the generator and setting to auto the generationType
#Id #Column(name = "RUN_ID")
#GeneratedValue(strategy=GenerationType.AUTO)
#SequenceGenerator(name="seq_run_id", sequenceName="seq_run_id")
private Long runId;
Hibernate is probably the only JPA Provider that selects the right Generationstrategy based on your databasetype. Using the GenerationType.AUTO statement hibernate will try to select the best strategy to implement an increasing row id.
In Oracle : It's no need for an Oracle trigger, but the sequence is must.
In pojo: you can use Annotations like this:
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="majorsSeq")
#SequenceGenerator(name="majorsSeq", sequenceName="MAJORS_SEQ", allocationSize = 1,initialValue = 1)
public int getId() {
return id;
}

Categories