only select columns of the a psql table could receive data - java

Something very bizarre have been happening. I have a very simple Entity recipe like so
#Data
#Entity
#Table(name = "recipe", schema = "public")
#AllArgsConstructor
#NoArgsConstructor
public class Recipe {
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
#Column(name = "id", updatable = false, nullable = false)
private long id;
#Column(name = "name")
private String name;
#Column(name = "instructions")
private String instructions;
#Column(name = "date_added", nullable = false)
private String dateAdded;
#Column(name = "last_edited", nullable = false)
private String lastEdited;
}
and I have this post service that should post the 4 string attribute to the database
public void postRecipe(Recipe recipe){
var sql = """
INSERT INTO public.recipe ("name","instructions","date_added","last_edited")
VALUES (?, ?, ?, ?)
""";
jdbcTemplate.update(
sql,
recipe.getName(),
recipe.getInstructions(),
recipe.getDateAdded(),
recipe.getLastEdited()
);
}
However when the following jason is sent using postman, I get the null value error.
{
"name":"test",
"instructions":"don't eat",
"date_added":"03/04/2017",
"last_edited":"03/04/2017"
}
ERROR: null value in column \"date_added\" of relation \"recipe\" violates not-null constraint\n Detail: Failing row contains (3, null, don't eat, null, test)
The strangest thing is that only the "name" and "instruction" columns receive their data and not the other columns. I have tried adding another String attribute to the Entity class and it also cannot get data from the jason.
Edit 1:
I have tried adding the data directly through pgadmin and it worked fine
INSERT INTO recipe (name, instructions, date_added, last_edited)
VALUES ('test', 'test instruction', '2020/03/05', '2020/05/08');

It looks like your deserialization is broken - transforming your JSON into the Java entity, which results in some null values present. Most likely because date_added != dateAdded (field name), and Jackson cannot properly set a value.
I recommend having a look at Jackson guide: https://www.baeldung.com/jackson-annotations, #JsonProperty specifically. And overall do not mix entities and DTOs

After many trials and errors I was able to come up with a solution but still have no clue as to why this is happening. It turns out the under score in the annotation is the problem.
//won't work
#Column(name = date_added)
//works
#Column(name = dateadded)
This is pretty strange because I am fairly certain that the under score is generated by hibernate.
if anyone know why this is happening please let me know... for now I will just stay away from the under scrolls.

Related

