Here is bean class,
#Entity
#Table(name="hlatlng")
public class HistoryLatitudeBean {
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name="vehicleno")
private int vehicleno;
#Column(name="lat")
private String lat;
#Column(name="lng")
private String lng;
#Column(name="status")
private String status;
#Column(name="rdate")
private Date rdate;
#Column(name="rtime")
private Date rtime;
//getter setter,
}
In Hibernate method I am writing,
Map<String, Object> parameterNameAndValues = new HashMap<String, Object>();
parameterNameAndValues.put("vehicleno", 12);
parameterNameAndValues.put("frmdate", frmDate);
parameterNameAndValues.put("todate", toDate);
hql= "from HistoryLatitudeBean where vehicleno=:vehicleno and rdate BETWEEN :frmdate and :todate";
Query query =session.createQuery(hql);
/*query.setParameter("vehicleno", 12);
query.setParameter("frmdate", frmDate);
query.setParameter("todate", toDate);*/
for (Entry<String, Object> e : parameterNameAndValues.entrySet()) {
query.setParameter(e.getKey(), e.getValue());
}
List<HistoryLatitudeBean> groupList = (List<HistoryLatitudeBean>)query.list();
//Here groupList contains null
for(HistoryLatitudeBean arr : groupList){
vehicleHistoryList.add(arr);
System.out.println("List :"+arr.getLat());
}
transaction.commit();
Problem is query.list() method returns null.
The same query I am trying in mysql db as,
SELECT * FROM hlatlng WHERE vehicleno='12' AND rdate BETWEEN '2014-01-01' AND '2014-09-01';
and my table structure is like this,
CREATE TABLE `hlatlng` (
`vehicleno` int(40) DEFAULT NULL,
`lat` varchar(40) DEFAULT NULL,
`lng` varchar(40) DEFAULT NULL,
`status` varchar(40) DEFAULT NULL,
`rdate` date DEFAULT NULL,
`rtime` date DEFAULT NULL,
`id` int(40) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
It gives me 3 rows. I am not getting what is wrong in my code , can any one help me in this please.
The Date in java will have the time part associated with it. If our data is only on dates, we need to trim the time part.
Adding the #Type(type="date") will take care of this while sending it to the database.
I tried to find a reference, unfortunately I could not find anything.
Related
I'm using this hibernate-types that allows hibernate to translate SQL layer data types into java classes in my springboot application, here I'm trying to add a text array field called user array.
#Entity
#Table(name = "user_update")
#Getter
#Setter
#NoArgsConstructor
#RequiredArgsConstructor
#TypeDef(name = "list-array", typeClass = ListArrayType.class)
public class UserUpdate {
#Id #NonNull private String userKey;
#Column #NonNull private String userName;
#Column #NonNull private Instant updatedAt;
#Type(type = "list-array")
#Column(columnDefinition = "text[]")
#NonNull
private List<String> userArray;
}
I can insert data into the table, but now I want to add a test and I see the following error message from the table.sql
CREATE TABLE IF NOT EXISTS user_update (
user_key VARCHAR(255) NOT NULL,
user_name VARCHAR(255) NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
user_array TEXT ARRAY NOT NULL,
PRIMARY KEY(org_key)
);
maybe it is because the test I'm running uses #DataJpaTest and for some reason it can not recognize the new text[] field ?
Error executing DDL "create table user_update (user_key varchar(255) not null, user_name varchar(255), user_array text[], updated_at timestamp, primary key (user_key))" via JDBC Statement
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "create table user_update (user_key varchar(255) not null, user_name varchar(255), user_array text[*][], updated_at timestamp, primary key (user_key))"; expected "(, ARRAY, INVISIBLE, VISIBLE, NOT, NULL, AS, DEFAULT, GENERATED, ON, NOT, NULL, DEFAULT, NULL_TO_DEFAULT, SEQUENCE, SELECTIVITY, COMMENT, CONSTRAINT, COMMENT, PRIMARY, UNIQUE, NOT, NULL, CHECK, REFERENCES, ,, )"; SQL statement:
With #DataJpaTest Spring will instruct Hibernate to create the schema and that will use the information that you provided in your annotations, but it seems this is not legal for H2.
Try using the following instead:
#Column(columnDefinition = "text array")
Using
Hibernate 5.3, Spring Boot 2.1, MySQL, that runs in Windows 10 OS.
What I know
I have verified on my phpmyadmin the case of the attributes. And as long the case were the same as the attributes of my Entity class you don't have to explicitly define the column name in that Entity. And using #Column(name="tableattribute") is not required.
Problem
Once I executes the query, the number of row has been retrieved correctly. For example, my database contains 5 record, the List contains 5 employee objects, but all its attributes of the Entity always returns as null value.
I want to remove explicitly declaring the column name on each attribute and ensure that it will work in the actual server which might cause problem with the case of column name and the attribute name.
Tried
I tried to add #Column('column Name all lowercase') on each attributes and It retrieve the value.
Upon learning this, I verified the table column if it is lower case, but is not in lower case. Instead, It still follow the camel-case that is in my SQL command to create the table.
MySQL Table
CREATE TABLE `personal` (
`empID` int(11) NOT NULL,
`empNumber` varchar(15) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '',
`surname` varchar(50) NOT NULL DEFAULT '',
`firstname` varchar(50) NOT NULL DEFAULT '',
`middlename` varchar(50) NOT NULL DEFAULT '',
`middleInitial` varchar(10) DEFAULT NULL,
`nameExtension` varchar(10) DEFAULT '',
`salutation` varchar(15) NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Entity
This Entity is now working fine as long as #Column and specify the column name in lowercase. But it is annoying to add each attribute with #Column and specify the name of the field in all lower case.
#Entity
#Table(name="personal")
public class Employee implements Serializable {
#Id
#Column(name="empID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#NotNull
#Column(name="empnumber")
private String empNumber;
private String surname;
private String firstname;
private String middlename;
#Column(name="middleinitial")
private String middleInitial;
#Column(name="nameextension")
private String nameExtension;
}
Actual Query Snippet on DAO
#Autowired
private EntityManager entityManager;
#Override
public List<Employee> findAll() {
Session currentSession = entityManager.unwrap(Session.class);
Query<Employee> query = currentSession.createQuery("from Employee", Employee.class);
return query.getResultList();
}
You can change that behavior by setting
spring.jpa.hibernate.naming.physical-strategy
spring.jpa.hibernate.naming.implicit-strategy
properties in your application.properties. On how to implement the strategies yourself, you can check out official docs.
Edit 1:
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.naming.implicit-strategy = org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
Query:
INSERT INTO PERSON
(email, mobile, party_id, affiliate_id, eligibility, member_start_date, created_by, created_dt, first_name, last_name, google_connected)
values
('xxx#yyy.org', NULL, 123, '123', '1', NULL, NULL, '2018-8-30 21:45:56.859000 -6:0:0', 'xxx', 'yyy', '0')
ON CONFLICT (email)
DO UPDATE SET create_dt = '2018-8-30 21:45:56.859000 -6:0:0' where email = ?
When the LocalDate value is not null, it works fine. Facing this issue only when LocalDate value is given as null.
Even after PostgreSQL casting, it does the same.
Exception stacktrace:
2018-08-30 21:10:48,372 -- [ERROR]-- There was an unexpected problem
with your request org.postgresql.util.PSQLException: ERROR: column
"member_start_date" is of type date but expression is of type bytea
Hint: You will need to rewrite or cast the expression. Position: 185
at
org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2182)
at
org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1911)
at
org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:173)
at
org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:645)
at
org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:495)
at
org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:380) at sun.reflect.GeneratedMethodAccessor98.invoke(Unknown Source) at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114)
at com.sun.proxy.$Proxy185.executeQuery(Unknown Source) at at
org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
... 149 common frames omitted
Entity:
#Entity(name = "person")
#EqualsAndHashCode(callSuper = false)
public class PersonEntity extends Audit {
#Id
#GeneratedValue
#Column(name = "person_id", columnDefinition = "uuid", updatable = false)
private UUID id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
#NotNull
private String email;
#Column(name = "mobile")
private String mobile;
#Column(name = "party_id")
private Long partyId;
#Column(name = "affiliate_id")
private String affiliateId;
#Column(name = "eligibility")
#NotNull
private Boolean eligibility;
#Column(name = "member_start_date")
private LocalDate memberStartDate;
#Column(name = "google_connected")
private Boolean googleAccountConnected;
}
PostgreSQL table definition; it's missing google_connected column which is not important:
CREATE TABLE person
(
person_id UUID NOT NULL,
email VARCHAR(128) NOT NULL,
mobile VARCHAR(20),
party_id INTEGER,
affiliate_id VARCHAR(20),
eligibility BOOLEAN NOT NULL,
member_start_date DATE,
created_by VARCHAR(128) NOT NULL,
created_dt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_by VARCHAR(128) DEFAULT NULL,
updated_dt TIMESTAMP NULL,
CONSTRAINT person_pk PRIMARY KEY ( person_id )
);
Because the query is native, Hibernate doesn't know the data types which to expect, so when you pass a null it defaults to the generic Serializable type handler. Changing this behaviour breaks compatibility with other databases.
Postgres, however parses the query immediately and determines what types are acceptable, and it always checks for type before it checks for null. They are the only ones who can fix this, but refuse to do so and say it works as intended.
The only solutions for you are:
use JPQL
use managed entities
use hard-coded nulls in the query string where you need to
Fortunately for the third option, with Hibernate you can use named parameters in native queries, so you don't have to do positional calculations for when something is available and when it isn't.
edit: 4th solution that I've discovered since.
You have your query:
Query q = em.createNativeQuery("UPDATE...");
Have some static final LocalDate object somewhere:
public static final LocalDate EPOCH_DATE = LocalDate.of(1970, 1, 1);
then call the query like this:
q.setParameter("start_date", EPOCH_DATE);
q.setParameter("start_date", nullableDateParam);
The first time you call setParameter for a parameter, Hibernate uses the class to resolve the type. The second time you call it, the type is already resolved, so a null will work.
It's an old question, but there is a more useful way:
your query...
.setParameter("transaction_id", null, LongType.INSTANCE)
It works.
Found from https://forum.hibernate.org/viewtopic.php?p=2493645
Going to newer versions of hibernate 5.1.17 and above + postgres seems to have exhibited this behavior. Looking into the code, when it binds a type that has no value, the old hibernate code attempted to resolve the type through a typeresolver. The newer versions of hibernate's implementation state that it will not guess.
public Type resolveParameterBindType(Object bindValue) {
if ( bindValue == null ) {
// we can't guess
return null;
}
We ended up just setting a default value based on the type first, and then the real null value.
I'm having problems where two Date fields are updated to the exact same date when only one should be. I'm trying to figure out why this is happening and how I can update only the one date field I want updated, and leave the other at its original value.
I'm using Hibernate with JPA on a MySQL database, in case that is part of the reason.
I have a persistence entity that looks something like this:
#NamedQueries({
#NamedQuery(name="MyObject.updateItem", query="UPDATE MyObject m SET m.item = :item, m.lastUpdate = :updated WHERE m.id = :id")
})
#Entity
#Table(name="entries")
public class MyObject implements Serializable
{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String item;
#Column(columnDefinition = "TIMESTAMP", nullable = false)
private Date dateCreated = new Date();
#Column(columnDefinition = "TIMESTAMP", nullable = false)
private Date lastUpdate = new Date();
// after here standard constructors, getters, setters, etc.
}
When from my DAO I call the NamedQuery and provide the correct paramters, I find that both lastUpdate and dateCreated are changed. Is there any reason for this and how can I prevent this from happening? Is this caused because I initialize the to date fields in the entity class?
I'm using the TIMESTAMP column definition because I want to be able to perform queries with < or >.
lastUpdate and dataCreated, aftare update have the same value?
I don't know if this will be a solution for you but this is what I commonly do for all of the entities I regularly implement. Add a PrePersist and PreUpdate function to your entity in order to set the created and last modified times. Also try adding #Temporal(TemporalType.TIMESTAMP) to each of your date fields.
#PrePersist
public void prePersist() {
this.dateCreated = new Date();
this.lastUpdated = this.dateCreated;
}
#PreUpdate
public void preUpdate() {
this.lastUpdated = new Date();
}
Beyond that, I'm a little stumped...
So I figured out the problem wasn't to do with my query or how I used persistence but how I built the database itself.
When I created the table to contain the data for the object I didn't specify a specific default for a NOT NULL field.
My original SQL CREATE statement looked something like this.
CREATE TABLE IF NOT EXISTS `entries` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`item` VARCHAR(255) NOT NULL,
`dateCreated` TIMESTAMP NOT NULL,
`lastUpdate` TIMESTAMP NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
When the MySQL Server executed this statement it deferred the first TIMESTAMP field (in this case dateCreated) with the default to fill it with the CURRENT_TIMESTAMP and the attribute on update CURRENT_TIMESTAMP which was unexpected by me.
I corrected this problem by changing default for the field to DEFAULT '0000-00-00 00:00:00' and by changing my CREATE TABLE statement to force this default so my new statement looks like
CREATE TABLE IF NOT EXISTS `entries` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`item` VARCHAR(255) NOT NULL,
`dateCreated` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
`lastUpdate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This apparently allows me to update the fields that I want without causing the other to update automatically.
I'm still not sure why MySQL assumed the defaults that it did. I guess it's probably somewhere in the documentation.
I have to create for test reason tables in SQL format.
They should be loaded for the test set up.
And after it, Service and DAO layer should be tested.
I have stuck at creating middle for Entities.
Here is User class:
public class User {
private Integer id;
private String name;
private Calendar birthday;
private String email;
private String role;
private Set<Ticket> bookedTickets = new HashSet<>();
It contains a Set of Tickets.
Here is Ticket POJO:
public class Ticket {
private Integer id;
private Event event;
private Double price;
private User user;
It has User and Event instances.
If Ticket isn't assigned to any User (user == null) => it is free. If is => it is purchased.
Event and Auditorium POJO:
public class Event {
private Integer id;
private String name;
private Double price;
private EventRating eventRating;
private Set<Calendar> eventDateTime;
public class Auditorium {
private Integer id;
private String name;
private Integer numberOfSeats;
private Set<Integer> vipSeats;
Event has Set of available dates, coz some event can be repeated during one day few times.
Getters and setters were omitted at code snippets.
Here is my create-db.sql script:
----------------------
-- Create Users table
----------------------
CREATE TABLE Users (
user_id INTEGER PRIMARY KEY NOT NULL,
user_name VARCHAR(30) NULL,
user_birthday DATETIME NULL,
user_email VARCHAR(30) NULL,
user_role VARCHAR(20) NULL,
user_tickets VARCHAR(100) NULL, -- Here should be collection of objects
);
----------------------
-- Create Events table
----------------------
CREATE TABLE Events (
event_id INTEGER PRIMARY KEY NOT NULL,
event_name VARCHAR(30),
event_price DECIMAL(8,2),
event_rating VARCHAR(30),
event_date DATETIME,
);
---------------------------
-- Create Auditoriums table
---------------------------
CREATE TABLE Auditoriums (
aud_id INTEGER PRIMARY KEY NOT NULL,
aud_name VARCHAR(30),
aud_seats INTEGER,
aud_vip INTEGER,
);
-----------------------
-- Create Tickets table
-----------------------
CREATE TABLE Tickets (
tick_id INTEGER PRIMARY KEY NOT NULL,
event_id VARCHAR(30),
tick_price DECIMAL(8,2),
user_id INTEGER,
);
here is insert-data.sql:
------------------------
-- Populate Users table
------------------------
INSERT INTO Users VALUES (1, 'Garry Potter', '2001-05-01', 'potter#gmail.com', 'admin', NULL);
INSERT INTO Users VALUES (2, 'Ron Weasley', '2000-05-01', 'ron#gmail.com', 'user', NULL);
INSERT INTO Users VALUES (3, 'Germiona Grendjer', '2000-05-01', 'germiona#gmail.com', 'user', NULL);
------------------------
-- Populate Events table
------------------------
INSERT INTO Events (event_id, event_name, event_price, event_rating, event_date)
VALUES (1, 'Green Mile', 60.0, 'high', '2016-02-28');
INSERT INTO Events (event_id, event_name, event_price, event_rating, event_date)
VALUES (2, 'Gone by the wind', 50.0, 'middle', '2016-02-28');
I am using Spring JDBC for working with DB.
How to manage saving Set<Ticket> and Set<Calendar> with SQL script and support their unique as well?