Generate values from db enum for jpa enum at runtime - java

I have seen on the internet ways to map a postgresql enum to a java enum. But all the methods i have seen do not fare well when i modify the enum in the DB. What i would want to do is create the java enum values at runtime by querying the db or something along those line. How would it be best to proceed?
For example in the db i have the enum { 'a','b','c','d'} and i manage to change it in the db one day to {'a','x','d','e'}. Is there any good way to make sure i do not get consistency problems with enum in java.(Obviously manual update IS my last choice). I'm using a pre-9.1 pg db if it matters

If you're updating enum definitions then you shouldn't be using enums. Use a lookup-table with a foreign key reference.
Enums are really for cases where you don't expect the enum to change, and where you're prepared to do significant work when they do change. In this case it would be entirely reasonable to expect to have to update all code that uses the enum if you change the enum's definition.

Related

How to insert all enums into database?

We have a list of ENUMS for different purposes.
Sample Enum:
public enum EJobTrackingType implements Lookup<EJobTrackingType> {
//I want to save all these enums into database
NOTIFY_SERVICE(230000001, 1,"Notify service", "desc"),
COMPLETED_SERVICE(230000002, 2,"Completed service", "desc"),
..... //more than 100 enums like this
}
we use .sql file to save this enums,
INSERT INTO FTTHAPP.TBL_LOOKUP (id, parent_lookup_id, group_id, group_name, code, name, desc) values (230000001, NULL, 23, 'JOB_TRACKING_TYPE', 1, 'NOTIFY_SERVICE', "desc")
Problem:
We need to write values two times (One in enum and another one .sql statement)
It seems not efficient way, Is any other way to save ENUMS to avoid this repetition?
From the above mentioned details what I understood is that we have to insert all the enums present in the java file to database.
The possible answer I think would be to iterate over all the enums and insert each of them to database.
EnumSet.allOf(EJobTrackingType.class)
.forEach(eJob -> ejobRepository.saveAnFlush(eJob));
This is not the actual implementation though but it gives idea how we can proceed.
We can have a class mapping to the values that has to be stored marked as #Entity.
Populate that class with values in Enums with the help of some adapter.
And the entity class can be saved to database.
We can have some attribute to specify an insert or update has to be made. So that we can have some filter during the forEach of Enums.
This job can be ran on the start up of application where a new class which will handle this job can be annotated with #Configuration. If there are too many rows to be updated/inserted there might be a possibility of running this job in a separate thread.
I think this helps.. These are few things I thought of..

JPA boolean discriminator

