OpenJPA - How to map View to Entity - java

I'm using WAS 8.0.0.5, which means I'm using OpenJPA 2.1.2-SNAPSHOT. I'm using the Criteria Query API and Canonical Metamodels. I need to access an Oracle View. The View has 1 column named GUID, which uses this SQL:
select sys_guid() from dual;
to populate itself.
I'm using RAD 8.5.1 and its JPA features to generate my entities based off what's in the db.
Here's my entity:
#Entity(name="vguid")
#Table(name="V_GUID")
public class VGuid implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(length=32)
private String guid;
public VGuid() {}
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
}
RAD is underlining #Column and providing this error:
Column "guid" cannot be resolved on table "V_GUID"
ಠ_ಠ
I know that #Column(length=32) works because I use it works within another Entity that reads a GUID from an Oracle table (The View is used to populate the GUID field of this other table).
How can I resolve this error?

O.K....so, I closed RAD and reopened the project. The error disappeared. Arghhh!

Related

No error when violating constraints after inserting data in spring-boot application with spring data jpa

I'm currently learning Spring-Boot and Spring-Data-JPA.
I'm using a postgresql database for storing the data.
My goal is to store ingredients with a unique and custom ID (you just type it in when creating it), but when another ingredient with the same ID gets inserted, there should be some kind of error. In my understanding, this is what happens when I use the #Id annotation, hibernate also logs the correct create table statement.
This is my Ingredient class:
public class Ingredient {
#Id
#Column(name = "ingredient_id")
private String ingredient_id;
#Column(name = "name")
private String name;
#Column(name = "curr_stock")
private double curr_stock;
#Column(name = "opt_stock")
private double opt_stock;
#Column(name = "unit")
private String unit;
#Column(name = "price_per_unit")
private double price_per_unit;
#Column(name = "supplier")
private String supplier;
-- ... getters, setters, constructors (they work fine, I can insert and get the data)
}
My controller looks like this:
#RestController
#RequestMapping(path = "api/v1/ingredient")
public class IngredientController {
private final IngredientService ingredientService;
#Autowired
public IngredientController(IngredientService ingredientService) {
this.ingredientService = ingredientService;
}
#GetMapping
public List<Ingredient> getIngredients(){
return ingredientService.getIngredients();
}
#PostMapping
public void registerNewStudent(#RequestBody Ingredient ingredient) {
ingredientService.saveIngredient(ingredient);
}
}
And my service class just uses the save() method from the JpaRepository to store new ingredients.
To this point I had the feeling, that I understood the whole thing, but when sending two post-requests to my application, each one containing an ingredient with the id "1234", and then showing all ingredients with a get request, the first ingredient just got replaced by the second one and there was no error or smth. like that in between.
Sending direct sql insert statements to the database with the same values throws an error, because the primary key constraint gets violated, just as it should be. Exactly this should have happened after the second post request (in my understanding).
What did I get wrong?
Update:
From the terminal output and the answers I got below, it is now clear, that the save() method can be understood as "insert or update if primary key is already existing".
But is there a better way around this than just error-handle every time when saving a new entry by hand?
The save method will create or update the entry if the id already exists. I'd switch to auto generating the ID when inserting, instead of manually creating the IDs. That would prevent the issue you have
When saving a new ingredient, jpa will perform an update if the value contained in the “id” field is already in the table.
A nice way through which you can achieve what you want is
ingredientRepository.findById(ingredientDTO.getIngredientId()).
ifPresentOrElse( ingredientEntity-> ResponseEntity.badRequest().build(), () -> ingredientRepository.save(ingredientDTO));
You can return an error if the entity is already in the table otherwise (empty lambda), you can save the new row
This is a downside to using CrudRepository save() on an entity where the id is set by the application.
Under the hood EntityManager.persist() will only be called if the id is null otherwise EntityManager.merge() is called.
Using the EntityManager directly gives you more fine grained control and you can call the persist method in your application when required

How to auto generate a primary key using Hibernate and an H2 database [duplicate]

