I am using Hibernate and spring. this is my model class
#Entity
#NamedNativeQueries({#NamedNativeQuery(
name = "CSI_TARGET",
query = "select * from CSITARGET('CSIINDEX',2)",
resultClass = CSITarget.class)})
public class CSITarget {
#Column(name="csi_target")
private BigDecimal csi_target;
#Id
#Column(name="financialyearfrom" ,nullable = true)
private int financialyearfrom =0;
#Column( name="at_yearhalf" , nullable = true)
private String at_yearhalf = "";
public BigDecimal getCsi_target() {
return csi_target;
}
public void setCsi_target(BigDecimal csi_target) {
this.csi_target = csi_target;
}
public int getFinancialyearfrom() {
return financialyearfrom;
}
public void setFinancialyearfrom(int financialyearfrom) {
this.financialyearfrom = financialyearfrom;
}
public String getAt_yearhalf() {
return at_yearhalf;
}
public void setAt_yearhalf(String at_yearhalf) {
this.at_yearhalf = at_yearhalf;
}
I am using Hibernate to call a stored procedure in postgres database. The stored procedure returns a table which is mapped to this model class. Now my problem is, the table that is returned from the database contains a null value. I am in the need of doing some manipulations on the data. Now since the null value is mapped to the bean class I am getting a null pointer exception. How can I make hibernate ignore the null values in the database and set a default value for the corresponding property in the bean class. As you can see I have used nullable property also. It does'nt work.
financialyearfrom is int which cannot be assigned null value though corresponding column you might be having null value in database if column is defined as nullable.
For handling null values in java primitive variables, remove nullable=true and possible add default value 0, so all null value from db column would convert to 0 or 0.0 etc.
Or
Use wrapper class instead i.e. Integer which will allow you to retain null value assigned from db column.
Again, above two approaches are in general applicable for primitive variables using in Hibernate entities.
Further to add #ID column shouldn't be nullable IMO, if it corresponds to primary key column (in most of the cases it is) so your code would be wrong as primary key column doesn't allow null values.
Would it be possible to use COALESCE in your query to assign a default value to that field if its null? If that's possible that's probably the best way to fix this issue w/o having to tweak your code too much.
Related
When I try to save my entity in my oracle db using the .save() method of the hibernate session I get this exception :
org.hibernate.PropertyAccessException: Could not set field value [1757] value by reflection : [class mypackage.MyEntity.myid] setter of mypackage.MyEntity.myid
The value 1757 is correct, it's the one I want for my ID. (when I do a select myschema.mysequence from dual; in my DB I get the next value of this one so it seems to work properly)
I don't understand the error, it's like it doesn't find the setter method but when I explore the exception, in the cause it says something else :
Can not set java.lang.Long field mypackage.MyEntity.myid to null value
which, for me, doesn't make any sense since the value "1757" is not null at all obviously ^^, and Long should accept null values anyway so I have no idea why it doesn't work. I supposed it was because an ID column coulnd't be null (which is false since we also can have a default for null values). So really, I don't get it.
My entity :
#Entity
#Table(name = "MYTABLE")
public class MyEntity implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="seqName", sequenceName="myschema.mysequence",allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seqName")
#Column(name = "MY_ID")
private Long myid; //NUMBER
//some other column
public Long getMyid() {
return myid;
}
public void setMyid(Long myid) {
this.myid = myid;
}
//some other accessors
}
I tried to change the type "Long" to long and I tried to do some other setters with different types (long, int, BigInteger, Integer, BigDecimal...) but nothing changed.
I'm able to create an occurrence using the "createNativeQuery" method with "myschema.mysequence.nextval" in myid field like this :
session.createNativeQuery("INSERT INTO myschema.MYTABLE (MY_ID, someotherfields)"
+ " VALUES (myschema.mysequence.nextval, someotherfieldvalues)")
.executeUpdate();
but if I do so, the id is lost... I want to get it back from the query like it's supposed to be with the session.save() method.
For now, the only way I found to get my ID from sequence after insert statement was to create it before (SELECT myschema.mysequence.nextval FROM DUAL) and it's terrible for the performances. We often add rows by thousands.
Try adding a no-parameter constructor to your entity.
Did you try debugging to the point where the exception is initially thrown and inspect what is happening exactly? Maybe some underlying exception is swallowed. Are you sure you updated Hibernate to the latest version 5.4.34/5.5.7? If so, and you still have the problem, please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.
How can I create a single add method that will insert different entities in the jdbc? I want to use annotations and reflection for that.
I have created 2 annotations:
(...)
public #interface Column {
String name();
boolean isPrimaryKey() default false;
}
and
(...)
public #interface Table {
String name();
}
Suppose we have 2 entities/models/etc. : Client and Waiter. For both we should make 2 add methods, each with own INSERT.
If we have like 4 entities, we should have 4 add methods for each entity. Instead of having 4 add methods, how can I make just 1 add method? and by using the annotations and the reflection.
Eg:
#Table(name = "Table_Client")
public class Client{
#Column(name = "ID", isPrimaryKey = true)
private long id;
#Column(name = "FULL_NAME")
private String name;
}
#Table(name = "Table_Waiter")
public class Waiter {
#Column(name = "FULL_NAME", isPrimaryKey = true)
private String name;
#Column(name = "AGE")
private int age;
}
case: db.add(Client c1) => add to the database in the table Table_Client the client c1
db.add(Waiter w1) => add to the database in the table Table_Waiter the waiter w1
and so on...
My idea is to take the class of the given object and scan it for the TYPE annotation to get the table's name. Then, take all the field's annotations and make a dynamic INSERT INTO VALUES query, but the problem is that I can't actually do that, because I can't pass the object's arguments.
Another question: if this can be done, update and delete methods can follow the same path?
I cannot refrain from mentioning how many holes you may find in the road ahead. But judging from the comments, that's the path you want to explore.
First of all, regarding your existing code, you need to apply a retention meta-annotation to your annotations, Column and Table. For example:
#Retention(RetentionPolicy.RUNTIME)
public #interface Column {
String name();
boolean isPrimaryKey() default false;
}
This meta-annotation will ensure that you can read your annotations at runtime through reflection.
Then, you need to inspect the class searching for these annotations at both class and field levels.
The Class class will have everything you need. You should know you can get it from any object by calling the getClass method. It contains a couple of important methods for what you are trying to achieve:
getAnnotation(Class c) will return the annotation if it exists, or null otherwise.
getDeclaredFields will return all declared class fields, even private ones.
At a field level, the Field class provides the following methods:
getAnnotation(Class c), same as above, will return the annotation if it exists, or null otherwise.
getType will return the class associated with the field
Now consider the following piece of code:
public static void inspectClass(Class<?> cls) {
Table t = cls.getAnnotation(Table.class);
if (t != null) {
System.out.print(t.name() + " --> ");
for (Field f: cls.getDeclaredFields()) {
Column c = f.getAnnotation(Column.class);
if (c != null) {
System.out.print(c.name()
+ " "
+ f.getType().getSimpleName()
+ (c.isPrimaryKey() ? " PK" : "") + ", ");
}
}
}
}
Applying this to your Client class, for instance, would return something like:
Table_Client --> ID long PK, FULL_NAME String,
Of course, this needs some work, but the idea is there.
EDIT:
To access values of an instance through reflection at runtime, for creating a dynamic INSERT statement, that could be done by calling get method on the Field class. When dealing with private fields though, it's necessary to tweak the privacy mode first:
f.setAccessible(true);
Object value = f.get(myInstance);
I set "firm_name" default value in Ben using annotation.
But when I insert data it will add NULL in database.
I want to set default value into database so that I just set the values which are require.
Other column values set as default value which is set into Bean.
Following is my Code.But it is not working. I will inset nNULL value into database.
#Entity
#Table(name = "my_leads")
public class My_leads{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id")
int id;
#Column(name = "name", length = 100,columnDefinition = "varchar(255) default 'NA'")
String name;
#Column(name = "enrtyDate", insertable = false, updatable = false, nullable = false,columnDefinition = "datetime default NOW()")
Date enrtyDate;
#Column(name = "mobileNo", nullable = false, length = 100)
String mobileNo;
#Column(name = "firm_name", length = 100, nullable = false,columnDefinition = "varchar(255) default 'No Refrence'")
String firm_name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getEnrtyDate() {
return enrtyDate;
}
public void setEnrtyDate(Date enrtyDate) {
this.enrtyDate = enrtyDate;
}
public String getMobileNo() {
return mobileNo;
}
public void setMobileNo(String mobileNo) {
this.mobileNo = mobileNo;
}
public String getFirm_name() {
return firm_name;
}
public void setFirm_name(String firm_name) {
this.firm_name = firm_name;
}
}
My_Leads lead=new My_Leads();
lead.setUser(1);
lead.setMobileNo("1234567896");
lead.setName("Sajan");
lead.setPriority(1);
lead.setStage(1);
lead.setCampain(1);
adminService.SaveLead(lead)
The code you wrote is not a way to set a default value by Hibernate - it's actually for a database.
When you create a table in the database you can define a column such way that if you try inserting a null value the default value will be inserted instead. That's what you did here varchar(255) default 'No Refrence'.
If your table is already created, Hibernate is gonna ignore that statement. That statement is used only when Hibernate is creating the schema for you, using #Entity classes. If you go into your database and check column definitions you will see that your column has no default value, since it was not created by Hibernate.
You can delete your schema and let Hibernate create it for you, then the default value will work. Or you can edit your schema manually, adding default value to already existing column. For example:
ALTER TABLE my_leads ALTER COLUMN firm_name SET DEFAULT 'No Refrence'
If you let Hibernate generate your schema and still have this error - make sure those are actually null values, not NULL strings or something.
If you don't want to have the default values inserted by database, but by Hibernate, do this in your #Entity class:
String firm_name = "No Refrence";
Whenever an entity is to be inserted, Hibernate is going to generate the following DML:
INSERT
INTO my_leads (id, name, enrtyDate, mobilNo, firm_name)
VALUES (?, ?, ?, ?, ?)
In your java code, you're simply not setting a value for firm_name so that property is null.
Whether or not the default value for the column is used is going to depend upon what database platform you're using and how it interprets NULL in this case.
For example, MySQL will see that Hibernate bound NULL for the firm_name and will therefore apply the default value for you rather than setting the column as NULL.
For example, SQL Server will see that the INSERT statement contains the field firm_name in the columns section and therefore will ignore the default value and use whatever value is supplied in the values section, thus the column will be set to NULL. The only way SQL Server will use the default value is if the column is omitted from the columns section of the insert statement.
The only way to guarantee that the default value is set regardless of your database platform is to make sure that your entity state adheres to that rule too. This means you either need to initialize firm_name with the default value in the field definition, in the constructor of your class or your business logic that constructs your entities.
I am trying to validate the data input by the user by making use of JSR 303 validations. One validation that I am trying to implement is to check that the size of the inputted value for each field does not exceed the maximum size of the corresponding column.
In order to map a field to a database column I am making use of JPA's #Column annotation as follows:
#ComplexValidation
public class Person {
#Column(table = "PERSON_DETAILS", name = "FIRST_NAME")
private String firstName;
}
The #ComplexValidation annotation on the Person class, is a JSR 303 custom constraint validator that I am trying to implement, which basically tries to carry out the following steps:
Retreives all fields in the class annotated with #Column annotation
It extracts the table name from the annotation and uses it to load the corresponding JOOQ generated class representing the table
It extracts the field name from the annotation and uses it to load the data type and size for the corresponding column
Is there any way in Jooq where I can retrieve the Jooq Generated class based on the table name? My first attempt can be found below, however it does not work since table(tableName) returns an SQLTable not a TableImpl object:
Column columnAnnotation = field.getDeclaredAnnotation(Column.class);
if (columnAnnotation != null) {
String tableName = columnAnnotation.table();
String fieldName = columnAnnotation.name();
TableField tableField = (TableField) ((TableImpl) table(tableName)).field(fieldName);
int columnLength = tableField.getDataType().length();
if (fieldValue.length() > columnLength) {
constraintValidatorContext
.buildConstraintViolationWithTemplate("exceeded maximum length")
.addPropertyNode(field.getName())
.addConstraintViolation();
}
}
Any other suggestions are welcome :)
Assuming you only have one generated schema (e.g. PUBLIC), you can access tables from there:
Table<?> table = PUBLIC.getTable(tableName);
See Schema.getTable(String)
I am trying to store a class to MySql database. The class is declared as follows:
#DatabaseTable(tableName = "categories")
public class CategoryItem {
#DatabaseField(generatedId = true)
protected long mUniqueId;
#DatabaseField
private String mCategoryDisplayName;
#DatabaseField
private int mItemsCount; // How many items are from this category
#DatabaseField(foreign = true, foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 5)
private CategoryItem mParent;
protected CategoryItem() {}
When trying to store this class to MySql database (in openshift), I receive the following exception:
java.sql.SQLException: generated-id key was not set by the update call
com.j256.ormlite.stmt.mapped.MappedCreate.insert(MappedCreate.java:115)
com.j256.ormlite.stmt.StatementExecutor.create(StatementExecutor.java:438)
com.j256.ormlite.dao.BaseDaoImpl.create(BaseDaoImpl.java:308)
com.kanooli.common.itemslist.ORMLite.ORMLiteItemsAdapter.addCategory(ORMLiteItemsAdapter.java:51)
com.kanooli.common.itemslist.Update.updateDataBase(Updater.java:85)
kanooliserver.mysql.DbUpdater.doGet(DbUpdater.java:65)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
When I looked in the source code, this is where this print comes:
if (key == null) {
// may never happen but let's be careful out there
throw new SQLException("generated-id key was not set by the update call");
}
Is this a bug in ORMLite?
java.sql.SQLException: generated-id key was not set by the update call
This is strange and should not happen. I don't believe this is a bug in ORMLite. I believe that this indicates that you have a mismatch between the schema that created the database table and the entity that is being inserted into the table. Please verify that the schema that created the MySQL table actually has the id field defined something like:
`id` INTEGER AUTO_INCREMENT
If you created the table without AUTO_INCREMENT and then tried to insert an entity into the table that thought it was generatedId = true then that would result in the exception that you have seen.
I've added some checks for this specific issue, some tests to look for it, and better messaging. See these check-ins:
Better messaging
Additional checks and some tests
Specific MySQL tests