Jooq enum converter uses the ordinal number. How can I switch to use the enum value number instead? - enums

We have an Enum class with customized values. The values are different from their ordinals intentionally for business purpose which I cannot change.
enum class Role(val value: Int) {
EXECUTOR(1),
MONITOR(3),
ADMIN(5),
companion object {
private val map = Role.values().associateBy(Role::value)
fun fromInt(role: Int) = map[role]
}
}
We are using JOOQ and postgres. We use the JOOQ default EnumConverter to convert db role integer values to objects.
ForcedType()
.withUserType("com.company.enums.Role")
.withEnumConverter(true)
.withIncludeExpression("role"),
However we noticed a problem -- the database stored the ordinals of the enum, instead of the values. For example we see in the db in roles column, the db value is 1, and the translated Enum is MONITOR, coz MONITOR has an ordinal of 1.
How can we store the values of Enum into db using JOOQ?
Thank you!

You can of course implement a custom converter from scratch, as you suggested in your own answer. But do note that starting from jOOQ 3.16 and https://github.com/jOOQ/jOOQ/issues/12423, you can simplify that implementation by extending the org.jooq.impl.EnumConverter like this:
class RoleConverter : EnumConverter<Int, Role>(
Int::class.java,
Role::class.java,
Role::value
)

Ohhh I figured it out! There's Custom Converter https://www.jooq.org/doc/latest/manual/code-generation/custom-data-types/ which is exactly what I need.

Related

Spring JPA criteria builder greaterThan : Can I pass String value for comparing Number type in database

I am using Spring Data JPA criteria builder greaterThan API for doing a comparison.
The database field rating is of type NUMBER(5,0). Entity class has a field rating which is of type Integer. And I am passing the value of type String for the comparison.
Even though I am not passing the Integer value for the comparison, still it is returning valid results. Please help me understand how this is possible.
Does it mean, I can pass the java String version of the database field to the greaterThan method when the actual data type of the field in the database is of a different type.
and my comparison block of code looks like this
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery();
Root<Customer> root = cq.from(Customer.class);
//you can see here , value 20 I am passing as String
Predicate comparisonPredicate = cb.greaterThan(root.get("rating"), "20");
cq.where(comparisonPredicate );
cq.select(root);
TypedQuery<Customer> query = entityManager.createQuery(cq);
This behavior is not documented.
Looking at the openJPA source code for Expressions.GreaterThan, and more specifically the toKernelExpression,
#Override
org.apache.openjpa.kernel.exps.Expression toKernelExpression(ExpressionFactory factory, CriteriaQueryImpl<?> q){
Value val1 = Expressions.toValue(e1, factory, q);
Value val2 = Expressions.toValue(e2, factory, q);
Expressions.setImplicitTypes(val1, val2, e1.getJavaType(), q);
return factory.greaterThan(val1, val2);
}
JPA uses the type of the first expression to build the query.
This behavior looks to be an accidental feature more than an intentional implementation. You should not rely on this and should explicitly cast the variable. You could also use a MetaModel to get a compiler error when trying to compare apples to oranges.

Hibernate Transformers.aliasToBean Josn String to List<>

I have a table called user_request and it has request_payload column of type text and I want to map this column to List in my DTO class using result transformer
 private Integer id;
 private List<userRequest> userRequestList;
 // setter and getters
}
is possible to get result like this from db using result transformer
Yes that is possible. Just look into the documentation which nicely explains how you can do this ;)

How to pass column name dynamically inside a #Query annotation using Spring data JPA