This question already has answers here:
Hibernate Auto Increment ID
(7 answers)
Closed 7 years ago.
I am using Spring 4 and have the following set up for my data model:
#Entity
#Table(name ="InstanceData")
public class InstanceData {
private Long instanceDataId;
private Long heapUsed; //in bytes
private Long heapMax; //in bytes
#Id
#Column(name="InstanceDataId")
#SequenceGenerator(name="DataSeq", sequenceName="DATA_SEQ")
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="DataSeq")
public Long getInstanceDataId() {
return instanceDataId;
}
public void setInstanceDataId(Long id) {
this.instanceDataId = id;
}
#Column(name="HeapUsed")
public Long getHeapUsed() {
return this.heapUsed;
}
public void setHeapUsed(Long heapUsed) {
this.heapUsed = heapUsed;
}
#Column(name="HeapMax")
public Long getHeapMax() {
return this.heapMax;
}
public void setHeapMax(Long heapMax) {
this.heapMax = heapMax;
}
I let Hibernate create the schema automatically. I then try the following SQL (on the H2 db):
insert into instance_data (heap_used, heap_max) values (100, 100);
The error I get is: Error: NULL not allowed for column "INSTANCE_DATA_ID";
SQLState: 23502
My question is why doesn't it auto generate the primary key? How should I change my data model configuration so that the primary key is auto generated (starting at 1)? Thanks for your help.
I would like to understand why even though I am using the #GeneratedValue annotation, the primary key is not auto generated.
Why are you using raw SQL? Just create a new object of class InstanceData, set fields heapUsed and heapMax and use Hibernate's save() method. Then id would be generated automatically.
Annotate id getter like this
#Id
#Column(name="InstanceDataId")
#GeneratedValue(strategy=GenerationType.AUTO)
public Long getInstanceDataId() {
return instanceDataId;
}
and if you dont want to create raw sql scheme you can build up something similar to this (ofcourse it works only using inmemory db)
#Component
#Transactional
public class DummyDbCreator {
private SomeService someService;
#Autowired
public DummyDbCreator(SomeService someService) {
this.someService = someService;
}
#PostConstruct
public void initialInserts() {
Some some = new Some();
// some more entites
// ...
// and other entites
someService.save(some);
}
}
Add this class to some component scanned package or just declare it as a bean in your configuration

Error insert element (primary key)

I have one problem with my configuration of play framework, when I insert a new Notification I have received the error. I don´t know why this error occured. Because I extends Model class, Play must generated a new ID for each row.
If you can say to me what is the problem, or other better way to do this, Maybe if I extends the GenericModel and I do the code that is commented like this:
// #Id
// #GeneratedValue(strategy = GenerationType.AUTO)
// public long id;
but if I do this, How I must do the insert a new row?
Thanks a lot!!!!
Error found:
PersistenceException occured : org.hibernate.HibernateException: The database returned no natively generated identity value
This is /app/controllers/WSConfiguracion.java :
if (cliente.valorBateria < filasConfiguracionClientes.get(i).limiteBateria) {
if (!estadoNotificacion.hayNotiBateria) {
// code below generated the error
Notificacion notificacion = new Notificacion(
filasConfiguracionClientes.get(i).imeiadmin,imei, "bateria baja"
).save();
estadoNotificacion.hayNotiBateria = true;
//notificacion.save();
estadoNotificacion.save();
renderText("NOTIFICA BATERIA");
}
} else {
...
}
This is my model.
package models;
import javax.persistence.Entity;
import play.db.jpa.Model;
#Entity
public class Notificacion extends Model {
//#Id
//#GeneratedValue(strategy = GenerationType.AUTO)
//public long id;
//#Id
public long imeiadmin;
//#Id
public long imeiclient;
public String detalleNotificacion;
public Notificacion(long imeiadmin, long imeiclient,String detalleNotificacion) {
this.imeiadmin = imeiadmin;
this.imeiclient = imeiclient;
this.detalleNotificacion = detalleNotificacion;
}
}
I think the error:
PersistenceException occured : org.hibernate.HibernateException: The database returned no natively generated identity value
is occurred because there is no sequence in your database. If you extends Model class for your model and you are on Development mode, Play!Framework automatically generated sequence on your database named hibernate_sequence. The sequence is used to generated ID for your model. You may check your database to ensure that sequence is present.
If the hibernate_sequence is present, you can insert data like you do before :
Notificacion notificacion = new Notificacion(
filasConfiguracionClientes.get(i).imeiadmin,imei, "bateria baja"
).save();
then, the error above should be resolved.
Note:
I am referring this answer if you used PostgreSQL database. If you use other database such as MySQL, you should define AUTO_INCREMENT on ID column as the sequence definition.
Update - I have tried this for H2 DB setting
Using H2 database as configure in application.conf :
# Development mode
application.mode=dev
# Set simple file written database (H2 file stored)
db=fs
# JPA DDL update for development purpose only
jpa.ddl=update
The controller :
public static void test15878866() {
// force to insert dummy data
Notificacion notificacion = new Notificacion(
1L, 2L, "This is new notificacion"
).save();
renderText(notificacion.detalleNotificacion);
}
The model :
#Entity
public class Notificacion extends Model {
public long imeiadmin;
public long imeiclient;
public String detalleNotificacion;
public Notificacion(long imeiadmin, long imeiclient,String detalleNotificacion) {
this.imeiadmin = imeiadmin;
this.imeiclient = imeiclient;
this.detalleNotificacion = detalleNotificacion;
}
}
I found the mistake!! I have only had to add super(); inside the constructor.
Thanks for all, iwawiwi.
The model :
#Entity
public class Notificacion extends Model {
public long imeiadmin;
public long imeiclient;
public String detalleNotificacion;
public Notificacion(long imeiadmin, long imeiclient,String detalleNotificacion) {
super();
this.imeiadmin = imeiadmin;
this.imeiclient = imeiclient;
this.detalleNotificacion = detalleNotificacion;
}
}

