Usage of Native SQL functions in ORMlite anotations - java

I am interesting in ORMlite usage in android application. But there is one problem.
The first step is to annotate your class, but I need something like this:
#DatabaseField(columnName = "geometry", useGetSet = true)
String JSONgeometry;
#Formula (nativeSQL = "ShapeFromJSONText(JSONgeometry)")
public void set(String JSONgeometry){
this.JSONgeometry = JSONgeometry;
}
#Formula (nativeSQL = "asJSONtext(geometry)")
public String get(){
return JSONgeometry;
}
Is there any way to insert native SQl functions in annotations? Is there any way to use BasePersister for solving this tasks?

Could you be more specific what functions ShapeFromJSONText and asJSONtext exactly do?
I feel from your approach that you want to save object in geometry field.
Create separate class in your model:
class Geometry {
#DatabaseField(generatedId = true)
int id;
#DatabaseField
float field1;
#DatabaseField
float field2;
}
In your parrent class refer to it like this:
class Shape {
#DatabaseField(foreign = true)
Geometry geometry;
}
Of course if you dont want to save object but just its JSON represenatation you can save it to the String field.
In case you want to use your SQL functions to change the saved object somehow you can do it in getter and setter too in Java.

Related

Unable to properly compare table columns with different types

I'm trying to use querydsl to build a query which joins two tables. However, a slight discrepancy between the corresponding Java class data types seems to prevent me from directly comparing the two columns values in my query. The data type within the object corresponding to table A is java.util.UUID while the data type of the object corresponding to table B is String.
I have something like the following:
#Table(name = "TABLE_A")
public class TableA {
#Column(name = "uuid")
#Type(type = "uuid-char")
private UUID uuid;
}
#Table(name = "TABLE_B")
public class TableB {
#Column(name = "uuid")
private String uuid;
}
#Service
public class QueryService {
private final JPQLQueryFactory queryFactory;
public UUID getData(UUID input) {
return queryFactory.select(QTableA.tableA.uuid)
.from(QTableA.tableA)
.innerJoin(QTableB.tableB)
.on(QTableB.tableB.uuid.eq(QTableA.tableA.uuid.toString()))
.where(QTableA.tableA.uuid.eq(input))
.fetchOne();
}
}
The above code does not return anything. However, the below code seems to work:
#Service
public class QueryService {
private final JPQLQueryFactory queryFactory;
public UUID getData(UUID input) {
return queryFactory.select(QTableA.tableA.uuid)
.from(QTableA.tableA)
.innerJoin(QTableB.tableB)
.on(QTableA.tableA.uuid.eq(input)
.and(QTableB.tableB.uuid.eq(input.toString()))
.where(QTableA.tableA.uuid.eq(input))
.fetchOne();
}
}
I don't understand why directly comparing the columns doesn't work, but comparing them to a common variable does work. Would QTableA.tableA.uuid.toString() not call the proper toString() method?
Please try:
.on(QTableB.tableB.uuid.toString().eq(QTableA.tableA.uuid.toString()))
Apply toString on QTableB.tableB.uuid
It's looking like a direct comparison is not possible with the current version. Querydsl's type checking is too strict for a direct comparison to be done on these kinds of differing data types.

Spring Data JPA select sequence for different bases, and set value to entity

I need implement next logic:
I have entity:
#Data
#Entity
#Table(name = "USERS")
public class User {
#Id
#Column(name = "GUID")
private String guid;
#Column(name = "MESSAGE_ID")
private String messageId;
#Column(name = "SOME_VALUE")
private String someValue;
And I need set to someValue generated value consisting of
"some prefix"+sequencefrom DB + "some suffix";
I can make select sequense from Db, generate vsomeValue and set it to entity, but maby Is there a way to make it easier? Because in my version I use two bases, and I have to write two native query for select a sequence and use the appropriate one depending on the profile.
I need somthig like this:
#Column(name = "SOME_VALUE")
#Value(MyGenerator.class)
private String someValue;
and in MyGenerator.class implement logic for generate someValue from prefix, sequence and suffix.
Instead of annotating the class members, annotate the getters and setters, and put your logic there.
Further reference in this question.
You are looking for Custom Sequence based ID generator.
This is a nice article on it which might help you.

Query using value from nested interface as parameter

I have been reading a lot about using enums as parameters in queries. I have some queries in my project that use the value from these enums as parameters.
For example:
public enum YesNo {
Y, N
}
Query:
select ent
from
Entity ent
where
ent.id = :id
and ent.deleted = project.path.example.YesNo.N
Entity:
#Entity
public class Entity{
Long id;
#Enumerated(EnumType.STRING)
YesNo deleted;
}
The above works correctly as expected.
However, when I have the following:
interface Commons{
interface MostCommonTypesofAnimals {
long DOG = 1L;
long CAT = 2L;
}
}
Query
select a
from
Animal a
where
a.id = :id
and a.type = project.path.example.Commons.MostCommonTypesofAnimals.DOG
Entity
#Entity
public class Animal{
Long id;
Type type;
}
#Entity
public class Type{
public Long id;
}
It does not work telling me that the path is incorrect even though it is actually correct.
Is there any work around? Or interface values cannot be mapped? Can anyone provide me an example that works? I could not find anything similar.
Please note that this is just an example to illustrate the situation., those are not the real names that I am using or anything.
For using enum while using hibernate / jpa (based on your tags), you should use annotation in your Pojo class.
#Enumerated(EnumType.ORDINAL)
In your example, something like:
#Entity
#Table(name = "tableName")
public class entityName {
#Enumerated(EnumType.ORDINAL)
private YesNo yesNoEnum;
}
The annotation can go here or in the getter, as you prefer.
You can find more info here
ps: for yes or no I suggest you using a boolean value, not an enum

How to return an entity by property if it already exists?

#Entity
public class Language {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(length = 2)
private String code; //EN, DE, US
public Language(String code) {
this.code = code;
}
}
#Entity
public class ProductText {
#OneToOne(Cascade.ALL)
private Language lang;
}
ProductText text = new ProductText();
text.setLang(new Language("en")); //what if "en" exists?
dao.save(text);
Now, when I persist the ProductText, everytime a new Language object would be generated.
Can I prevent this, and in case a language table entry with code = 'en' exists this existing entity should be linked instead.
My initial goal is to not having to repeat the countryCodeString "EN" multiple times in my product-text table, but just reference the id. But does this really make sense? Should I rather just use the plain String without an extra table? (I later want to query a list of productTexts where lang = 'de').
Is the only change executing a select like dao.findByLang("en") before?
Or is there also some hibernate feature that would support this without explicit executing a query myself?
Do you process the value "en" further or do you display it directly? If only used for displaying purposes, I would just store the string, but if you want to reduce redundancy by using foreign key IDs you have to create an Entity containing the language string en which can be persisted via entity manager and which you have to obtain out of the entity manager before persisting to reuse it.
If there is only three different possible values for the language, you can also use an enum like thisĀ :
public enum Language {
EN("EN"),
DE("DE"),
US("US");
private String code; //EN, DE, US
public Language(String code) {
this.code = code;
}
// Getter...
}
#Entity
public class ProductText {
#Enumerated(EnumType.STRING)
// Or #Enumerated(EnumType.ORDINAL)
private Language lang;
}
EnumType.STRING will store the enum in the database as a String, while EnumType.ORDINAL will store it as an int. Int is maybe a little more efficient, but the mapping could change if you insert a new value in your enum. String is more flexible since it will use the names of your enum members.
In both case, you don't have to manage a separate entity and hibernate will not create an additional table, and it's more type-safe than using a plain string.
If the only value in Language is a 2 or 3 letter string, why not just have the string as a member? This will be quicker and more efficient.

Storing Objects in columns using Hibernate JPA

Is it possible to store something like the following using only one table? Right now, what hibernate will do is create two tables, one for Families and one for people. I would like for the familymembers object to be serialized into the column in the database.
#Entity(name = "family")
class Family{
private final List<Person> familyMembers;
}
class Person{
String firstName, lastName;
int age;
}
This is an horrible design and I'm really not recommending it (you should just create another table) but it is possible.
First, you'll need to use a byte[] attribute to hold a serialized version of the list of persons that will be stored in a BLOB in the database. So annotate it's getter with #Lob (I would make the getter and setter private to not expose them). Then, expose "fake" getter and setter to return or set a List<Person> from the byte[]. I'm using SerializationUtils from Commons Lang in the sample below (provide you own helper class if you don't want to import this library) to serialize/deserialize on the fly to/from the byte[]. Don't forget to mark the "fake" getter with #Transcient or Hibernate will try to create a field (and fail because it won't be able to determine the type for a List).
#Entity(name = "family")
class Family implements Serializable {
// ...
private byte[] familyMembersAsByteArray;
public Family() {}
#Lob
#Column(name = "members", length = Integer.MAX_VALUE - 1)
private byte[] getFamilyMembersAsByteArray() { // not exposed
return familyMembersAsByteArray;
}
private void setFamilyMembersAsByteArray((byte[] familyMembersAsByteArray() { // not exposed
this.familyMembersAsByteArray = familyMembersAsByteArray;
}
#Transient
public List<Person> getFamilyMembers() {
return (List<Person>) SerializationUtils.deserialize(familyMembersAsByteArray);
}
public void setParticipants(List familyMembers) {
this.familyMembersAsByteArray = SerializationUtils.serialize((Serializable) familyMembers);
}
}
Don't forget to make the Person class Serializable and to add a real serialVersionUID (I'm just showing a default here):
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
// ...
private String firstName, lastName;
private int age;
}
But, let me insist, this is an horrible design and it will be very fragile (changing Person might require to "migrate" the content of the BLOB to avoid deserialization issues and this will become painful. You should really reconsider this idea and use another table for the Person instead (or I don't get why you use a database).
#Type(type = "serializable")
private List<Person> familyMembers;
if you can't use hibernate annotations try this:
#Lob
private Serializable familyMembers;
public List<Person> getFamilyMembers(){
return (List) familyMembers;
}
public void setFamilyMembers(List<Person> family){
familyMembers = family;
}
Annotate the property with #Column and define the type to be ArrayList, not just List. And make Person implement Serializable.
But you should do this only if your motives are very clear, because this is the correct solution in some very rare cases. As Pascal noted, if you ever have to change Person you'll have headaches.
You can create pseudoproperty (getter and setter) which accepts/returns the serialized form, and annotate the familyMembers with #Transient. This would also need to annotate the getters, not fields, for all other properties.

Categories