JPA changes UUID value - java

I use varbinary(36) to save UUID in MySql as primary keys. And I use EclipseLink to auto gen my data objects. It gens primary key as String. I inserted data as below. When I use JPA to select * from country, the COUNTRY_ID becames: '66653565373765302D663832312D313165332D613361632D303830303230306339613636'. What am I doing wrong?
INSERT INTO `didicity`.`country`
(`COUNTRY_ID`, `NAME`, `SHORT_NAME`)
VALUES
('fe5e77e0-f821-11e3-a3ac-0800200c9a66',
'United State',
'USA'
);
#Id
#Column(name = "COUNTRY_ID")
private String countryId;

Related

Hibernate ignoring changes in schema.sql

I'm developing an application with Spring Boot and hibernate, which connects to a postgres instance running in docker. When I first created my schema.sql, it looked like this:
CREATE TABLE groups(
group_id varchar(255) PRIMARY KEY,
group_desc varchar(255),
group_name varchar(255)
);
The table created successfully, however I soon realized 255 is too short for my purposes and changed my schema to the following:
CREATE TABLE groups(
group_id text PRIMARY KEY,
group_desc text,
group_name text
);
However, the database keeps reverting to the original data types. I've tried dropping the table, however when the Spring app runs and it gets created again as varchar(255) instead of text. How do I force hibernate to use the updated schema?
I've tried changing the spring.jpa.hibernate.ddl-auto property to create and update, and tried changing the fields to other datatypes, including other lengths of varchar. Nothing has worked so far. Even deleting schema.sql seemingly has no effect.
My application.properties looks like this:
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=<redacted>
spring.datasource.password=<redacted>
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
The Text datatype is not a Varchar but a CLOB.
Check your Groups class. I guess the name and desc attributes are String and the default related db type is then VARCHAR(255). Thus, if you generate your schema from your entity, String always become VARCHAR(255)
If you want to use Text, your field should be annotated with #Lob
public class Groups {
#Lob
#Column(name = "group_desc")
private String desc
#Lob
#Column(name = "group_name")
private String name
}
This being stated, I think you should change your java/db model because having a Lob/Text type as primary/foreign key frightens me a little (even if I never tried)
CREATE TABLE groups(
group_id bigint PRIMARY KEY,
group_code text NOT NULL UNIQUE,
group_desc text,
group_name text
);
public class Groups {
#Id
#Column(name = "group_id")
private Long id;
#Lob
#Column(name = "group_code", nullable = false, unique = true)
private String code;
#Lob
#Column(name = "group_desc")
private String desc;
#Lob
#Column(name = "group_name")
private String name;
}
NB : I usually don't generate the schema from entities so I instead use the code below to map a db text field to entity attribute :
#Column(name = "group_desc", columnDefinition = "CLOB")
private String desc;
But I am not sure if this is handled correctly to generate the schema

How to add two ID Sequence Auto Increment In Postgres And Mapping With Hibernate

I'm Developing small MicroService Using Spring boot.
My database Is Postgres and I have a pojo in my service mapping the table.
Initially my Table is created with one Primary Key NOT NULL serial.
Now I want to add One more column with serial number starting from 6000 and map with my pojo.
#JsonProperty("id")
#Column(name = "id", nullable = false)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY,generator = "order_seq_gen")
#SequenceGenerator(name = "order_seq_gen", sequenceName ="order_id_seq")
private Integer id;
#JsonProperty("state")
private String state;
#JsonProperty("user_Id")
#Column(name = "user_Id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY,generator = "user_seq_gen")
#SequenceGenerator(name = "user_seq_gen", sequenceName ="user_id_seq")
private Integer userId;
This is My Pojo.
The first Id Is creating but the userId Is not creating.
Bellow is my Table structure and sequences.
This is my create table statement
CREATE TABLE public.user
(
id integer NOT NULL DEFAULT nextval('user_id_seq'::regclass),
created timestamp without time zone,
modified timestamp without time zone,
state character varying(255),
name text,
user_id integer NOT NULL DEFAULT nextval('user_id_seq'::regclass), CONSTRAINT user_pkey
PRIMARY KEY (id)
)
Below is my sequence.
CREATE SEQUENCE public.user_id_seq INCREMENT 1 MINVALUE 6001
MAXVALUE 9223372036854775807 START 6000 CACHE 1;
ALTER TABLE public.user_id_seq OWNER TO postgres;
What I'm trying is in my table the column user_id should generate Auto from Base as 6000 and increment each time by 1.
Whenever I call API from my service it is creating new record. But the user_id is not showing anything.

