Issue with writing named sql query with hibernate - spring

I am trying to access database FK using named SQL query with Hibernate, the idea is to query a customer table which contains name, and companyId,etc. CompanyId is the FK for a commpany table. The query I wrote is as follows:
#NamedNativeQuery(name="getcustomer", query="Select CUSTOMER.* from CUSTOMER,COMPANY where CUSTOMER_FIRST_NAME = (?1) and CUSTOMER_LAST_NAME= (?2) and CUSTOMER_COMPANY_ID_FK = (?3) ",resultClass=Customer.class)
The issue I am currently having as follow:
Exception in thread "main" org.hibernate.QueryParameterException:
Position beyond number of declared ordinal parameters. Remember that
ordinal parameters are 1-based! Position: 2 at
org.hibernate.engine.query.spi.ParameterMetadata.getOrdinalParameterDescriptor(ParameterMetadata.java:89)
at
org.hibernate.engine.query.spi.ParameterMetadata.getOrdinalParameterExpectedType(ParameterMetadata.java:109)
at
org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:507)
at
org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:479)
at
com.comresource.scrapmetalapp.DAOImpl.CustomerDAOImpl.searchCustomer(CustomerDAOImpl.java:61)
at
com.comresource.scrapmetalapp.ServiceImpl.CustomerServiceImpl.searchCustomer(CustomerServiceImpl.java:39)
at com.comresource.scrapmetalapp.Config.Run.main(Run.java:57)
My DAO implementation is like this:
#Override
public Customer searchCustomer(String fName, String lName, Integer company) {
Session session = sessionFactory.openSession();
return (Customer) session.getNamedQuery("getcustomer").setParameter(1, fName)
.setParameter(2, lName)
.setParameter(3, company)
.uniqueResult();
}
What is the issue here?

For this, I would need to see how you are associating the mapping in your model class, but the query should go like this.
public Customer getMeThatCustomer(String param1, String param2, int foreignkey){
session = getCurrentSession();
org.hibernate.Query query = session.createQuery("From Customer as c where c.name=:param1 and c.lastname=:param2 and c.company.companyid=:foreignkey");
//Note the last parameter, where I have mentioned c.company, in place of
company, there should be the foregin key association and then the primary key in java class.
query.setParameter("param1",param1);
query.setP...er("param2",param2);
quer.....("companyid",companyid);
return (Customer) query.uniqueResult();
}
So, try it out, let me know if there is any problem

Related

Why can JPQLs modifying queries only return void or int?