I want to map in JPA 2.1 (on Hibernate 5.0.2 with MySQL database if that's relevant) a single table to two classes. I know that's done with SINGLE_TABLE inheritance + #DiscriminatorColumn and #DiscriminatorValue.
However, I wanted to discriminate based on a boolean column (well, boolean field in the mapping, I'm not sure how the database handles that). DiscriminatorType only contains 3 values (String, Char, and Integer) none of which seem particularly correct for my requirement. I could, I suppose, change my discriminator column to a more standard type, but I really do only need a boolean distinction and do not care how does the database store that info.
While a good workaround for MySQL 5.5 (which I would imagine looks something like use Char and write "0" and "1" as values, due to how it stores values it'll cast correctly) would be appreciated, I feel like database agnostic solution is in order.

Best way to represent set of string values in DB and UI

I'm looking for opinions so I guess this is a 'which is better' question. I have a webapp build in Javascript/jQuery and struts that uses Hibernate to access data in a relational DB (MySQL). When an object/database field has a limited set of strings for values, is it better to use the full string in the object/DB or a 'code' for that string, like a single CHAR instead of the entire string?
class User {
int id;
String userName;
String type; // Values of 'Administrator', 'Regular'
OR
char type // Values of 'A', 'R'
OR
char type // Values of 'A', 'R'
String typeString; // Can be returned on the fly based on 'type' or by DB in SQL CASE statement
}
If the database has the full text string, then its easy coding all the way around, but its wasting the space (in the DB, data transfer) on something that only has a few values.
If the database has just a 'code' then when presenting this field to a user ( like in a grid of existing users, or a dropdown selection list when creating a new user ) the char value must be converted to the full string. Then the question is where should that conversion be done? It could be at the DB level where Hibernate can fill in the full string value from a CASE statement. This saves DB space, but not in data transfer or memory. It could be at the object level where its done in the getter/setter for the 'type' field. Or it could be all the way in the GUI where Javascript converts the 'char' to the appropriate string for the user to see.
Also... if either method is OK to use, what might influence the choice you make? The number of different values? The max length of the strings? How many rows are expected in the table?
I'm sure every DB/programmer has come across this situation many times and probably has a preference.
If you only have a fixed set of user types like Admin and Regular, I think it will easier to use a static hashmap in your code and just store A and R in your code. Something like:
static HashMap<Character,String> userRoles = new HashMap<>();
static{
userRoles.put("A","Admin");
userRoles.put("R", "Regular");
}
When ever you get result from DB, you can just do userRoles.get(type) to check the actual type. This saves space and also it's readable.
I would put the full name in the database alongside an associated short code or ID in some kind of lookup table. Use the shortcode/ID as the primary key for the lookup table, and as a foreign key from other tables. If someone needs to investigate the database layer, or someone needs to use the database for reporting, data warehousing, or analytics this will simplify things greatly.
It's commonly seen as bad practice to name variables, database tables, database columns, functions, etc. with unclear names or abbreviations that not everyone will understand - short codes like this should be seen the same way.
I think its better to do the conversion from the typecode to type (and vice versa) as close to database interaction as possible - in this case Hibernate. This is because your application logic would become more readable and intuitive if it uses the explicit types.
In my opinion- if(BMW.equals(carTypeCode)) {} is lot more readable than if("X".equals(carTypeCode)) {}.
I am not very familiar with Hibernate, but it would be awesome if you could leverage Hibernate for the mapping of String to DB representation and vice versa (maybe using CASE as you mentioned). Personally, I would probably have modeled these Strings as enums and used something like Hibernate Enum Type mapping. Also, you should think about making these type codes a little bit readable by making them at least few chars because these may come in handy when you are debugging some issue by looking at DB dump and you don't have to consult your type-code to type conversion chart.
I don't think performance wise either would not impact much in the average case.

Hibernate: Avoid using column names as strings

I would like to avoid having column names as strings in the code. Is there any other way to accomplish this?:
String query = "SELECT c.foo1.columnA, c.foo1.foo2.columnB FROM Table c";
session.createQuery(query).list();
I'm able to iterate over a column as string like c.foo1.foo2.columnB by splitting and getting the ClassMetadata, the property Type and other Hibernate functions until I reach the last element. However, I can't think a way to get a column string from Java beans, iterating through properties too.
Not sure what is the intention. Couple of thoughts
If you are worried about possibility of property names being wrong, current day IDEs does a good job by validating the property names in JPA queries
Object reflection can give you the property names. But not necessarily all properties are mapped to columns. You can look at this and use it along with bean property names via reflection.
Hope that helps.
There is no way to achieve what you are looking for. But, if your concern is correctness of these queries and worry that the problem will not be known until the execution hits this, you could use NamedQuery
#Entity
#NamedQuery(
name="findAllEmployeesByFirstName",
queryString="SELECT OBJECT(emp) FROM Employee emp WHERE emp.firstName = 'John'"
)
public class Employee implements Serializable {
...
}
Usage
List employees = em.createNamedQuery("findAllEmployeesByFirstName").getResultList();
The benefit is that queries defined in NamedQuery annotations are compiled to actual SQL at start up time. So incorrect field references(typo etc) will cause a start up error and the application will not start.
Another option will be as mentioned in the other answer to trust in a good IDE to refactor all occurrences properly when you rename fields (Idea does a great job at this, so would any other IDE)
EDIT: I do not think there is any performance degradation with named queries. Rather it may appear to be faster as compiled queries are cached(very subjective)
Finally, its better to use the actual query as-is as mentioned in comments. It is far more readable and debug in its context. If you are concerned about correctness, unit-test the heck out of it and be confident.

Equivalent to NEW operator that uses mutators instead of construtor

JPQL queries can return custom result objects with the NEW operator:
SELECT NEW myPackage.MyVO(e.fieldX, e.relationshipX.fieldY)
FROM MyEntity AS e
This is very useful to feed VOs. The problem is, you have to create constructors that exactly match the number of arguments, order and types of your query projection. This starts to get messy when you use a lot of projections for the same VO... Either you have one big constructor in your VO and resort to a lot of NULL literals on your query, or your VO must have a lot of different constructors.
So my question is: Is there a way in JPQL to set result object fields through mutators instead of constructors?
To people with .NET background, I'm looking to a equivalent of LINQ + object initializers.
DataNucleus JPA certainly supports two ways of instantiating result objects using no non-standard annotations or calls, primarily driven by the fact that it also supports JDO and that has the requirement for it :-
Result type with argumented constructor (as you say)
Result type with default constructor, and with setters
Such as
TypedQuery<MyResultType> q = em.createQuery("SELECT x AS field1, y AS field2 FROM ...", MyResultType.class);
where MyResultType has setters "setField1", "setField2".
Short Answer No you can not use mutators in JPQL.
While I do not know LINQ I can not see this getting done without creating mess .
Now I am sure you know that Classes can have mutlple constructors . So why not create constructors where you will not have too feed in null.
Depending upon what you need and which JPA implementation you are using , most providers do provide non standard ways around it .e.g. Hibernate has #formula which in some cases be used instead to using a constructor.
I you are using JPA2 then criteria queries might be a better choice and can take care of these kind of things.
In somecases you might prefer using #PostLoad .
Either way you need to know this converstion in not happening in SQL so you are not really offloading any work to SQL . Which we generally prefer i.e. make SQL do as much work as possible in single hit.
Yes these are my generalizations and concrete solutions or requirements may not fit.

Categories

Resources