I've a problem with a query that returns multiple value using Spring 3.
I'm using this to retrieve values, but the TemplateFlow objects returned from DB are always null (all field contains null or default value).
List<TemplateFlow> flows = (List<TemplateFlow>) getJdbcTemplate().query(
sqlString,
ParameterizedBeanPropertyRowMapper.newInstance(TemplateFlow.class)
);
TemplateFlow is a class that contains all field. I'm retrieving some values after an update, is it possible I need to commit the changes? (but I'm not using any kind of transaction).
public class TemplateFlow {
private int id_templateflow;
private int id_templateprocess;
public int id_templateflow() { return this.id_templateflow; }
public void id_templateflow(int id_templateflow) { this.id_templateflow = id_templateflow; }
public int id_templateprocess() { return this.id_templateprocess; }
public void id_templateprocess(int id_templateprocess) { this.id_templateprocess = id_templateprocess; }
}
I I try to run the query directly on DB it returns two rows.
thanks for help!
Andrea
Your TemplateFlow class does not conform to the javabean pattern, and ParameterizedBeanPropertyRowMapper requires this to be the case:
Column values are mapped based on matching the column name as obtained from result set metadata to public setters for the corresponding properties.
For example, you should have
int getId_templateflow()
void setId_templateflow(int)
instead of
int id_templateflow()
void id_templateflow(int)
However, I'd advise against using ParameterizedBeanPropertyRowMapper at all - it couples your database too tightly to your code, and that's not a good thing. Consider instead writing your own implementation of RowMapper.
Related
I'm on jOOQ 3.13.1, dropwizard 2.0.7. To make jOOQ and dropwizard together, I am using (https://droptools.bendb.com/jooq/). I am using custom generation strategy to maintain camel case for my setters and getters. The names are coming in as expected.
The record objects have data for their respective columns. However, I keep on getting errors from my database that I am trying to set "null" on a non-null column.
I see this issue only when I am trying to create a new record. Updating records work just fine.
ERROR [2021-03-18 14:58:05,363] com.bendb.dropwizard.jooq.jersey.LoggingDataAccessExceptionMapper: Error handling a request: 9f65c0316d996ebb
! org.postgresql.util.PSQLException: ERROR: null value in column "createdAt" of relation "failures" violates not-null constraint
! Detail: Failing row contains (265, null, Some callback, User account not found, null, null, null).
If I print the record, it looks like this:
+------+------+--------------+--------------------------------------------------+------------------------------+------------------------------+------+
| id|userId|action |error |createdAt |updatedAt |status|
+------+------+--------------+--------------------------------------------------+------------------------------+------------------------------+------+
|{null}|{null}|*Some callback|*User account not found|*2021-03-18 14:58:05,363|*2021-03-18 14:58:05,363|{null}|
+------+------+--------------+--------------------------------------------------+------------------------------+------------------------------+------+
My getter names are:
"getId", "getUserId", "getAction", "getError", "getCreatedAt", "getUpdatedAt", "getStatus".
For columns that are in lowercase, I see no issues. The issue if for places where the column names are in CamelCase.
The class looks something like:
public class FailureDao {
private final DSLContext database;
public FailureDao(DSLContext database) {
this.database = database;
}
public void storeFailure(FailureRecord failure) {
database.newRecord(FAILURES, failure).store();
}
}
For code generation, I am following the documentation here https://www.jooq.org/doc/3.13/manual/code-generation/codegen-generatorstrategy/
My generator class looks something like:
public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
#Override
public String getJavaIdentifier(Definition definition) {
return definition.getOutputName().toUpperCase();
}
#Override
public String getJavaSetterName(Definition definition, Mode mode) {
return "set" + StringUtils.toUC(definition.getOutputName());
}
#Override
public String getJavaGetterName(Definition definition, Mode mode) {
return "get" + StringUtils.toUC(definition.getOutputName());
}
}
I found the issue. Turns out, it was explained on https://groups.google.com/g/jooq-user/c/1iy0EdWe_T8/m/YN9PEsIF4lcJ. My workaround was to use a jOOQ generated POJO. To create a new record, instead of passing an object of Record class, I am now passing an object of the POJO class.
I have crud methods that modify the data in the cache and database
I also have a method that returns all entities when I use it after changes in the cache and database, I get irrelevant data.
As I understand it, the point is in the method of returning all entities. It uses the default key, it is different from other methods.
What do I need to do so that I can return the actual data sheet?
#Service
#CacheConfig(cacheNames = "configuration")
class ServiceConfiguration{
#Cacheable //this method returns non actual data
public List<MySomeConfiguration> getAllProxyConfigurations() {
return repository.getAllConfigurations();
}
#Cacheable(key = "#root.target.getConfigurationById(#id).serverId")
public MySomeConfiguration getConfigurationById(Long id) {
...
return configuration;
}
#CachePut(key = "#configuration.serverId", condition = "#result.id != null")
public MySomeConfiguration addOrUpdateConfiguration(Configuration configuration) {
return configuration;
}
#Cacheable(key = "#serverId")
public MySomeConfiguration getConfigurationByServerId(String serverId) {...
return configuration;
}
#CacheEvict(key = "#root.target.getConfigurationById(#id).serverId")
public void deleteConfigurationById(Long id) {
...
}
}//end class
p.s. sorry for my english
By default redis cache manager uses StringRedisSerializer for Key serializer
Your class toString() is used to serializer the key of the object so don't give different keys for different methods like put, get, evict etc jus rely on your toString() to get the key or override by using Spring Cache Custom KeyGenerator
Refer
https://www.baeldung.com/spring-cache-custom-keygenerator
I have a field in a class that should only be accessed directly from a getter. As an example...
public class CustomerHelper {
private final Integer customerId;
private String customerName_ = null;
public CustomerHelper(Integer customerId) {
this.customerId = customerId;
}
public String getCustomerName() {
if(customerName_ == null){
// Get data from database.
customerName_ = customerDatabase.readCustomerNameFromId(customerId);
// Maybe do some additional post-processing, like casting to all uppercase.
customerName_ = customerName_.toUpperCase();
}
return customerName_;
}
public String getFormattedCustomerInfo() {
return String.format("%s: %s", customerId, getCustomerName());
}
}
So even within the class itself a function like getFormattedCustomerInfo should not be able to access it via customerName_. Is there a way to enforce a class not access a field directly aside from the provided getter function?
There is no such mechanism in Java (or at least I think there should not be). If you are sure that getFormattedCustomerInfo should be prohibited from direct access to customerName_, create another class and compose them.
I would recommend CustomerInfoFormatter.
Also, I would change customerName_ to customerName as the language supports privacy by explicit declaration and it is not needed to add more indicators.
It looks like you are trying to cache the database value, and want to protect against accessing a value which has yet to be cached.
If this is true, then the variable customerName_ should not exist in the CustomerHelper class; the cached value should exist closer to the database.
The method customerDatabase.readCustomerNameFromId(customerId) should first look at a cache, and if the cache is empty, call the database and cache the result.
Effectively, customerName_ becomes a value in the cache: Map<Integer, String> cache where the key is customerId.
In my datamodel a have many entities where attributes are mapped to enumerations like this:
#Enumerated(EnumType.STRING)
private MySpecialEnum enumValue;
MySpecialEnum defines some fixed values. The mapping works fine and if the database holds a NULL-value for a column I get NULL in the enumValue-attribute too.
The problem is, that my backend module (where I have no influence on) uses spaces in CHAR-columns to identify that no value is set. So I get an IllegalArgumentException instead of a NULL-value.
So my question is: Is there a JPA-Event where I can change the value read from the database before mapping to the enum-attribute?
For the write-access there is the #PrePersist where I can change Null-values to spaces. I know there is the #PostLoad-event, but this is handled after mapping.
Btw: I am using OpenJpa shipped within WebSphere Application Server.
You could map the enum-type field as #Transient (it will not be persisted) and map another field directly as String, synchronizing them in #PostLoad:
#Transient
private MyEnum fieldProxy;
private String fieldDB;
#PostLoad
public void postLoad() {
if (" ".equals(fieldDB))
fieldProxy = null;
else
fieldProxy = MyEnum.valueOf(fieldDB);
}
Use get/setFieldProxy() in your Java code.
As for synchronizing the other way, I'd do it in a setter, not in a #PreUpdate, as changes to #Transient fields probably do not mark the entity as modified and the update operation might not be triggered (I'm not sure of this):
public void setFieldProxy(MyEnum value) {
fieldProxy = value;
if (fieldProxy == null)
fieldDB = " ";
else
fieldDB = value.name();
}
OpenJPA offers #Externalizer and #Factory to handle "special" database values.
See this: http://ci.apache.org/projects/openjpa/2.0.x/manual/manual.html#ref_guide_pc_extern_values
You might end up with something like this: not tested...
#Factory("MyClass.mySpecialEnumFactory")
private MySpecialEnum special;
...
public static MySpecialEnum mySpecialEnumFactory(String external) {
if(StringUtils.isBlank(external) return null; // or why not MySpecialEnum.NONE;
return MySpecialEnum.valueOf(external);
}
I am using Hibernate to map with MySQL
I have an entity class in which I have the methods mapped with columns in MySQL
The question is, if its possible that I do not map some of the method in that class with any column in SQL, as if i try not to map one of my method in entity class, it gives exception.
Here is the code snippet , what i am trying
#Column(name="skills")
public String getSkills() {
return skills;
}
public void setSkills(String skills) {
this.skills = skills;
}
#Transient
public int getRowCount() {
return rowCount;
}
public void setRowCount(int count) {
this.rowCount = count;
}
I have used #transiet , but after this if i set some value in setRowCunt and then tries to get that same value with getRowCount it gives null value , anyone have some idea
thanks
You are correct with the #Transient annotation. Perhaps you are setting the rowCount value in one object, than fetch it from db and try to get the value from it? - it would obviously fail because the field is not persisted and you're dealing with new instance of that object.
Perhaps You could provide broader context - what are the steps between setting a value and getting null?