I have several entities that have transient properties that I would like to populate from the sql query. I have tried several things but have not found the correct combination yet.
here is an example entity
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
long id;
#Size(max=1000)
String image_url;
#Transient
boolean liked;
#Transient
long numLikes;
**getters and setters** for persistent properties
public boolean isLiked() {
return liked;
}
public void setLiked(boolean liked) {
this.liked = liked;
}
public long getNumLikes() {
return numLikes;
}
public void setNumLikes(long numLikes) {
this.numLikes = numLikes;
}
I have tried using the #Basic anotation and setting it's fetch method to eager
#Basic(fetch = FetchType.EAGER)
on the getters but that didn't seem to do anything. I've seen it set to lazy as well.
Am I missing anything in here that would cause a column name not be mapped to one of these transient properties?
here is my impl code.
SQLQuery query = getCurrentSession().createSQLQuery("" +
"SELECT * ,count(likes1.liked) as numLikes " +
"FROM aboutme " +
"left JOIN " +
"(" +
" select liked, likedObject_id " +
" from likes " +
" where liked = 1" +
") as likes1 ON aboutme.id = likes1.likedObject_id " +
"left join " +
"(" +
" select likedObject_id, liked " +
" from likes " +
" where liked = 1 and profile_id = :id" +
") as likes2 on likes2.likedObject_id = aboutme.id " +
"WHERE aboutme.profile_id = :id " +
"group by aboutme.id");
query.addEntity(AboutMe.class);
query.setParameter("id",id);
return query.list();
I've tried using the
SQLQuery query = ..."Select count(value that returns properly) as {object.numLikes}..."
query.addEntity("object",Object.class),
I get an error here that says it can't find the column name for property [property] for alias [alias]
What am I doing wrong?
Transient properties are probably not the way to go for what I am trying to do. what I need to figure out is how to map these derived columns to an object that I can return to the front end. how do I set up an object that hibernate can map these aliased columns to properties?
I figured it out. You can set the transient property though it's kind of a pain.
using the addScalar Method on the SQLQuery object you can set the transient properties. However if it is done this way you have to set ALL the properties in the object this way (Hibernate doesn't autofill any properties)
Also you will have to use the setResultTransformer Method also on the SQLQuery object. So to finish off my previous example I would have to add the following code in my impl.
// query.addEntity(AboutMe.class); <- this contradicts the setResultTransformer
query.setParameter("id",id);
query.addScalar("id",StandardBasicTypes.LONG);
query.addScalar("image_url",StandardBasicTypes.LONG);
query.addScalar("liked",StandardBasicTypes.LONG);
query.addScalar("numLikes",StandardBasicTypes.LONG);
query.setResultTransformer(Transformers.aliasToBean(Object.class));
where Object is the class that I am wanting to use that has all these properties declared.
Hibernate will never populate your transient fields and what is most important transient fields are not even part of the java serialization process. What I would try if you really need this - is the ResultTransformer.alliasToBean which is "injecting" the values into the class with reflection.
setResultTransformer(Transformers.aliasToBean(Yourclass.class));
Just a quick idea, not sure whether it will work.
Related
What I am trying is to read data on a query, and write to a column called endoso , which is a property, so that it can be persisted by the database, since this property is calculated and I want it to be displayed in the database.
But it is failing me when running my program. Anyone know what might be happening?
#ManyToOne
#JoinColumn(name = "remesa_id", nullable = false)
#JsonBackReference
private Remesa remesa;
private Long endoso;
#ColumnTransformer(read = "(select count(*)"
+ " from Documento"
+ " inner join Remesa"
+ " on Remesa.id = Documento.remesa.id"
+ " inner join EnvioRemesa"
+ " on Remesa.id = EnvioRemesa.remesa.id"
+ " where Remesa.id=remesa.id)" //remesa.id is the id of the property remesa
, write = "endoso = ?" )
private Long writeEndosoInDataBase;
I do not know if I am using the ideal nomenclature to be able to what I comment
JdbcTemplate is returning an empty list when executing the "query" method.
public List<Loan> getLoanDAO(Employee employee, String s) {
final String SQL = "SELECT CTLPCODCIA, CTLPCODSUC, CTLPCODTRA, EMPNOMBRE, EMPAPATERN, EMPAMATERN, CTLPCODPRE, "
+ "CTLPTIPPRE, TIPDESPRE, CTLPMONEDA, CTLPESTADO, CTLPMONTOP, CTLPNROCUO, CTLPCUOTA, FLAGTIPOCUOTA, CTLGLOSA, CTLDIASFR, "
+ "CTLDOCADJ, CTLUSUCREA, CTLFECCREA "
+ "FROM HR_CTLPREC_SS INNER JOIN HR_EMPLEADO ON CTLPCODCIA=EMPCODCIA AND CTLPCODSUC=EMPCODSUC AND CTLPCODTRA=EMPCODTRA "
+ "INNER JOIN HR_TIPPRE ON CTLPCODCIA=TIPCODCIA AND CTLPCODSUC=TIPCODSUC AND CTLPTIPPRE=TIPCODPRE "
+ "WHERE TIPFLGEST = '1' AND TIPSELFSERVICE = '1' "
+ "AND CTLPCODCIA = ? AND CTLPCODSUC = ? AND EMPCODTRAJEF = ? AND CTLPESTADO = ? ";
List<Loan> loans = jdbcTemplate.query(SQL, new Object[] {
employee.getCTLPCODCIA(), employee.getCTLPCODSUC(), employee.getCTLPCODTRA(), s }, loanMapper);
return loans;
}
However, when replacing the "?" with the same parameters used in execution and executing in sqldeveloper, it returns 4 rows. I don't know what is wrong since I've been doing de data access code in the same way for all the other entities.
Problem solved
As stated by #Julian:
JdbcTemplate is a proved spring component used by a huge number of applications so in my opinion it must be a bug in your code.
It was not a problem from JdbcTemplate, neither my code. It was an issue from the IDE. I just build my project from scratch using maven console commands and the code worked as intended.
Thanks folks.
JdbcTemplate is a proved spring component used by a huge number of applications so in my opinion it must be a bug in your code.
Not sure what version of Spring you are using but jdbcTemplate.query would expect a Loan Mapper class as one of its arguments. There is no such a mapper present in your code.
I suggest you put a breakpoint just before the query and inspect the employee fields and see if they match the values you are playing in the sqldeveloper.
One other thing that it attracts my attention is the third one where u have EMPCODTRAJEF = ? in the query definition but you use employee.getCTLPCODTRA() as the argument. Obviously I don't know your data model but should it rather be employee.getEMPCODTRAJEF() or the other way around?
If this won't work double check your arguments.
final String SQL = "SELECT CTLPCODCIA, CTLPCODSUC, CTLPCODTRA, EMPNOMBRE, EMPAPATERN, EMPAMATERN, CTLPCODPRE, "
+ "CTLPTIPPRE, TIPDESPRE, CTLPMONEDA, CTLPESTADO, CTLPMONTOP, CTLPNROCUO, CTLPCUOTA, FLAGTIPOCUOTA, CTLGLOSA, CTLDIASFR, "
+ "CTLDOCADJ, CTLUSUCREA, CTLFECCREA "
+ "FROM HR_CTLPREC_SS INNER JOIN HR_EMPLEADO ON CTLPCODCIA=EMPCODCIA AND CTLPCODSUC=EMPCODSUC AND CTLPCODTRA=EMPCODTRA "
+ "INNER JOIN HR_TIPPRE ON CTLPCODCIA=TIPCODCIA AND CTLPCODSUC=TIPCODSUC AND CTLPTIPPRE=TIPCODPRE "
+ "WHERE CTLPCODCIA=? AND CTLPCODSUC = ? AND EMPCODTRAJEF = ? AND CTLPESTADO = ? "
+ "AND TIPFLGEST='1' AND TIPSELFSERVICE='1'";
Add this to application.properties to debug your query.
logging.level.org.springframework.jdbc.core = TRACE
I want to insert a list of Objects in my db. In a special case I know that they primary key (not auto-generated) is not already there. Since I need to insert a big collection, the save(Iterable<Obj> objects) is to slow.
Therefore I consider using a native query. native insert query in hibernate + spring data
In the previous answer, it does not say how to insert a collection of objects. Is this possible?
#Query("insert into my_table (date, feature1, feature2, quantity) VALUES <I do not know what to add here>", nativeQuery = true)
void insert(List<Obj> objs);
Of course if you have a better solution overall, Its even better.
I ended up implementing my own repository. The performance of this is really good, 2s instead of 35s before to insert 50000 elements. The problem with this code is that it does not prevent sql injections.
I also tryed to build a query using setParameter(1, ...) but somehow JPA takes a long time to do that.
class ObjectRepositoryImpl implements DemandGroupSalesOfDayCustomRepository {
private static final int INSERT_BATCH_SIZE = 50000;
#Autowired
private EntityManager entityManager;
#Override
public void blindInsert(List<SomeObject> objects) {
partition(objects, INSERT_BATCH_SIZE).forEach(this::insertAll);
}
private void insertAll(List<SomeObject> objects) {
String values = objects.stream().map(this::renderSqlForObj).collect(joining(","));
String insertSQL = "INSERT INTO mytable (date, feature1, feature2, quantity) VALUES ";
entityManager.createNativeQuery(insertSQL + values).executeUpdate();
entityManager.flush();
entityManager.clear();
}
private String renderSqlForObj(Object obj) {
return "('" + obj.getDate() + "','" +
obj.getFeature1() + "','" +
obj.getFeature2() + "'," +
obj.getQuantity() + ")";
}
}
I am getting this exception from fetching record through database based on column portfolio
Query:
String queryString= "select entity from " +Name + " entity WHERE entity."+Column+" = "+ searchId.toString();
Query query = _em.createQuery(queryString);
Many things are wrong here and a lot of important information is missing (entity code?).
className in your example should be just Portfolio instead of class com.hexgen.orm.Portfolio (assuming Portfolio is entity's name, which doesn't have to be the same as class name). If you are using someEntity.getClass().getName() to get it, change to someEntity.getClass().getSimpleName()
searchColumn should be the field name of Portfolio class, not column name in the database. Asssuming PORTFOLIO column is mapped to portfolio field, it should be portfolio.
String queryString = "select entity from " + simpleClassName + " entity WHERE entity." + searchColumn + " = :searchId";
Query query = _em.createQuery(queryString);
query.setParameter("searchId", searchId.toString());
If you don't switch to using query parameters, searchId.toString() should be enclosed in single quotes.
So, the valid query should look something like this
select entity from Portfolio entity WHERE entity.portfolio = 'HEXAGON20'
You have several problems in your query syntax and if you look at the message it's quite explicit:
You build your query with
"select entity from " +className + " entity WHERE entity."+searchColumn+" = "+ searchId.toString();
Which gives
select entity from class com.hexgen.orm.Portfolio entity WHERE entity.PORTFOLIO = HEXAGON20
1- the class should not be there. Ir looks like it comes from the variable className.
2- HEXAGON20 is a string value that should be 'HEXAGON20'
I have the following function that builds a Hibernate Criteria to generate binned data:
private Criteria getCustomBinResultCriteriaSQL(double binSizeX, double binSizeY, String xVar, String yVar, String customBinQuery) {
return createCriteria(Residue.class)
.setProjection(Projections.projectionList()
.add(Projections.sqlGroupProjection(
"floor(" + xVar + " / " + binSizeX + ") * " + binSizeX + " as xBin, " +
"floor(" + yVar + " / " + binSizeY + ") * " + binSizeY + " as yBin, " +
"CAST (" + customBinQuery + " AS DOUBLE PRECISION) as customBinResult",
"xBin, yBin",
new String[] { "xBin", "yBin", "customBinResult" },
new Type[] { Hibernate.DOUBLE, Hibernate.DOUBLE, Hibernate.DOUBLE })))
.setResultTransformer(Transformers.aliasToBean(CustomBinResult.class));
}
This all works pretty well for data within the same table (residue), but let's say my datastructure is like this:
pdbentry:
id
pdbvar
expmethod:
id
expvar
residue:
id
resvar
pdbentry has a one-to-one relation with expmethod, and a one-to-many relation with residue.
How would I go about joining the residue table with expmethod, based on the criteria-builder above. So in other words: what do I need to add to the criteria to be able to have "expvar" as xVar?
I tried adding something like:
.setFetchMode("pdbentry", FetchMode.JOIN);
.setFetchMode("expmethod", FetchMode.JOIN);
at the end, but then I still couldn't put "expvar" nor "expmethod.expvar" as xVar.
Any ideas?
I'm aliasing the joined-to tables via
.createCriteria("rootEntity.foreignEntity", "someAlias")
This makes rootEntity.foreignEntity.someProperty available to the Criteria query as someAlias.someProperty (usually I choose "someAlias" to be the same as "foreignEntity").
Since I usually want an eager fetch, I tend to have Criteria.INNER_JOIN or Criteria.LEFT_JOIN on the createCriteria call, too.
Have you tried "pdbentry.expmethod.expvar"?
It is not clear (to me) what you are trying to do from just this, but the way you define your entity relationships, the way to access the relevant expvar from a given residue would be "residue.pdbentry.expmethod.expvar".