I have entity like:
#Id
#Column_name = "abc"
int pk;
#Column_name = "def"
int id;
And I have Repository as:
interface fetchDataRepository extends jpaRepository<className, int> {
#Query("Select S_Test.nextVal from dual");
Long generateId();
}
In above example S_Test is hardcoded sequence name.
But the problem is that I want to pass sequence name dynamically as follows:
Long generateId(#Param("sequenceName") String sequenceName)
and use inside #Query annotation as:
#Query("Select :sequenceName.nextVal from dual");
Is there anyway to do that? Any suggestion would be appreciated.
Edit: Isn't there possible to use #(#entityName). If yes, then please tell me how?
Unfortunately you can only substitute in things that you could do in JDBC anyway (so, pretty much just values in the INSERT and WHERE clauses). No dynamic table, column, schema names are supported.
There is one exception that may apply, and that is a limited subset of SpEL can be used. There is one variable available - #entityName. So, assuming that the #Entity annotation on your entity class is named identically to the sequence, you could use an #Query like so:
#Query("Select #{#entityName}.nextVal from dual");
Otherwise, since your query is simple and does not involve any object relational mapping, you would probably need to Create a custom repository implementation and inject a JdbcTemplate into it in order to run the query.
Else you could inject an EntityManager and try using the JPA Criteria API - but again you arent actualy trying to map a resultset to an entity so JdbcTemplate will be simpler.

Enum data type in Cassandra

I am trying to migrate my database from MySQL to Cassasndra. The problem I am facing is with one of the column type defined as Enum (enum('GP','NGP','PGP','PAGP')). Cassandra does not support Enum data types (it supports collections though). Is there a way to implement Enum data type in Cassandra, so that the value of a column should be restricted from a set of values? I am using Apache Cassandra version 2.0.7.
See datastax cassandra Object-mapping API,
http://docs.datastax.com/en/developer/java-driver/2.1/java-driver/reference/crudOperations.html
enum Gender { FEMALE, MALE };
// FEMALE will be persisted as 'FEMALE'
#Enumerated(EnumType.STRING)
private Gender gender;
// FEMALE will be persisted as 0, MALE as 1
#Enumerated(EnumType.ORDINAL)
private Gender gender
for cassandra 3.0
enum State {INIT, RUNNING, STOPPING, STOPPED}
cluster.getConfiguration().getCodecRegistry()
.register(new EnumNameCodec<State>(State.class));
// schema: create table name_example(id int PRIMARY KEY, state text)
session.execute("insert into name_example (id, state) values (1, ?)", State.INIT);
// state is saved as 'INIT'
http://docs.datastax.com/en/developer/java-driver/3.1/manual/custom_codecs/extras/
As far I know and after reading the documentation about cql types, you can not use directly enum in cql statements (I check this for the java clients).
So the option you have is convert the Enum to String to include the field in a cql statement. BY this way all your application use the Enum but in the backend layer use the string representation for the enum.
I was facing the same issue with an integer enum... here's what I did:
MappingConfiguration.Global.Define(
new[] {
new Map<Login>()
.TableName("logins")
.PartitionKey(el => el.UserId)
.Column(el => el.UserId, cm => cm.WithName("user_id")),
.Column(el => el.Gender, cm => cm.WithName("gender_id").WithDbType<int>()),
});
Using C# driver 2.5 and DSE 4.7.
there is more or less native support of enums in cassandra
http://docs.datastax.com/en/developer/java-driver/2.1/java-driver/reference/crudOperations.html
As far as I know you can write your own custom serializers etc for cassandra and it will be able to understand your specific enum. But the those jars should be places in cassandra folder.
You can also store it as String or ordinal int value

Hibernate entity with enum foreign key

I'm not sure if the topic name makes sense.
Anyway, the problem is that in my table I have column which stores fk to dictionary table and I want to map it in hibernate in a way that getType will return a value from this dictionary. As an example I have row with type id = 1 which in dictionary corresponds to HIGH, and I have such enum declared in java as ProductType, I want to have method
ProductType getType() which will automatically map values from column type to my enum.
If something's not clear, please let me know.
Thanks in advance!
This is the answer to my question
#Column(name="TYPE_ID")
#Enumerated(EnumType.ORDINAL)
private MyType myType;
Of course my enum looks as follows:
public enum MyType {
HIGH(1),
LOW(2);

Resources