Can I create my own sequence in Hibernate, like I have a database sequence and I have to add 2 characters before the sequence?
You can create your own identifier generator. Have a look at this blog post which is basically showing how to do something similar to what you're looking for (unless I misundertsood the question):
Custom Hibernate Sequence Generator for Id field
I have a table with a primary key in
the format M001, M002 etc (lets not
think about what happens after M999
for now). I’m using Hibernate
Annotations, and I found a great way
of generating the Primary Key value
for new Records:
First I created a database sequence to
use. Then I implemented
org.hibernate.id.IdentifierGenerator;
public class StockCodeGenerator implements IdentifierGenerator {
private static Logger log = Logger.getLogger(StockCodeGenerator.class);
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
String prefix = "M";
Connection connection = session.connection();
try {
PreparedStatement ps = connection
.prepareStatement("SELECT nextval ('seq_stock_code') as nextval");
ResultSet rs = ps.executeQuery();
if (rs.next()) {
int id = rs.getInt("nextval");
String code = prefix + StringUtils.leftPad("" + id,3, '0');
log.debug("Generated Stock Code: " + code);
return code;
}
} catch (SQLException e) {
log.error(e);
throw new HibernateException(
"Unable to generate Stock Code Sequence");
}
return null;
}
}
Then, in my entity class, I simply
annotate the id field like this:
#Id
#GenericGenerator(name="seq_id", strategy="my.package.StockCodeGenerator")
#GeneratedValue(generator="seq_id")
#Column(name = "stock_code", unique = true, nullable = false, length = 20)
public String getStockCode() {
return this.stockCode;
}
Try this one. With Date and Calender
public class StockCodeGenerator
implements IdentifierGenerator
{
private static Logger log = Logger.getLogger(StockCodeGenerator.class);
public StockCodeGenerator() {}
public int generateCustId()
{
Random random = new Random();
return random.nextInt(100);
}
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException
{
String prefix = "Custom_String";
Connection connection = session.connection();
System.out.println(session.connection());
Date date = new Date();
Calendar calendar = Calendar.getInstance();
return prefix + "_" + generateCustId() + "_" + calendar.get(1);
}
}
And then use it in your #GenericGenerator annotation
#Id
#GenericGenerator(name="seq_id",strategy="com.mvc.StockCodeGenerator.
StockCodeGenerator")
#GeneratedValue(generator="seq_id")
Related
I'm trying to use JOOQ without code generation. I have a dao class that looks like this
public class FilesDao {
public List<FilePojo> getAllFiles() {
DataSource dataSource = DataSourceFactory.getTestiDataSource();
List<FilePojo> filePojos = new ArrayList<>();
try (Connection con = dataSource.getConnection()) {
DSLContext create = DSL.using(con, SQLDialect.MARIADB);
filePojos = create.select(field("tiedosto.id"), field("tiedosto.nimi"), field("tiedosto.koko_tavua"),
field("tiedosto.sisalto"), field("tiedosto.hlo_id"))
.from(table("tiedosto"))
.where(field("minioupload").eq((byte) 0))
.fetch().into(FilePojo.class);
} catch (SQLException e) {
e.printStackTrace();
}
return filePojos;
}
}
and a Pojo class that looks like this
import javax.persistence.Column;
import javax.persistence.Table;
#Table(name="tiedosto")
public class FilePojo {
#Column(name = "id")
private Integer id;
#Column(name = "hlo_id")
private Integer customerId;
#Column(name = "koko_tavua")
private Integer fileSize;
#Column(name = "nimi")
private String fileName;
#Column(name = "sisalto")
private byte[] content;}
//Getters setters omitted
When I try to read from the table using a main method like this
public class App {
public static void main(String[] args) {
FilesDao mydao = new FilesDao();
List<FilePojo> myList = mydao.getAllFiles();
for (FilePojo filePojo : myList) {
System.out.println("==========================================" + "\n" +
filePojo.getId() + " " +
filePojo.getCustomerId() + " " +
filePojo.getFileName() + " " +
filePojo.getFileSize() + " " +
filePojo.getContent() + " " +
"==========================================");
}
}
}
The output is as follows
I can see that the SQL query is running fine and listing all the matched rows, but pojo is returning null values. What am I doing wrong here? Can someone please point me to the right direction? I'd really appreciate any sort of help.
I'm undecided whether this is a bug or a feature. You're using the plain SQL templating API when you should probably be using the identifier building API. When you write
field("tiedosto.id")
Then, jOOQ (possibly erroneously) thinks that your column is named `tiedosto.id`, with a period in the name. When it should really be qualified as `tiedosto`.`id`. There are a few possible fixes:
Keep using the plain SQL templating API
But then, don't qualify the name:
field("id")
Use the identifier building API
field(name("tiedosto", "id"))
Use the code generator
This should always be your preferred option, of course.
i am using Hibernate OGM (5.2.0.Alpha1) with Mongodb (3.6)
#Entity
#Table(name = "currency_master)
#JsonInclude(Include.NON_EMPTY)
public class CurrencyMaster{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonSerialize(using = ToStringSerializer.class)
#Column(name = "CURRENCY_ID", unique = true, nullable = false)
private ObjectId id;
private String code;
#OneToMany(mappedBy = "currencyMaster")
private Set<PurchaseOrder> setOfPurchaseOrder;
getter()
setter()
}
#Entity
#Table(name = "purchase_order)
#JsonInclude(Include.NON_EMPTY)
public class PurchaseOrder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonSerialize(using = ToStringSerializer.class)
#Column(name = "PURCHASE_ORDER_ID", unique = true, nullable = false)
private ObjectId id;
private String purchaseOrderNo;
private Double total;
#ManyToOne
#JsonIgnore
private CurrencyMaster currencyMaster;
getter()
setter()
}
DAO Layer:
#SuppressWarnings("unchecked")
#Override
public <T> void update(T t) {
try {
Field[] fields = t.getClass().getDeclaredFields();
Map<String, Object> mapUpdatedFields = new HashMap<String, Object>();
for (Field field : fields) {
field.setAccessible(true);
mapUpdatedFields.put(field.getName(), field.get(t));
}
T newT = this.getById(mapUpdatedFields.get("id").toString(), t);
mapUpdatedFields.remove("id");
mapUpdatedFields.forEach((k, v) -> {
if (!AccountingMethodUtils.isObjectisNullOrEmpty("update()", v)) {
AccountingMethodUtils.setValueToField(newT, k, v);
}
});
entityManager.merge(newT);
} catch (Exception e) {
e.printStackTrace();
LOGGER.error(
"update() of DAO : (Error in outer try..catch) Error in updating record of {} and Error is {}.",
t.getClass(), e);
}
}
#Override
public <T> List<T> executeQuery(String query, Integer startPosition, Integer noOfRecords, T t) {
List<T> listOfT = new ArrayList<>();
if (AccountingMethodUtils.isObjectisNullOrEmpty(startPosition, noOfRecords)) {
listOfT = entityManager.createNativeQuery(query.toString(), t.getClass()).getResultList();
} else {
listOfT = entityManager.createNativeQuery(query.toString(), t.getClass()).setFirstResult(startPosition)
.setMaxResults(noOfRecords).getResultList();
}
return AccountingMethodUtils.isListIsNullOrEmpty(listOfT) ? new ArrayList<>() : listOfT;
}
Service Layer:
#Override
#Transactional
public String updatePurchaseOrder(AccountingRequestBody input) {
PurchaseOrder purchaseOrder = AccountingMethodUtils.getObjectMapper().convertValue(input.getJsonOfObject(),
PurchaseOrder.class);
// Query : db.purchase_order.find( {'_id' : ObjectId("5ab88323191bb91e78f9e33d") } , { 'purchaseOrderNo' : 1, 'currencyMaster_CURRENCY_ID' : 1 , 'total' : 1 })
StringBuilder sb = new StringBuilder().append("db.").append(AccountingVariableUtils.TABLE_NAME_FOR_PURCHASE_ORDER)
.append(".find( {'_id' : ObjectId('" + purchaseOrder.getId().toString()
+ "') } , { 'purchaseOrderNo' : 1, 'currencyMaster_CURRENCY_ID' : 1 , 'total' : 1 })");
List<PurchaseOrder> poFromDB = purchaseOrderDao.executeQuery(sb.toString(), null, null, new PurchaseOrder());
if (!AccountingMethodUtils.isListIsNullOrEmpty(poFromDB)) {
System.out.println("id before update : " + poFromDB.get(0).getCurrencyMaster().getId()); // Output: 5ab8830b191bb91e78f9e221
System.out.println("code before update : " + poFromDB.get(0).getCurrencyMaster().getCode()); // Output: INR
}
purchaseOrderDao.update(purchaseOrder);
poFromDB = purchaseOrderDao.executeQuery(sb.toString(), null, null, new PurchaseOrder());
if (!AccountingMethodUtils.isListIsNullOrEmpty(poFromDB)) {
System.out.println("id after update : " + poFromDB.get(0).getCurrencyMaster().getId()); // Output: 5ab8830b191bb91e78f9e221
System.out.println("code after update : " + poFromDB.get(0).getCurrencyMaster().getCode()); // Output: null //?????????????????????
}
}
output:
id before update : 5ab8830b191bb91e78f9e221
code before update: INR
id after update : 5ab8830b191bb91e78f9e221
code afterupdate: null ?????????????????????
Description:
Currency Master has one to many mapping(bidirectional) with purchase order.
In Service Layer,
first i executed query to get "id,code,total" from purchase order and successfully got all the fields.
then i updated purchase order.
then i again executed same query ( to get "id,code,total" from purchase order) after update then i can get id of currency master but can't get code of currency master.
Is Am i Right???
I think the problem is that you are using projection in your native query and trying to create the entity without retrieving all the information needed. I would remove the projection part from the native query and only use:
db.purchase_order.find( {'_id' : ObjectId("5ab88323191bb91e78f9e33d") } );
This happens because Hibernate OGM caches results, so you have to make sure to initialize entities correctly.
Or, even better, why don't you try using a JPQL query?
PurchaseOrder order = em.createQuery( "FROM PurchaseOrder po WHERE po.id = :id", PurchaseOrder.class )
.setParameter( "id", "5ab88323191bb91e78f9e33d" )
.getSingleResult();
By the way, Hibernate OGM shouldn't let you do this kind of things and will throw an exception in follow-up versions.
Last, I would recommend to update to Hibernate OGM 5.3.0.Final or at least to 5.2.0.Final (if there is any reason for you to stick to stick to the 5.2 family).
I'm just start to learning this ORM, so maybe I've done something wrong. In entity I write OneToOne relation but greendao doesn't generate it. If I'm writing in entity constructor arguments for foreign key it just ignores this and makes it like this. So there is no property and column in table. Thank you.
Public:
#Entity(active = true)
public class Public {
#Id(autoincrement = true)
Long id;
int publicId;
#ToOne(joinProperty = "id")
private Category category; ...
#Generated(hash = 12945501)
public Public(Long id, int publicId) {
this.id = id;
this.publicId = publicId;
}
PublicDao:
public class PublicDao extends AbstractDao<Public, Long> {
public static final String TABLENAME = "PUBLIC";
/**
* Properties of entity Public.<br/>
* Can be used for QueryBuilder and for referencing column names.
*/
public static class Properties {
public final static Property Id = new Property(0, Long.class, "id", true, "_id");
public final static Property PublicId = new Property(1, int.class, "publicId", false, "PUBLIC_ID");
} ...
/** Creates the underlying database table. */
public static void createTable(Database db, boolean ifNotExists) {
String constraint = ifNotExists? "IF NOT EXISTS ": "";
db.execSQL("CREATE TABLE " + constraint + "\"PUBLIC\" (" + //
"\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
"\"PUBLIC_ID\" INTEGER NOT NULL );"); // 1: publicId
}
My mistake. I should to add another field for it, and to write it in joinProperty.
We have a table where the ID is generated by a trigger -
ID = year+month+sequence
I mapped the table via JPA and I would like to use the same PK generation in my code as well. I tried the following options:
#Id
#SequenceGenerator(name = "assetSeq", sequenceName = "ASSET_SEQ")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "assetSeq")
#Transient
private long id;
and also tried to change the setter
public void setId(long id) {
String finalId=getIdPrefix()+id;
this.id = Long.parseLong(finalId);
}
private String getIdPrefix() {
DateFormat df = new SimpleDateFormat("YYYYMM");
Date today = Calendar.getInstance().getTime();
return df.format(today);
}
but non of them worked. I just want to insert new record in the database and do not want to use the id later. I use Hibernate for JPA
You can do this if you implement custom Hibernate generator. This blog has almost identical example to what you need. I'll post here the code from the blog adjusted to your needs (might not work if you copy-paste it, but it will be close)
public class CustomIdGenerator implements IdentifierGenerator {
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
String prefix = getIdPrefix();
Connection connection = session.connection();
try {
PreparedStatement ps = connection
.prepareStatement("SELECT nextval ('ASSET_SEQ') as nextval"); // could be different, depending on database vendor
ResultSet rs = ps.executeQuery();
if (rs.next()) {
int id = rs.getInt("nextval");
String code = prefix + id;
return code;
}
} catch (SQLException e) {
throw new HibernateException(
"Unable to generate ID");
} finally {
if (ps != null) {
try {
ps.close();
} catch (Throwable e) {
// log error, or rethrow exception
}
}
}
return null;
}
private String getIdPrefix() {
DateFormat df = new SimpleDateFormat("YYYYMM");
Date today = Calendar.getInstance().getTime();
return df.format(today);
}
}
#Id
#GenericGenerator(name="seq_id", strategy="my.package.CustomIdGenerator")
#GeneratedValue(generator="seq_id")
// don't put that #Transient here
private long id;
Hope this helps.
I am trying to do a hibernate join - the query seemingly works but when i try to cast from the object returned into the type i want it to be it doesnt work...im assuming because it has the joined table info too..
#Entity
#Table(name = "PSNG_SMRY")
public class PSNG_SMRY implements Serializable, Comparable<PSNG_SMRY>
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment" , strategy = "increment")
#Printable
public Integer SMRY_ID;
public Integer DEV_ID;
public Integer RPTD_TRN_ID;
#OneToOne(mappedBy="smry", cascade=CascadeType.ALL)
public TRN trn;
}
#Entity
#Table(name = "TRN")
public class TRN implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
public Integer TRN_ID;
public String TRN_SCTN
public String TRN_SYMB;
#OneToOne
#PrimaryKeyJoinColumn
private PSNG_SMRY smry;
}
I found this one to one mapping example here - link
And when I get the Object back from hibernate I try to cast it to PSNG_SMRY and it wont work - how am i am to do a join where i get the PSNG_SMRY info and the TRN_SYMB from the TRN table back using a join?
EDIT:
I get an invalid cast exception - [Ljava.lang.Object; cannot be cast to PSNG_SMRY
query code:
//code from some function that sets up all queries
String qQuery = "FROM PSNG_SMRY P, TRN T WHERE T.TRN_ID = P.RPTD_TRN_ID and P.FIR_AXLE_PASD_DT > sysdate - :timeLimit and P.FIR_AXLE_PASD_DT < sysdate - 1/24 ORDER BY P.FIR_AXLE_PASD_DT";
hqlParamList.add(new HQLParams("timeLimit", timeLimit)); //some list to pass to hibernate and then parameterize the queury
result = queryDatabase(qQuery, q4Query, hqlParamList);
public QueryResult queryDatabase(String qQuery, String q4Query,
List<HQLParams> params) {
QueryResult results = new QueryResult();
jwdsqa = new Connection("JWDSQA");
jwds4qa = new Connection("JWDS4QA");
results.qa = jwdsqa.retrieve(qQuery, params);
results.qa4 = jwds4qa.retrieve(q4Query, params);
return results;
}
EDIT:
This is the connection class - it is just used to get the session information and do all the hibernate stuff such as getting data...
public class Connection {
public static Logger logger = Logger.getLogger(Connection.class);
Session session;
String sessionName;
public Connection(String name){
session = HibernateUtil.getSessionFactory(name).openSession();
sessionName = name;
if(session.isConnected()){
//System.out.println(name + " - Connected");
}
}
public Session getSession(){
return session;
}
#SuppressWarnings("unchecked")
public List<Object> retrieve(String qry, List<HQLParams> paramList)
{
Transaction transaction = null;
List<Object> obj = null;
try {
transaction = session.beginTransaction();
String queryString = qry;
Query query = session.createQuery(queryString);
if(paramList != null)
{
for(HQLParams param: paramList)
{
query.setParameter(param.paramName, param.params);
}
}
List<Object> obj_ = query.list();
obj = obj_;
//session.getTransaction().commit();
} catch (HibernateException ex) {
ex.printStackTrace();
logger.error(ex.getMessage() + "\n" + ex.getStackTrace());
transaction.rollback();
} catch (Exception ex) {
System.err.println(ex.getMessage());
logger.error(ex.getMessage() + "\n" + ex.getStackTrace());
}
finally
{
session.close();
//System.out.println("Closing session " + sessionName);
}
return obj;
}
}
I ended up figuring this out - the reason why I was getting the casting error was hibernate was returning both the PSNG_SMRY and TRN objects back as an Object[] - and not as one Object.
If you want PSNG_SMRY instances you should not have to ask for the TRN table. This is provided for you when you use using JPA mapping
FROM PSNG_SMRY P
WHERE P.FIR_AXLE_PASD_DT > sysdate - :timeLimit
and P.FIR_AXLE_PASD_DT < sysdate - 1/24
ORDER BY P.FIR_AXLE_PASD_DT
If you do not get the TRN for the retrieved PSNG_SMRY objects then it means there is a mapping error because you are telling Hibernate how to retrieve the TRN for a PSNG_SMRY in your annotation
#OneToOne(mappedBy="smry", cascade=CascadeType.ALL)
public TRN trn;