I am using hibernate to save records (i.e. objects) to a database. Before saving my objects, I want to verify if the database already contains this object. (The primary key is just an incremental key and cannot be used for this.)
I am creating a HQL statement at runtime to check the existance of a record with these attributes (i.e. column1-3).
The resulting query should look like:
from myTable where column1 is null and column2 = :column2 and column3 = :column3'
Because sometimes the columns can contain null values, I check the value of the attributes, if it is a NULL value, then I use a is instead of a = in this query (e.g. the column1 is :column1 in the above statement).
Because I start to realize that I am doing a lot of work to achieve something reletively crucial, I am starting to wonder if I'm on the right track. Is there an easier way to check the existance of objects ?
EDIT: I slightly rephrased my question after I realized that also column1 is :column1 does not work when :column1 parameter is set to null. Apparently the only syntax that seems to work as expected is column1 is null. So, it seems like you just cannot use wildcards when searching for null values. But that does not change the main aspect of my question: should I really be checking all this stuff at runtime ?
This is the best way that I found so far.
I prefer to put my filters in a map. The key refers to the property (i.e. map.put("column1", Integer.valueOf(1))).
There is a Restritions.eqOrIsNull method that simplifies the conversion to a Criterion object. The following method converts an entire Map to a List<Criterion>.
public List<Criterion> mapToCriterion(Map<String, Object> params)
{
if (params == null) return null;
// convert the parameter map to a list of criterion
List<Criterion> criterionList = new ArrayList<>(params.size());
for (Map.Entry<String, Object> entry : params.entrySet())
criterionList.add(Restrictions.eqOrIsNull(entry.getKey(), entry.getValue()));
return criterionList;
}
Later on, I use the List<Criterion> to build a Criteria object.
Criteria criteria = session.createCriteria(clazz);
if (criterionList != null)
{
for(Criterion criterion : criterionList)
criteria.add(criterion);
}
// get the full list
#SuppressWarnings("unchecked")
List<T> objectList = criteria.list();
My general impression is still that there are missing several convenience methods here (e.g. Criteria#addAll(List<Criterion>) would have been nice).
Related
There is a table that has map type column, and the map column type would be like below
Map<String, CustomClass.class>
and CustomClass is like below
Class CustomClass {
String name;
String attr;
}
I would like to select record that match 'keyword' contain in map column's values (no matter what key is). I need something like below. Is there any way that I can use?
JooqQuery jooqQuery = (SelectJoinStep<?> step) -> {
step.where(MANAGERS.NAME_DESC_I18N_MAP.contains(
Map<"ANY KEY", keyword in CustomClass.name> // need help here
));
You can use LIKE as a quantified comparison predicate in jOOQ. If it's not supported natively by your RDBMS, jOOQ will emulate it for you. Try this:
MANAGERS.NAME_DESC_I18N_MAP.like(any(
map.values().stream().map(cc -> "%" + cc.name + "%").toArray(String[]::new)
))
You can't use contains() in this way yet, but I guess that's OK.
See also this blog post about using LIKE as a quantified comparison predicate.
I need to copy the records of one table to another table based on some condition.
String query = "insert into public.ticket_booking_archive select * from public.ticket_booking where ticketId in (:ticketIds)";
So here the :ticketIds are dynamic, where i need to pass ticketIds to make sure whether it satisfies the condition. So it may be the matching and non matching ticket id's here at runtime.
The values of ticketIds are something like this
('f1fa3a42-5837-11ec-bf63-0242ac130002','516fd14d-3c9d-4b4b-91a0-b684d8592dfe','c9652f86-734c-4df5-8ef9-d407cb3eaf7a','df7f2812-b445-45b4-b731-da23c36d7738','f1fa3a42-5837-11ec-bf63-0242ac130002'). And this is just an example. And the list might goes on.
Since it is of type UUID, I'm storing it into a Set<UUID>
Set<UUID> tktIds = new HashSet<UUID>();
for(int i=0 ; i<ticketIds.size(); i++) {
String ticketId = ticketIds[i];
tktIds.add(UUID.fromString(ticketId));
}
Map<String, Object> params = new HashMap<>();
params.put("ticketIds", tktIds);
SqlParameterSource namedParameters =
new MapSqlParameterSource().addValue("ticketIds",params.get("ticketIds"));
Since I'm using NamedParameterJdbcTemplate, so I'm using like below
int res = writeNamedJdbcTemplate.update(query, namedParameters);
res = 3 when executed programmatically.
Here the problem is, as soon as it finds the first matching value in the IN clause it executes. And it is not considering the other matching values (ticketIds here)
But if I execute the same query in pgadmin it works fine
insert into public.ticket_booking_archive select * from public.ticket_booking where ticketId in ('f1fa3a42-5837-11ec-bf63-0242ac130002','516fd14d-3c9d-4b4b-91a0-b684d8592dfe','c9652f86-734c-4df5-8ef9-d407cb3eaf7a','df7f2812-b445-45b4-b731-da23c36d7738','f1fa3a42-5837-11ec-bf63-0242ac130002');
result is 6. Working as expected.
writeNamedJdbcTemplate.queryForObject(query, namedParameters, Integer.class); //. throws an error
Can anyone please assist? I'm really not sure where I'm making a mistake
I am not quite sure whether you are using the appropriate JDBC template for the named parameters, but you can do the following:
you can consult this article to use the right template and employ proper SQL query composition,
for string passing you can wrap the parameter mapping as shown here
after all your named parameter should work
I have an big query and my problem is setting NULL values using jooq.
For example, I have this piece of sql query:
IF(t.PANEL_ID IS NULL, t.ID, NULL) AS testId
If transform this into jooq implementation something like this will come out:
when(TEST.PANEL_ID.isNull(), TEST.ID).otherwise(null)).as("testId")
but this is ambiguous method call.
I made some research, and find this snippet:
DSL.val((String) null)
but it didn't work, because it cannot resolve method with jooq.Param<String>.
How should I proceed?
Your NULL expression must be of the same type as your TEST.ID column. I would imagine this is not a String column, but some numeric one. Irrespective of the actual data type, you can always create a bind value using the data type of another expression, e.g.
// Bind variable:
DSL.val(null, TEST.ID)
// Inline value / NULL literal
DSL.inline(null, TEST.ID)
If you're doing this a lot, you could also extract your own utility like this:
public static <T> util(Field<?> nullable, Field<T> other) {
return when(nullable.isNull(), other).otherwise(inline(null, other));
}
Notice, jOOQ has a built-in method NVL2 for this purpose:
nvl2(TEST.PANEL_ID, inline(null, TEST.ID), TEST.ID).as("testId")
Probably the only way to do this is to keep a list of static final Strings but if anyone has any idea it is welcome.
I have a POJO and a database table. The columns(properties) are the same as the class members of the POJO. I want to avoid (it is a fairly big program) to write getColumn("username") but instead write something like getColumn(UserPOJO.getUsername().getActualMemberNameInAString())
The only way I can think of is to have a UserPOJO class with just static variables and update it when I add members in the class. The second option is to have all the properties as enums but that is bad I think in a number of levels.
What I would like to have is a way to get the member name that corresponds to the getter method. Some kind of reflection?
Problem to be solved is typos in a huge codebase. I overemphasize here because I have received comments and answers that are not what I am asking for.
Note that I am not using any framework or ORM tool. I am using a Graph database that maps all columns to a Vertex and then you need to do .getProperty(string s) to get an Object. And I do this many times in the code
My understanding of this question is you want minimum code change when your underlaying Database Table get changed.
so let me put it as , say I have a table Info as
CREATE TABLE Info (
field1 INTEGER ,
field2 VARCHAR(1)
);
and I am expecting field3 could be added in future then I need a solution where
I do not need to add extra code for getting information for field3.
Please confirm if the understanding is correct ? if yes then you can use below strategy
/**
* generic Method for executing Any RAW SQL Query.
* for e.g. sql = "select * from Info";
*/
public List<Map<String,String>> executeQuery(String sql) throws Exception {
logger.info("executing SQL = "+sql);
List<Map<String,String>> resultList = new ArrayList<Map<String, String>>();
Statement statement=null;
ResultSet resultSet=null;
ResultSetMetaData metaData = null;
try{
statement = connection.createStatement();
resultSet = statement.executeQuery(sql);
metaData = resultSet.getMetaData();
int noOfColumns = metaData.getColumnCount();
while(resultSet.next()){
Map<String,String> row = new HashMap<String, String>();
for(int i =1;i<=noOfColumns;i++){
row.put(metaData.getColumnName(i), resultSet.getString(metaData.getColumnName(i)));
}
resultList.add(row);
}
} catch (SQLException e) {
throw new Exception(" Exception while executing query on database. Reason "+e.getMessage());
}
finally {
closeResources(statement, resultSet);
}
return resultList;
}
for input String sql = "select * from Info"; Here you will get all records of Info Table with key-value pair where key suggests columnName and value suggests value of that column.
And this is as good as dynamic ,even if we add extra columns we will get that information in our Map also it does not require to use any framework
You have multiple options:
If you only need the name once, I wouldn't bother to create constants for them.
In one of your comments you stated you will use it a lot and in different places, you could create a class that stores all those strings as constants. At least you will avoid typos, and your code wont be littered with strings.
You could use reflection but that would overcomplicate things (in my opinion).
I wouldn't exclude using enums as an option. This SO answer explains it better, then I could do...
I'm working with Java Apache Cayenne, under a MySQL DB.
I have quite a large table with a single bigint PK and some fields.
I'd like to retrieve just only the PK values and not all the object that maps this entity, as it would be too resource-consuming.
Is there a snippet that I can use, instead of this one that retrieves all the objects?
ObjectContext context = ...
SelectQuery select = new SelectQuery(MyClass.class);
List<MyClass> result = context.performQuery(select);
You should try using SQLTemplate instead of SelectQuery.
Here's a quick example:
ObjectContext context = ...
SQLTemplate select = new SQLTemplate(MyClass.class, "SELECT #result('PK_COLUMN' 'long') FROM MY_TABLE");
List result = context.performQuery(select);
You can find more information here
+1 for Josemando's answer. And here is another way that may work in case you are planning to only work with a subset of fetched objects:
ObjectContext context = ...
SelectQuery select = new SelectQuery(MyClass.class);
select.setPageSize(100);
List<MyClass> result = context.performQuery(select);
'setPageSize' ensures that 'result' only contains ids, until you attempt to read an object from the list. And when you do, it will resolve it page-by-page (100 objects at a time in the example above). This may fit a number of scenarios. Of course if you iterate through the entire list, eventually all objects will be fully resolved, and there will be no memory benefit.