How to insert entity with foreign keys defined as Long in Hibernate?

I'm using Hibernate 3.6.8 and I have a table defined in mysql (5.5) like this:
CREATE TABLE mytable
(
id BIGINT(20) PRIMARY KEY NOT NULL,
version INT(11),
description VARCHAR(60),
scheduled_at DATETIME,
`from` BIGINT(20),
`to` BIGINT(20),
deleted BIT(1) DEFAULT b'0',
completed BIT(1) DEFAULT b'0',
delete_from_after_completion BIT(1) DEFAULT b'0',
CONSTRAINT FK14F71A73C588I54F FOREIGN KEY (`from`) REFERENCES other_table (id),
CONSTRAINT FK14F71C231C45J198 FOREIGN KEY (`to`) REFERENCES other_table (id)
);
CREATE INDEX FK14F71A73C588I54F ON mytable (`from`);
CREATE INDEX FK14F71C231C45J198 ON mytable (`to`);
And a Java entity defined like this:
#Entity
public class MyTable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Version
#Column(name = "version")
private Integer version;
#Column(name = "description")
private String description;
#Column(name = "scheduled_at")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(style = "SM")
private Date scheduledAt;
#Column(name = "from")
private Long fromId;
#Column(name = "to")
private Long toId;
#Column(name = "deleted")
private boolean deleted;
#Column(name = "completed")
private boolean completed;
#Column(name = "delete_from_after_completion")
private boolean deleteFromEntityAfterCompletion;
...
}
When I try to persist an instance of MyTable with valid values I end up with the following error:
2016-01-12 10:06:33,443 [qtp2139431292-20] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1064, SQLState: 42000
2016-01-12 10:06:33,443 [qtp2139431292-20] ERROR org.hibernate.util.JDBCExceptionReporter - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from, scheduled_at, to, version) values (0, 1, 0, 'Test', 10, '2016-01-13 00:00:' at line 1
I suspect that the problem occurs since I try to model the foreign key relationships (to and from) as Long instead of an entity (OtherTable). I suspect this because Hibernate can indeed persist this entity if I comment out the to and from fields. Note that the relationship to the to and from entities does indeed exists in the database so that's not the problem.
If I try insert manually using something like this it works:
insert into mytable values(3, 0, "desc", '2016-10-10 00:00:', 10, 11, 0, 0, 0);
You have a column that is a SQL reserved keyword ("from") and Hibernate doesn't bother quoting it for you. Other JPA implementations (e.g DataNucleus JPA) take care of such things for you. You will have to add single quotes around the reserved word in your JPA annotation information
I am pretty sure that the problem is not a matter of persisting Long values.
Your code has something wrong. I bet there is a wrong quotation mark in your insert code.

JPA composite primary key with null value

I have a table containing customer data in an oracle database. Here is a simplified definition:
CUSTOMER (CUSTOMER_ID NUMBER NOT NULL,
SOURCE_SYSTEM VARCHAR2(30),
FULL_NAME VARCHAR2(360),
PHONE_NUMBER VARCHAR2(240)
)
The primary key for this table is (CUSTOMER_ID, SOURCE_SYSTEM).
The table has numerous rows for which SOURCE_SYSTEM is null. At the database level, there is no issue, however when I try to access any of these rows via JPA Entity, it causes a number of issues:
1: Using em.find() to fetch a row with a null SOURCE_SYSTEM always results in a null being returned.
2: Using em.merge() to upsert a row with a null SOURCE_SYSTEM succeeds if the record does not exist in the table, but fails on subsequent updates because the merge ALWAYS results in an insert being run.
3: Using em.createQuery() to explicitly query for a row with a null causes the following exception:
Exception [EclipseLink-6044] (Eclipse Persistence Services - 2.3.1.v20111018-r10243):
org.eclipse.persistence.exceptions.QueryException
Exception Description: The primary key read from the row [ArrayRecord(
CUSTOMER.CUSTOMER_ID => 1
CUSTOMER.FULL_NAME => GUY PERSON
CUSTOMER.PHONE_NUMBER => 555-555-1234
CUSTOMER.SOURCE_SYSTEM => null)] during the execution of the query was detected to be null.
Primary keys must not contain null.
Query: ReadAllQuery(referenceClass=Customer sql="SELECT CUSTOMER_ID, FULL_NAME, PHONE_NUMBER, SOURCE_SYSTEM FROM CUSTOMER WHERE ((CUSTOMER_ID = ?) AND (SOURCE_SYSTEM IS NULL))")
Unfortunately, "Primary keys must not contain null" seems pretty final. I was unable to find too much information on workarounds for this error, which makes it seem like there is no solution.
THE QUESTION: I would like to know if anyone has any Java code-based solution that don't involve making changes to the database. My current workaround is to use ROW_ID as the #Id of the table, but this means I can no longer use em.merge() or em.find().
Here are my Java classes:
Customer.java:
#Entity
#Table(name = "CUSTOMER")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private Customer_Id key;
#Column(name = "CUSTOMER_ID", nullable = false, insertable = false, updatable = false)
private Long customerId;
#Column(name = "SOURCE_SYSTEM", length = 30, insertable = false, updatable = false)
private String sourceSystem;
#Column(name = "FULL_NAME", length = 360)
private String fullName;
#Column(name = "PHONE_NUMBER", length = 240)
private String phoneNumber;
//Setters, Getters, etc
...
}
Customer_Id.java
#Embeddable
public class Customer_Id implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "CUSTOMER_ID", nullable = false)
private Long customerId;
#Column(name = "SOURCE_SYSTEM", length = 30)
private String sourceSystem;
//Setters, Getters, etc
...
}
Primary keys cannot contain null (in JPA or in databases). Use a different value such as "" or " ".
Is the customer_id unique? if so then just remove the sourceSystem from the Id.
Otherwise, you could try logging a bug to have support for null ids added.