When i want to modify the database via JPQL i have to mark the query as Transactional and Modiyfing. If i do so, the return type of the method representing the query has to be either void or int(representing the number of edited rows i think). Why are only the two return types allowed? If i do a HTTP-PUT request and update the object with an own JPQL query, i would like to return the updated object again. Whats the best way to do it if the return type of the query has to be void or int? Do i have to do a seperate query/request again which selects the object after it was updated?
EDIT:
Thats how i call the query:
if (inactivityListDTO.getProjectIds().size() > 0) {
projectRepository.updateProjectsIsArchivedByProjectIds(inactivityListDTO.getProjectIds(), inactivityListDTO.getIsArchived());
}
Thats the query:
#Transactional
#Modifying
#Query("UPDATE Project project SET project.isArchived = :isArchived,
project.archivedDate = current_date " +
"WHERE project.id IN :ids")
void updateProjectsIsArchivedByProjectIds(#Param("ids") List<Long> ids, #Param("isArchived") boolean isArchived);
Because it finally boils down to execute a standard UPDATE SQL in the DB , and the UPDATE in standard SQL only returns the number of records being updated and does not return a result set.
And yes , if you need get a record 's value after update , you have to query it again. Alternatively , you should consider using a JPA way to update a record , which first query the object , then update it by changing its state . Something like below (Assume you are using spring #Transactional to manage the transactional boundary):
#Transactional
public void changeEmployeeSalary(Integer employeeId , Integer salary){
Employee employee = entityManager.find(Employee.class , employeeId);
employee.setSalary(salary);
}
In this way , you do not need to query the record again after it is updated and you also do not need to manually write a UPDATE SQL.

Query to check if the record exists in Spring Jdbc Template

I am fairly new to spring ,I am looking to check if a certain email id exists in database or not , using Spring Jdbc Template ,I looked here but could'nt find the proper answer .I am looking something like ,SELECT count(*) from table where email=?
Any help will be appreciated.
You can do something as below if you are using jdbctemplate and new version of spring
private boolean isEmailIdExists(String email) {
String sql = "SELECT count(*) FROM table WHERE email = ?";
int count = jdbcTemplate.queryForObject(sql, new Object[] { email }, Integer.class);
return count > 0;
}
queryForObject method of jdbcTemplate accepts the sql query as the first parameter, second argument is an array of objects for the sql query place holders and the third argument is the expected return value from the sql query.
In this case we only have one place holder and hence I gave the second argument as new Object[] { email } and the result we are expecting is a count which is a Integer and hence I gave it as Integer.class
I kind of got this answer from https://www.mkyong.com/spring/jdbctemplate-queryforint-is-deprecated/
You can go through it if you are interested.
private boolean isEmailIdExists(String email) {
return jdbcTemplate.queryForObject("SELECT EXISTS(SELECT FROM table WHERE email = ?)", Boolean.class, email);
}
http://www.postgresqltutorial.com/postgresql-exists/

Use WHERE clause with instances in hql

How to select a record from a table using WHERE clause and comparing instances (patient)
public History findHistory(Patient patient) { History model=null;
Session sesion=util.HibernateUtil.getSessionFactory().getCurrentSession();
String sql="FROM History h WHERE h.patients=" + patient;
try{
sesion.beginTransaction();
model=(History) sesion.createQuery(sql).uniqueResult();
sesion.beginTransaction().commit();
}
catch(Exception e){
sesion.beginTransaction().rollback();
}
return model;
}
That throws a queryException #1562
e.queryString="FROM entidad.Historia h WHERE h.pacientes=entidad.Paciente#3ad3a221"
e.detailMessage="unexpected char: '#'"
The problem with your code is that concatenating patient like you do will just append patient.toString(), which in your case is the default implementation (i.e. classname#hashcode) and it is no use for Hibernate to find out which data to retrieve in the DB.
You need to bind the parameter, first:
String sql = "FROM History h WHERE h.patients = :patient";
Then
model = (History) sesion.createQuery(sql)
.setParameter("patient", patient)
.uniqueResult();
Edit:
SQLGrammarException: could not execute query can occurs for various reason. Try to run the generated query in SqlDeveloper (or any other tool) and see what your DB says. In your case, the last part and .=? cause the error. The cross join is Harming too. I suspect your mapping is incomplete and Hibernate can't find how to join History and Patient. Try to add something like this in History entity:
#ManyToOne
#JoinColumn(name = "patient")
private Patient patient;

Using distinct in Spring data over multiple columns

My domain model is like this:
CollectedData {
String name;
String description;
int count;
int xAxis,
int yAxis
}
Using Spring data repository query, I would like to retrieve all the unique rows (unique with name, xAxis, yAxis)
I am trying something like this
#Query("select distinct a.name, a.xAxis, a.yAxis from CollectedData a")
List<CollectedData> findAllDistinctData();
So, when I do
List<CollectedData> records= findAllDistinctData();
for (CollectedData record : records) { //Exception on this line
}
Exception
[Ljava.lang.Object; cannot be cast to CollectedData.
Is there any other way to write query for this ?
#Query return ArrayList of Object(s) instead of specific type of object. so you have to define some thing like
#Query("select distinct a.name, a.xAxis, a.yAxis from CollectedData a")
List<Object> findAllDistinctData();
then cast according to your requirement,
List<Object> cdataList=findAllDistinctData();
for (Object cdata:cdataList) {
Object[] obj= (Object[]) cdata;
String name = (String)obj[0];
String description = (String)obj[1];;
...
}
Instead of returning an object you can use JPA's constructor expression feature to return a more specific object holding only the columns you're interested in. See also following answer:
JPQL Constructor Expression - org.hibernate.hql.ast.QuerySyntaxException:Table is not mapped
According to your example you could create a new Object with only the columns you are interested in:
SELECT DISTINCT new com.mypackage.MyInterestingCollectedData(a.name, a.xAxis, a.yAxis) from CollectedData a
If you want to select complete object based on distinct values of multiple columns,
In that case the native query would be the option.
e.g.
#Query(
value = "select distinct on (column1, column2, column3) * From my_table where someId=: order by column1 asc,column2 desc,column3 desc,column4 desc",
nativeQuery = true
)
fun finalAllDistinctBy(containerId: String): List<MyTable>

Linq nested select new not working

I'm trying to get eager loading working with Subsonic, and it's been returning null for me.
In the method below, I'm trying to hydrate a domain model (UserModel) which contains another domain model (CompanyModel). However, with the code below, UserModel.Company is always null.
What am I missing here. Any help would be appreciated.
public IList<UserModel> GetUsers()
{
return (from u in SubsonicSqlServer.Users.All()
select new UserModel
{
UserId= u.UserId,
Company = (from c in u.Companies
select new CompanyModel
{
CompanyId = c.CompanyId,
CompanyName = c.CompanyName
}).SingleOrDefault(),
FirstName = u.FirstName,
LastName = u.LastName,
BirthDate = u.BirthDate
}).ToList();
}
Update (08/11/09):
More toying around with the code, I found out that setting CompanyId in the following example doesn't work either. I initially thought this was an issue with Subsonic, but if the code below doesn't work, I'm guessing it has something to do with my Linq statement. Any ideas?
public IList<UserModel> GetUsers()
{
return (from u in SubsonicSqlServer.Users.All()
select new UserModel
{
UserId= u.UserId,
CompanyId = Guid.NewGuid(),
FirstName = u.FirstName,
LastName = u.LastName,
BirthDate = u.BirthDate
}).ToList();
}
Update (11/17/2009):
Still haven't found a solution. But we are switching to nHibernate (not because of this issue).
"UserModel.Company is always null."
since you are setting this with an expression that ends with .SingleOrDefault(), I'm going to suggest that the query isn't returning a single item. Start investigating there. If you are expecting exactly one item in u.Companies, change to .Single() and force an early failure.
You can do the .Single() before creating the new CompanyModel object, I think.
As for style, I like the query comprehension syntax ("from x in y select") but find it awkward when combined with traditional dot-notation syntax. It's just hard to read. (LINQ - Fluent and Query Expression - Is there any benefit(s) of one over other?).
Consider using let in the query comprehension to make it clearer.
Also, since a query already returns an IEnumerable<T>, and calling ToList() forces all items to be realized, I would modify my method to return IEnumerable<T> if possible.
So, in your case, I would refactor the first to say:
public IEnumerable<User> GetUsers()
{
return from u in SubsonicSqlServer.Users.All()
let c = u.Companies.Single()
select new UserModel
{
UserId = u.UserId,
Company = new CompanyModel
{
CompanyId = c.CompanyId,
CompanyName = c.CompanyName
},
FirstName = e.FirstName,
LastName = e.LastName,
BirthDate = e.BirthDate
};
}
If it makes sense in your object model, you could modify User to have a constructor that takes whatever type u is, and it gets even simpler:
return from u in SubsonicSqlServer.Users.All()
select new UserModel (u);
or even
return SubsonicSqlServer.Users.All().Select(u => new UserModel (u));
Two things
You're returning a List<UserModel> when your method's signature line says IList<User> does UserModel inherit from User?
Am I missing something, where does e come from?
FirstName = e.FirstName,
LastName = e.LastName,
BirthDate = e.BirthDate Blockquote
Please check out my fork # github (http://github.com/funky81/SubSonic-3.0/commit/aa7a9c1b564b2667db7fbd41e09ab72f5d58dcdb) for this solution, actually there's a problem when subsonic try to project new type class, so there's nothin wrong with your code actually :D

Resources