Hibernate - AttributeConverter and custom SQL function - java

I'm trying to map EnumSet into a single value as integer via Hibernate.
I have implemented AttributeConverter:
public class RolesToIntConverter implements AttributeConverter<Set<Roles>, Integer> {
#Override
public Integer convertToDatabaseColumn(Set<Roles> attribute) {
return Roles.encode(attribute);
}
#Override
public Set<Roles> convertToEntityAttribute(Integer dbData) {
return Roles.decode(dbData);
}
}
As well as new SqlDialect:
public class LocalSqlDialect extends MySQL5Dialect {
public LocalSqlDialect() {
super();
registerFunction("bitwise_and", new SQLFunctionTemplate(IntegerType.INSTANCE, "(?1 & ?2)"));
}
}
Then I call it like this:
public Collection<PersonsEntity> getAll(Roles roles) {
Query q = getEntityManager().createQuery("SELECT s FROM PersonsEntity AS s WHERE ( bitwise_and(s.roles,:roles) <> 0 )");
q.setParameter("roles", EnumSet.of(roles));
List<PersonsEntity> result = (List<PersonsEntity>) q.getResultList();
return result;
}
This causes several issues:
ClassCastException, because for some reason, it passes set to the AttributeConverter per each element
I tried changing type from Set<Roles> to Object (at the converter), and then using instanceof I checked whether it is a single object or a set and parsed accordingly. After that I found out, that while calling s.roles = :roles worked fine, calling the registered bitwise function did not even call the AttributeConverter
ResultSet exception, because after calling bitwise function and using as input Set with two values, it actually puts ?, ? into the query instead of calling AttributeParser, which should merge it into a single number
The question is, what em I doing wrong? Or do you know a better solution to a problem: map EnumSet into a single database column, while being able to assign multiple roles to one entity.
For example I have value 1 for user, value 2 for manager, value 4 for admin, etc.. I want a particular person to be a user and a manager at the same time, which would mean value 3 (1 | 2) and then I want to find him when searching for user only (resp. manager only) via number 1 (resp. 2) - which suggests bitwise and.
Thank you in advance for any response!

Related

Riak 2i - Update deletes secondary indexes

I am using oficial Riak Java client v2.0.2. When I update previously written value (with 2i indexes), the secondary indexes are not preserved.
This is how I do update:
Location location = new Location(this.namespace, key);
UpdateValue updateOp = new UpdateValue.Builder(location)
.withFetchOption(FetchValue.Option.DELETED_VCLOCK, true)
.withUpdate(new RiakKVUpdateValue(values))
.build();
And this is my update class:
public class RiakKVUpdateValue extends Update<Map<String, String>> {
private final Map<String, String> value;
public RiakKVUpdateValue(HashMap<String, ByteIterator> values) {
this.value = StringByteIterator.getStringMap(values);
}
#Override
public Map<String, String> apply(Map<String, String> original) {
return this.value;
}
}
I haven't found anything in the docs about updating objects with 2i indexes.
Am I doing someting wrong?
Should I do manual Read/Modify/Write?
You have to fetch the index and write it back every time you update the value. See 2i Indexing an Object.
I would suggest to create a field to hold the index and annotate it with #RiakIndex. A field annotated with this annotation is populated with 2i values automatically by the Java client when fetched. Then, copy its value in RiakKVUpdateValue.apply() to retain it. Alternatively, fetch and then write back in two separate commands as you already mentioned. This will allow you to control metadata you want to write back. Don't forget to populate the VClocks.
P.S. Retaining 2i automatically can be a bad idea since it's not obvious that a user will want to keep old 2i values. I believe that's why it is left up to the user to decide.

How can I know a where-clause query results contains another where-clause query results?

How can I know a where-clause's query-results contains another where-clause's query-results?
For example:
"id>0" contains "id>1"
"id>0 or name='China'" contains "id>1"
"id>0 or name='China'" contains "name='China'"
Sorry,My English proficiency is very bad.
There is a table: Countries(id,name).
id name
0 America
1 China
2 Japan
3 England
Obviously,The query-results of select id, name from Countries where id>0 contains select id, name from Countries id>2's.
I want to get the result by comparing the two where-clauses directly, I don't want to execute the actual query operation
I use java.
It depends on your data, so you have to run each where clauses by joining their results. You can join them and check if any result exists.
You can use set operators to compare the two. If query2 does not have any rows that aren't in query1, than query1 contains query2.
E.g., for Oracle:
SELECT *
FROM my_table
WHERE condtion2
MINUS
SELECT *
FROM my_table
WHERE condtion1
For MS SQL Server and PostgreSQL, use EXCEPT instead of MINUS.
Well, first of all, you'd need a way to represent your condition other than just text. Without fleshing out all of the classes, below should get the gist of it.
public abstract class Condition implements Comparable<C extends Condition> {
public abstract boolean equals(C other);
public abstract boolean contains(C other);
};
public class OrCondition extends Condition {
// contains a list of the conditions it's OR-ring together
public boolean contains(Condition other) {
// true if the list of conditions
// contains a condition c such that c.equals(other)
}
}
public class GreaterThanCondition extends Condition {
// contains a fieldname and a number to compare it to
public boolean contains(Condition other) {
// true if other is a GreaterThanCondition as well
// on the same field and the number other.number >= this.number
}
}
And so on. Comparing strings and coming up with other conditions is left as an exercise to the OP (or the reader, if the reader is inclined to do so).
Of course, this works up to a point. As soon as you want to answer questions that depend on the data, you have no choice but to execute some query. For instance, there is easier way to find out that WHERE id > 1 contains WHERE name > 'China' than issueing the queries.