JPA joined column allow every value

I'm testing JPA, in a simple case File/FileVersions tables (Master/Details), with OneToMany relation, I have this problem: in FileVersions table, the field "file_id" (responsable for the relation with File table) accepts every values, not only values from File table.
How can I use the JPA mapping to limit the input in FileVersion.file_id only for values existing in File.id?
My class are File and FileVersion:
FILE CLASS
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="FILE_ID")
private Long id;
#Column(name="NAME", nullable = false, length = 30)
private String name;
//RELATIONS -------------------------------------------
#OneToMany(mappedBy="file", fetch=FetchType.EAGER)
private Collection <FileVersion> fileVersionsList;
//-----------------------------------------------------
FILEVERSION CLASS
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="VERSION_ID")
private Long id;
#Column(name="FILENAME", nullable = false, length = 255)
private String fileName;
#Column(name="NOTES", nullable = false, length = 200)
private String notes;
//RELATIONS -------------------------------------------
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="FILE_ID", referencedColumnName="FILE_ID", nullable=false)
private File file;
//-----------------------------------------------------
and this is the FILEVERSION TABLE
CREATE TABLE `JPA-Support`.`FILEVERSION` (
`VERSION_ID` bigint(20) NOT NULL AUTO_INCREMENT,
`FILENAME` varchar(255) NOT NULL,
`NOTES` varchar(200) NOT NULL,
`FILE_ID` bigint(20) NOT NULL,
PRIMARY KEY (`VERSION_ID`),
KEY `FK_FILEVERSION_FILE_ID` (`FILE_ID`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
Thanks for help,
I know the SQL constraint to limit the input, but it is possible to create this SQL costraint using some annotation, without writing by hand the SQL in the database?
I'm new on JPA, I was thinking that using #JoinColumn annotation, JPA could create also the costraint...
Thank you again.
At the Java level, you describe and annotate associations between classes - which and you did - and your mapping looks fine.
At the database level, if you want to restrict the possible values in the file_id column to values that are primary keys in the FILE table, you should use a foreign key constraint. To do so, you will need to use InnoDB tables. Something like that:
CREATE TABLE `JPA-Support`.`FILEVERSION` (
`VERSION_ID` bigint(20) NOT NULL AUTO_INCREMENT,
`FILENAME` varchar(255) NOT NULL,
`NOTES` varchar(200) NOT NULL,
`FILE_ID` bigint(20) NOT NULL,
PRIMARY KEY (`VERSION_ID`),
FOREIGN KEY `FK_FILEVERSION_FILE_ID` (`FILE_ID`) REFERENCES FILE(ID)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
The table FILE also has to use InnoDB. Actually, use InnoDB tables for the tables for which you want to use referential integrity.

Categories