Quarkus with hibernate found [bpchar (Types#CHAR)], but expecting [char (Types#VARCHAR)]

Hello i'm trying to learn Quarkus with Hibernate but i've ran into an issue the schema-validation.
The error:
2021-12-29 16:05:14,915 ERROR
[io.qua.hib.orm.run.sch.SchemaManagementIntegrator] (Hibernate
post-boot validation thread for ) Failed to validate Schema:
Schema-validation: wrong column type encount ered in column [BED_INFO]
in table [ROOM]; found [bpchar (Types#CHAR)], but expecting [char
(Types#VARCHAR)] 2021-12-29 16:05:14,921 ERROR
[io.qua.hib.orm.run.sch.SchemaManagementIntegrator] (Hibernate
post-boot validation thread for ) The following SQL may
resolve the database issues, as generated by the Hibernate schema
migration tool. WARNING: You must manually verify this SQL is correct,
this is a best effort guess, do not copy/paste it without verifying
that it does what you expect.
the class Room looks like this
#Entity
#Table(name = "ROOM")
public class Room {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ROOM_ID")
private long id;
#Column(name = "NAME")
private String name;
#Column(name = "ROOM_NUMBER")
private String roomNumber;
#Column(name = "BED_INFO", columnDefinition = "char")
private String bedInfo;
public Room(String name, String roomNumber, String bedInfo) {
this.name = name;
this.roomNumber = roomNumber;
this.bedInfo = bedInfo;
}
}
and the mysql schema like this
CREATE TABLE ROOM(
ROOM_ID BIGSERIAL PRIMARY KEY,
NAME VARCHAR(16) NOT NULL,
ROOM_NUMBER CHAR(2) NOT NULL UNIQUE,
BED_INFO CHAR(2) NOT NULL
);
According to their documentation this "should" work but i'm perhaps missing something here.
[BED_INFO] in table [ROOM]; found [bpchar (Types#CHAR)], but expecting [char (Types#VARCHAR)]
Means that Hibernate has found a bpchar(char) where it would expect a varchar. It seems that columnDefinition does not handle char. If you really want it to be a char, try bpchar instead.
In case it doesn't work, try running your quarkus app in dev mode with this option in the application.properties file.
quarkus.hibernate-orm.database.generation=create
This will generate the actual DDL for your database that Hibernate is expecting.
Personally I would refrain from columnDefinition, instead i would use length and nullable. Unless you are building an app on an existent, I would also remove name and #Table.

Hibernate: Reference a column in an association, for efficency

For simplicity I'll chop the tables down quite a bit
Given the tables REPORT_DOWNLOAD, REPORT
REPORT has ID, NAME
REPORT_DOWNLOAD has ID, FK_REPORT_ID
I essentially want to build the query:
SELECT R.NAME, RD.ID FROM REPORT_DOWNLOAD RD, REPORT R WHERE
RD.FK_REPORT_ID = R.ID
My entity for REPORT_DOWNLOAD essentially looks like
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "FK_REPORT_ID", referencedColumnName = "ID", nullable = false)
private ReportOrm report;
But that queries the whole REPORT table. Is there a way to reference just the NAME column from the entity?
#SomeAnnotationThatMagicallyPulls("FK_REPORT_ID", "NAME")
private String reportName;
I feel like there must be some Hibernate / JPA magic here that I could use

Hibernate doesn't persist when inserting long texts

I'm using Postgresql 9.6 and before I was using mySQL an I get the same problem with the two databases. I also have the same problem with Hibernate 4 and 5.
When I'm trying to persist an Object with a long String inside, it never ends the method session.persist(object). In the other hand it works perfectly when the string ismySQL an I get the same problem with the two databases.
not that long, like this paragraph.
addVehicle method in VehicleDAO.java
public Vehicle addVehicle(Vehicle vehicle) {
Session session =
this.sessionFactory.getCurrentSession();
session.persist(vehicle);
return vehicle;
}
Vehicle attributes:
public class Vehicle {
#Id
#Column(name = "idvehicle")
#GeneratedValue(strategy = GenerationType.IDENTITY)
int idVehicle;
#Column(name = "name")
String name;
#Column(name = "description")
String description;
#Column(name = "photob64")
String photoB64;
Eclipse console log:
Hibernate: insert into vehicle (description, name, photob64, idvehicletype) values (?, ?, ?, ?)
Hibernate doesn't persist when inserting long texts
As per your question, it doesn't persist when inserting long texts. It's is because by default String lenght is 255. You can see in database. The VARCHAR(255) lenght is 255.
You can mentioned length by using below approach:
#Column(name=" description", length = 300)
private String description;
If you are not sure of length, then it's good idea to go with lob, blob or clob as per your need. You can read details of lob, blob and clob and select one of them. For text lob or clob will work for you.
There are two ways,
You can set columnDefinition like
#Column(name = "notes", columnDefinition = "varchar(300)")
private String notes;
If you don't know maximum length of string you can set columnDefinition as text like
#Column(name = "notes", columnDefinition = "text")
private String notes;
I figured out what was happening. The method persist never ended because the information couldn't be transferred completely to the DB which was in other device, a Raspberry Pi.
I changed the MTU of the network adapters of my PC and Raspberry Pi to 1492 with the command:
sudo ifconfig eth0 mtu 1492
More info: http://www.ubuntugeek.com/how-to-change-mtu-maximum-transmission-unit-of-network-interface-in-ubuntu-linux.html

Native named query fails with exception "column is of type date but expression is of type bytea"when NULL LocalDate is given as input

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.

Hibernate - byNaturalId not working

I have a user entity identified by two natural ids, something like
#Entity
#Table(name = "user", uniqueConstraints =
{ #UniqueConstraint(columnNames = "email"),
#UniqueConstraint(columnNames = "nick") })
public User()
{}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private id;
#Column(name = "email", unique = true, nullable = false, length = 31)
#NaturalId(mutable = true)
private String email;
#Column(name = "nick", unique = true, nullable = false, length = 31)
#NaturalId(mutable = false)
private String nick;
However, when I try to execute
session.byNaturalId(User.class).with(LockOptions.READ).using("email", "admin#mail.com").load();
it throws an exception
org.hibernate.HibernateException: Entity [pervasive.com.gmail.tigerjack89.forum.shared.model.entities.User] defines its natural-id with 2 properties but only 1 were specified
at org.hibernate.event.spi.ResolveNaturalIdEvent.<init>(ResolveNaturalIdEvent.java:75)
at org.hibernate.event.spi.ResolveNaturalIdEvent.<init>(ResolveNaturalIdEvent.java:52)
at org.hibernate.internal.SessionImpl$BaseNaturalIdLoadAccessImpl.resolveNaturalId(SessionImpl.java:2607)
at org.hibernate.internal.SessionImpl$NaturalIdLoadAccessImpl.load(SessionImpl.java:2722)
at pervasive.com.gmail.tigerjack89.forum.server.model.orm.StorageManager.getByNaturalId(StorageManager.java:217)
at pervasive.com.gmail.tigerjack89.test.local.MyHibernateTest.test1(MyHibernateTest.java:37)
at pervasive.com.gmail.tigerjack89.test.local.MyHibernateTest.main(MyHibernateTest.java:23)
Why is this? I think it's also due to the log of the SQL syntax generated by Hibernate. Indeed, it is strange (redundant) at this point and I think it's the cause of the exception
Hibernate:
alter table user
add constraint UK_t8tbwelrnviudxdaggwr1kd9b unique (email, nick)
Hibernate:
alter table user
add constraint UK_ob8kqyqqgmefl0aco34akdtpe unique (email)
Hibernate:
alter table user
add constraint UK_pvnbxcfihb58o5n2n1fnc7fh1 unique (nick)
EDIT: Reading the code again, I thought that the problem could be related to the #UniqueConstraints annotations. However, even if I try to remove one of them, Hibernate continues to genetate the above SQL syntax.
I would make the email address alone the NaturalId and then your query would work.
When two columns are identified as the NaturalId it creates a Composite Key.
Nick could still be used as a foreign Key.
You've a composite naturalId key (email,nick) so you can have multiples results with simple email arg.
you've to use
session
.byNaturalId(User.class)
.with(LockOptions.READ)
.using("email", "admin#mail.com")
.using("nick", "admin")
.load();
You can also use Metamodel
session
.byNaturalId(User.class)
.with(LockOptions.READ)
.using(User_.email.getName(), "admin#mail.com")
.using(User_.nick.getName(), "admin")
.load();

Categories

Resources