How should I save UUID with JPA? - java

How should I work with UUID and JPA?
Should I assign the random UUID value to a String field in my class? Or should I have a field with type UUID and do something else to it when I want to map it to a column?

That depends on the database.
There are databases such as H2, MSSQL and PostgreSQL that support a uniqueidentifer type.
For these types you can extend the provided Dialect (i.e - PostgreSQLDialect) and add handling of the new type.
I implemented something like that, based on the following post , for both MSSQL and Postgresql.
For databases that do not support a uniqueidentifier/UUID type, you should use String.
This means that you should also ask yourself if your application must support multiple database vendors, or if you can stick with a single vendor (and then select the first option, if applicable).

Related

User-defined types in Apache Derby as ENUM replacements

I'm using Apache Derby as an in-memory mock database for unit testing some code that works with MySQL using jOOQ.
The production database uses enums for certain fields (this is a given and out of scope of this question - I know enums are bad but I can't change this part now), so jOOQ generates code to handle the enums.
Unfortunately, Derby does not support enums and when I try to create the database in Derby (from jOOQ SQL generator), I get errors.
My solution was to user-defined types that mimic the enum by wrapping the relevant jOOQ generated enum Java class. So, for example, if I have an enum field kind in the table stuffs, jOOQ SQL generator creates Derby table creation SQL that talks about stuffs_kind.
To support this I created the class my.project.tests.StuffsKindDebyEnum that wraps the jOOQ generated enum type my.project.model.StuffsKind. I then run the following SQL through Derby, before running the jOOQ database creation SQL:
CREATE TYPE stuffs_kind EXTERNAL NAME 'my.project.tests.StuffsKindDerbyEnum' LANGUAGE JAVA
When I then use jOOQ to insert new records, jOOQ generates SQL that looks somewhat like this:
insert into "schema"."stuffs" ("text", "kind")
values (cast (? as varchar(32672)), cast(? as stuffs_kind)
But binds a string value to the kind argument (as expected), and it work for MySQL but with Derby I get an exception:
java.sql.SQLDataException: An attempt was made to get a data value of type
'"APP"."STUFFS_KIND"' from a data value of type 'VARCHAR'
After looking at all kinds of ways to solve this problem (including trying to treat enums as simple VARCHARs), and before I give up on being able to test my jOOQ-using code, is there a way to get Derby to "cast" varchar into user-defined types? If could put some Java code that can handle that, it will not be a problem as I can simply do StuffsKind.valueOf(value) to convert a string to the correct enum type, but after perusing the (very minimal) Derby documentation, I can't figure out if it is even should be possible.
Any ideas are welcome!
Implementing a dialect sensitive custom data type binding:
The proper way forward here would be to use a dialect sensitive, custom data type binding:
https://www.jooq.org/doc/latest/manual/sql-building/queryparts/custom-bindings
The binding could then implement, e.g. the bind variable SQL generation as follows:
#Override
public void sql(BindingSQLContext<StuffsKindDerbyEnum> ctx) throws SQLException {
if (ctx.family() == MYSQL)
ctx.render().visit(DSL.val(ctx.convert(converter()).value()));
else if (ctx.family() == DERBY)
ctx.render()
.sql("cast(
.visit(DSL.val(ctx.convert(converter()).value()))
.sql(" as varchar(255))");
else
throw new UnsupportedOperationException("Dialect not supported: " + ctx.family());
}
You'd obviously also have to implement the other methods that tell jOOQ how to bind your variable to a JDBC PreparedStatement, or how to fetch it from a ResultSet
Avoiding the MySQL enum
Another, simpler way forward might be to avoid the vendor-specific feature and just use VARCHAR in both databases. You can still map that VARCHAR to a Java enum type using a jOOQ Converter that will work the same way in both databases.
Simplify testing by avoiding Derby
A much simpler way forward is to test your application directly on MySQL, e.g. on an in-memory docker virtualisation. There are a lot of differences between database vendors and their features, and at some point, working around those differences just to get slightly faster tests doesn't seem reasonable.
The exception is, of course, if you have to support both Derby and MySQL in production, in case of which the data type binding is again the best solution.

Corresponding java datatype for Numeric(9,2) in sybase

I want to insert a Numeric(9,2)value through SP in Sybase which is being invoked through Java.
What data type should I use in java side.
When you have to write an application to use data stored on database I suggest you to search for the default data type mapping of the jdbc driver you have to use (it depends on target database).
In your situation you could check this data type mapping http://jtds.sourceforge.net/typemap.html. For numeric the default is BigDecimal. In my experience BigDecimal saves some headaches.

Conversion String to UUID in Postgres and Java

I need to convert String ( text ) to UUID ( Postgres ) and keep the same sorting like for a String. Is it possible? I saw the UUID base on the time, so maybe it's not possible?
In PostgresSQL's SQL grammar
Using
concat(UUID,'')
returns a text result. Using
uuid(text)
returns a UUID result.
In PostgreSQL, apart from using uuid(), it's also possible to specify the type explicitly like ::uuid:
with myconst (__ef_filter__id_0, __filter_workitemid_0, __filter_projectid_1, __id_2) as (
values ( 'fcb8284c-1bd4-4d50-b5df-09a091b01d8c'::uuid, '9e4b70a7-c222-47dd-87cb-fbbaaf396ccd'::uuid, uuid('2b10c0a5-e35d-425d-a71a-9e473924ac4c'), uuid('3fa85f64-5717-4562-b3fc-2c963f66afa6')) )
select ...
There is a class in JDK dedicated to the management of UUIDs, called java.util.UUID. There's a static method fromString in it that should fit your goal. As far as I can see, you can use instances of UUID in JDBC insert statements.
At oVirt open source project, we use the PostgreSQL uuid type to store our Primary keys and Foreign keys.
We have build a wrapper called Guid that uses the java.util.UUID class to hold the read data from the DB.
When retrieving a ResultSet (we use spring-jdbc) we use the getString method in order to get the UUID value as String, and then use the fromString method of java.util.UUID.
You can git clone our project and look at ovirt-engine/backend/manager/modules/dal (our data access layer) project for more information.

Type casting in Hibernate for column in Informix database

I am using Informix for a OR database and Spring + Hibernate on the backend of my application.
The thing is, I make in a String variable the query that inserts data in the database table. In this query string I'm using type casting for some columns (something like this: ..ROW(street,city,country)::addressT.. where addressT is the type I made in the database).
The problem here lays in Hibernates createSQLQuery(String query) method. When I pass it the query string, it automatically searches in that string for named parameters (:namedParameter - so the "colon" sign and the name of the parameter) and tries to replace it with something.
The result is a query like this: ...ROW(street,city,country)?...
Is there any way to disable hibernates automatic named parameter replacement or is there any other way to forward the native query to my Informix database?
You might be able to use the CAST(<expression> AS <type>) notation.
Beware of other system's adamant insistence that 'db#server:owner.table' or 'DATETIME(12:13:14) YEAR TO SECOND' contain placeholders, not legitimate Informix syntactic constructs.

Adding a constraint to a JPA or Hibernate entity column using annotations

I want to have a column for an entity which only accepts one of an enumerated set of values. For example let's say I have a POJO/entity class "Pet" with a String column "petType". I want petType to only allow one of three values: "cat", "dog", or "gorilla". How would I go about annotating the getPetType() method in order to have a database level constraint created which enforces this?
I am allowing Hibernate to create or update my database table at application start up via the Hibernate property "hbm2ddlauto" being set to "update".
I have tried using a parameterized user type in association with the #Type annotation but this doesn't appear to provide any sort of constraint on the database column itself. There doesn't appear to be a way of specifying this sort of constraint in the #Column annotation short of using some SQL with the columnDefinition element, and I'm hesitant to go this route since it seems that whatever I use there will not be cross platform/database independent (important to me since I run my code in production on Oracle but I do testing locally using HSQLDB and Derby). Maybe what I want to do just can't be done simply using annotations.
Thanks in advance for any insight you can give me on this topic.
Create a enum of type PetType and defined you mapping as
#Enumerated(EnumType.STRING)
That way, strings are stored in the database and your java enum type only accept the 3 values you specify.

Categories