How annotation mapping is done in java persistence?

We use annotations for mapping the entity class with the database table by simply specifying #Entity and more like #Id, table joins and many things. I do not know how these entity variables are getting mapped with database table. Can anyone give a short description for understanding.
Thanks :)
Well the idea is to translate your objects and their connections with other objects into a relational database. These two ways of representing data (objects defined by classes and in tables in a database) are not directly compatible and that is where a so called Object Relational Mapper framework comes into play.
So a class like
class MyObject
{
private String name;
private int age;
private String password;
// Getters and setters
}
Will translate into a database table containing a column name which is of type varchar, age of type int and password of type varchar.
Annotations in Java simply add additional information (so called meta data) to your class definitions, which can be read by any other class (e.g. JavaDoc) and in the case of the Java Persistence API will be used by an ORM framework like Hibernate to read additional information you need to translate your object into the database (your database table needs a primary id and some information - like what type of a relation an object has to another - can't be automatically determined by just looking at your class definition).
Annotations are very well explained here:
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/
annotations are just metadata on a class, nothing magical. You can write your own annotations. Those annotations are given retention policies of runtime (which means you have access to that metadata at runtime). When you call persist etc the persistence provider iterates through the fields (java.lang.reflect.Field) in your class and checks what annotations are present to build up your SQL statement. Try writing your own annotation and doing something with it. It won't seem very magical after that.
in your case annotation working means mapping with tablename with entity class is look like as ....
#Entity
#Table(name = "CompanyUser")
public class CompanyUserCAB implements java.io.Serializable
{
private long companyUserID;
private int companyID;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "companyUserID")
public long getCompanyUserID()
{
return this.companyUserID;
}
public void setCompanyUserID(long companyUserID)
{
this.companyUserID = companyUserID;
}
#Column(name = "companyID")
public int getCompanyID()
{
return this.companyID;
}
public void setCompanyID(int companyID)
{
this.companyID = companyID;
}
}

org.hibernate.exception.SQLGrammarException: could not execute query

I use play framework !! But when I run my project it give me this
org.hibernate.exception.SQLGrammarException: could not execute query
who can help me ?
this is my model:
package models;
import java.util.*;
import javax.persistence.*;
import play.db.jpa.*;
import play.db.jpa.Model;
#Entity
#Table(name="GxkAccount")
public class GxkAccount extends Model {
private String Account;
private String Psw;
public String getAccount() {
return Account;
}
public void setAccount(String account) {
Account = account;
}
public String getPsw() {
return Psw;
}
public void setPsw(String psw) {
Psw = psw;
}
public static List<GxkAccount> GetList()
{
List<GxkAccount> infoList=GxkAccount.findAll();
return infoList;
}
}
You are completely missing the mapping annotations for the properties of your class.
P.S. Please try to follow the Java naming conventions
Using mysql, we also faced this type of issue. We found in play framework application.conf:
jpa.dialect=org.hibernate.dialect.PostgreSQLDialect
we replaced this with
jpa.dialect=org.hibernate.dialect.MySqlDialect.
This solved the problem. If you are facing this issue you can try out this configuration setting.
We also faced the same issue. We were having create in the xml and #GeneratedValue on the id column. The resolution is remove the #GeneratedValue annotation and put the value of the id manually, also the jpa takes long by default so give long value e.g 1l.
To do the auto generation follow some another rule.
The issue around the JPA related auto generated Id is resolved as below:
Modify the Person.java model class to have the following annotations for the Id attribute:
#Id
#TableGenerator(name="TABLE_GEN",table="T_GENERATOR",pkColumnName="GEN_KEY",pkColumnValue="TEST",valueColumnName="GEN_VALUE",initialValue=1,allocationSize=1)
#GeneratedValue(strategy=GenerationType.TABLE, generator="TABLE_GEN")
public Long Id;
This will create a table in the mysql schema called T_GNERATOR which will have the tracking of the next value for Id and JPA over hibernate knows how to retrieve this value. The assumption is that the initial value for the Id is 1 and it is incremented by 1 on each new insertion into it as is obvious from the attributes of the annotation.

Categories

Resources