Conversion String to UUID in Postgres and Java - 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.

Related

When Using sql2o, what is the org.sql2o.converters.ConverterException?

I am using the .executeScalar() method from the sql2o .jar file. I am getting this exception when using an Employee POJO, when I use .executeScalar(Employee.class) I am getting:
org.sql2o.converters.ConverterException: No converter registered for class: com.mack.sales.employees.Employee
I cannot find anything to help resolve this issue, any help is appreciated.
Converters are what sql2o uses to convert from database values to Java values. For instance, if one of your properties in your pojo is an integer, sql2o uses its integer converter to convert from any compatible database datatype (int, number, etc) to integer.
The executeScalar method will fetch only one value (first column and first row) from the database and convert it to a Java value. It is meant to be used with single value queries. For instance a select count(*) from table.
To fetch multiple columns and map their values to a pojo, you can use the executeAndFetchFirst() method.

Java UUID or QueryBuilder uuid

I'm using Datastax Java driver to perform basic insert statement in Cassandra database. My primary key column is uuid type. From what I see in official documentation, recommended way to call uuid() function in Cassandra is to use QueryBuilder#uuid() method. However, is it safe to use java util's UUID.randomUUID() too, since my types are colliding (QueryBuilder.uuid() returns Object while UUID.randomUUID() returns UUID)?
UUID.randomUUID() creates type-4 UUID and it is safe to use.
Infact, datastax UUID utility class com.datastax.driver.core.utils.UUIDs has a method named random(), which is just a convenience for UUID.randomUUID()
If you are using the generated UUID for ordering (clustering key), please use QueryBuilder#uuid(). This is because Cassandra has a different implementation. The Java UUID ordering is different.
If you are using it as any other key, it doesn't matter.
Hope it helps!

JPA - Mapping an Entity's field to a database function result

I'm using JPA 2.0. Is it possible to map an Entity's attribute (column) to the result of a function and then control the way it's persisted too?
Note: This is related to PostGIS. Since there is no native support for Geometry types in JPA/EclipseLink, I might do something like this:
#Entity
public class Foo {
#Column(name="geom", appendBeforeChange( ST_FromKml ))
public String kmlString;
}
In other words, I could store the geometry as a String in Java, but when EclipseLink writes it to the database, it should first call the database function ST_FromKml and provide the String, which will convert it to the Geometry type in the database...
I know it's a stretch, but figured I would ask...
I actually found a workaround with help from this post:
Are JPA (EclipseLink) custom types possible?
In Postgres, I create an implicit cast from String to Geometry:
CREATE OR REPLACE FUNCTION geom_in_text(varchar) RETURNS geometry AS $$
SELECT ST_GeomFromText($1::varchar);
$$ LANGUAGE SQL IMMUTABLE;
CREATE CAST (varchar AS geometry) WITH FUNCTION geom_in_text(varchar) AS IMPLICIT;
And now in Java, I just keep my Entity member variable as a String in WKT format. When Postgres see's the INSERT, it will recognize the avaiable implicit cast and not complain.
Note - I store WKT in my Entity class, but I could theoretically store KML and then update my function to call ST_GeomFromKml instead...

How should I save UUID with JPA?

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).

JPA merge fails due to duplicate key

I have a simple entity, Code, that I need to persist to a MySQL database.
public class Code implements Serializable {
#Id
private String key;
private String description;
...getters and setters...
}
The user supplies a file full of key, description pairs which I read, convert to Code objects and then insert in a single transaction using em.merge(code). The file will generally have duplicate entries which I deal with by first adding them to a map keyed on the key field as I read them in.
A problem arises though when keys differ only by case (for example: XYZ and XyZ). My map will, of course, contain both entries but during the merge process MySQL sees the two keys as being the same and the call to merge fails with a MySQLIntegrityConstraintViolationException.
I could easily fix this by uppercasing the keys as I read them in but I'd like to understand exactly what is going wrong. The conclusion I have come to is that JPA considers XYZ and XyZ to be different keys but MySQL considers them to be the same. As such when JPA checks its list of known keys (or does whatever it does to determine whether it needs to perform an insert or update) it fails to find the previous insert and issuing another which then fails. Is this corrent? Is there anyway round this other than better filtering the client data?
I haven't defined .equals or .hashCode on the Code class so perhaps this is the problem.
I haven't defined .equals or .hashCode on the Code class so perhaps this is the problem.
Well, you really should, you don't want to inherit from the behavior of Object for Entities. Whether you want to use the primary key, do a case sensitive comparison, or use a business identity is another story but you certainly don't want to use reference equality. You don't want the following entities:
Code code1 = new Code();
code1.setKey("abc");
Code code2 = new Code();
code2.setKey("abc");
To be considered as different by JPA.
Second, if you want to be able to insert an Entity with XYZ as key and another one with XyZ, then you should use a case sensitive column type (you can make the varchar column case sensitive by using the binary attribute) or you'll get a primary key constraint violation.
So, to summarize:
implements equals (and hashCode), decide whether you need case sensitive comparison of the key or not.
use the appropriate column type at the database level.
This depends on how your column is defined in mySQL. mySQL is the oddman out of databases in that VARCHAR and similar columns default to case insensitive matches. If you want XYZ and XyZ to be distinct legal options, you'll need to change your CREATE TABLE statement to create a case sensitive column (see docs for your version of mySQL.)
It's likely something like this:
CREATE TABLE code (
key VARCHAR(32) BINARY,
value VARCHAR(32) BINARY
)

Categories