Objectify app engine - querying embedded entities using a list of values

I am using objectify-appengine framework for querying. Here is my simplified problem: Consider these 2 classes:-
public class Customer {
#Id private String email;
#Embedded private Account Account = new Account(); // note embedded annotation
}
and
public class Account {
private String number; //example: 1234
}
The following query works & gives me 1 customer:
Objectify ofy = ObjectifyService.begin();
ofy.query(Customer.class).filter("account.number = ", "1234");
Question:
However, if have a List of values (account numbers). Is there a way to fetch them in 1 query? I tried passing a list of account numbers like this:
ofy.query(Customer.class).filter("account.number = ", myAccountNumberList);
But if fails saying:
java.lang.IllegalArgumentException: A collection of values is not allowed.
Thoughts?
filter("account.number IN", theList)
Note that IN just causes the GAE SDK to issue multiple queries for you, merging the results:
The IN operator also performs multiple queries, one for each item in the specified list, with all other filters the same and the IN filter replaced with an EQUAL filter. The results are merged, in the order of the items in the list. If a query has more than one IN filter, it is performed as multiple queries, one for each possible combination of values in the IN lists.
From https://developers.google.com/appengine/docs/java/datastore/queries

Getting Callback after all setters called to add extra fields?

I'd like to override a setter so that I can perform some function on the data so I can return a calculated column for my entity. The function depends a several columns (e.g. COL1, COL2, ...) so I can't really intercept any particular setter because the other values might not yet be populated. Does hibernate provide some sort of "finish()" method that can be called once at the values are set for the Entity?
#Override
#Column(name="COL1")
public String getCol1() {
return this.col1;
}
#Override
public void setCol1(String value) {
super.setCol1(value);
genMagicValue();
}
public String getMagicValue() {
return this.magicValue();
}
I don't understand your question,
setCol1 may be never called (and left with its default value).
Furthermore, no one is preventing you to call it twice with different values.
perhaps the pattern you are looking for is:
boolean magicDone=false;
public String getMagicValue() {
if (!magicDone){
magicDone=true;
genMagicValue();
}
return this.magicValue();
}
Aside from what hibernate provides, is it not possible to lazy init the magicValue so that the calculation happens the first time getMagicValue is called and subsequent calls to getMagicValue just return the computed value?

JPA 2.0 persisting property with no setter

I'm using JPA 2.0, more precisely Eclipselink. Here's my problem:
I have an entity that has a property like "isPaid". that property is the result of some calculations the entity performs with some of its other fields. since this is derived from other fields, the property does not have a setter method.
As an example, the getter is something like this:
public boolean isPaid() {
return this.totalAmount - this.amountPaid == 0;
}
that's just an example. The thing is, I want this property to be calculated and persisted, so i can do a jpql query like:
SELECT d FROM Debt d WHERE d.isPaid = true
Is this possible? Is there any workaround for this?.
I don't want to retrieve all entities to call this method and then filter those that return true.
Here are a couple of options:
1) Create a jpql query that directly does what you need:
select d from Debt d where (d.totalAmount - d.amountPaid) = 0
The benefits of the approach is that it is simple and will always work. The downside is that your query has to understand how the paid logic was calculated.
2) Create a persisted paid value that stores the calculated value:
#Basic
private boolean paid;
public boolean isPaid() {
return this.paid;
}
private void updateCalculations() {
this.paid = (this.totalAmount - this.amountPaid == 0);
}
// using int as example here
public void setTotalAmount(int totalAmount) {
this.totalAmount = totalAmount;
updateCalculations();
}
public void setAmountPaid(int amountPaid) {
this.amountPaid = amountPaid;
updateCalculations();
}
The benefit of this approach is that you will be able to create a jpql query that directly checks for the boolean value, i.e.,
select d from Debt d where d.paid = true;
Obviously, the downside to the approach is that you need to make sure to recalculate the value anytime you update the values. However, this can be alleviated if you only calculate it on access. Meaning that in your isPaid() method, you calculate the value, assign it to the paid attribute and then return the value. If you decide to go with this approach, you will need to add a #PrePersist and #PreUpdate method that performs the paid calculation and updates the paid attribute prior to the bean being persisted to the datastore (makes sure that the paid value is always covered.
If you use JPA annotations on your attributes themselves, you can have a getter without a setter and still be able to correctly retrieve and store the values in the database.
Seen this: Mapping calculated properties with JPA ?
Basically you need a setter one way or the other in order to make JPA happy.

Categories

Resources