JPA Query with Joins and a Custom Obj that is not Table - java

I am doing a join with a native query. The returned object is a new object that contains all the attributes in the query. But it throws an error saying it can't bind object[] to CombinedObj. What do I do?
public interface SettingsRepository extends JpaRepository<Setting, Long> {
#Query(value = "select s.some_value, o.other_value from settings s inner join other_table o on o.id = s.other_table_id where user_id = :user_id", nativeQuery = true)
List<CombinedObj> find(#Param("user_id") int userId);
}

You can't simply project your columns and expect that jpa infer this columns to result object.
It's possible to solve this using a Named Native Query. Like this:
#Entity
#Table(name = "settings")
#SqlResultSetMapping(
name = "yourResultSetMapping",
classes = {
#ConstructorResult(
targetClass = CombinedObj.class,
columns = {
#ColumnResult(name = "some_value"), #ColumnResult(name = "other_value")
}
)
}
)
#NamedNativeQuery(
name = "Settings.getNativeQuery",
query = "select s.some_value, o.other_value from settings s inner join other_table o on o.id = s.other_table_id where user_id = :user_id",
resultSetMapping = "yourResultSetMapping"
)
public class Settings{...}

Related

Best way to fetch data in SpringBoot by query from two tables

I have two tables:
A : x_id, emp_id, name, age
B: emp_id, company_id, location
I want to fetch data which contain columns 'x_id', 'emp_id', 'company_id', 'name' joining tables 'A' and 'B' using emp_id..What is the best way to get it?
Is it possible to fetch data without creating beans mapping A and B like
Can I create a bean 'Result' containing variables 'x_id', 'emp_id', 'company_id', 'name' and populate it and get list of 'Result' beans as my output?
Yes, first you have to create a model class which includes the required details as the attributes.
#SqlResultSetMapping(
name = "ResultMap",
classes = #ConstructorResult(
targetClass = A.class,
columns = {
#ColumnResult(name = "x_id", type = Long.class),
#ColumnResult(name = "emp_id", type = Long.class),
#ColumnResult(name = "company_id", type = Long.class),
#ColumnResult(name = "name", type = String.class)
}
)
)
public class ResultMap {
private BigInteger x_id;
private BigInteger emp_id;
private BigInteger company_id;
private String name;
public ResultMap(BigInteger x_id, BigInteger emp_id, BigInteger company_id, String name) {
this.x_id = x_id;
this.emp_id = emp_id;
this.company_id = company_id;
this.name = name;
}
}
Then, write a custom query in repository class to get required data. Return type will be List of Tuple.
#Query(
value = "SELECT a.x_id, a.emp_id, b.company_id, a.name \n" +
"FROM A as a, B as b \n" +
"WHERE a.emp_id = b.emp_id",
nativeQuery = true)
List<Tuple> findResultMaps();
Finally Map this List of Tuple to List of ResultMap where ever it used in.
List<Tuple> resultsMapTuples = resultMapDao.findResultMaps();
List<ResultMap> resultMaps = resultsMapTuples.stream()
.map(t -> new ResultMap(
t.get("x_id", BigInteger.class),
t.get("emp_id", BigInteger.class),
t.get("company_id", BigInteger.class)
t.get("name", String.class)
)).collect(Collectors.toList());
resultMapDao is the repository class that findResultMaps() method written in.

How can I map a result set to custom POJO in JPA

I need to fetch 6 columns by joining 3 different tables. I have declared them as NamedNativequery on top of the entity class and I have used create named query method form JPA. When I try fo fetch the result set i get the list of array objects instead of the List of objects of POJO type. is there any external mapping should I be defining in order to map the result set to an external POJO?
You certainly can. This should help:
#NamedNativeQuery(query = "SELECT t1.col1, t2.col2 FROM t1 JOIN t2 ON ...", name = "MyNamedQuery", resultSetMapping = "MyPojoMapper")
#SqlResultSetMapping(name = "MyPojoMapper", classes = #ConstructorResult(
targetClass = MyPojo.class,
columns = {
#ColumnResult(name = "col1", type = String.class),
#ColumnResult(name = "cols", type = String.class)
}))
Then use it as such:
NativeQuery query = session.getNamedNativeQuery("MyNamedQuery");
MyPojo result = (MyPojo) query.getSingleResult();
You can use projection to specify what properties you want to get
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
or directly get with JPQL:
Repository.java
#Repository
public class CustomRepositoryImpl {
#Autowired
private EntityManager entityManager;
public List<Dto> find() {
var query = "SELECT new Dto(
x.Field1,
y.Field2,
z.Field3,
...)
FROM XxxEntity x
LEFT JOIN YyyEntity y
LEFT JOIN ZzzEntity z"
var jpqlQuery = entityManager.createQuery(query);
return jpqlQuery.getResultList();
}
}
Dto.java
public class Dto {
// Must have parameterized constructor with all fields what used in Repository
public Dto(int field1, String field2, String field3, ...) {
}
}

Spring data throws an exception:" No property [property_name] found for type [Object]!"

I would like a Spring Data interface to return a non-entity object.
I have googled and found a solution that I should use named queries with the result set mapping to a non-entity class.
However, I do resieve the described above exception. What causes this exception?
Here is my implementation of the sql result set mapping and named native query:
#SqlResultSetMapping(
name = "revenue",
classes = {
#ConstructorResult(
targetClass = Revenue.class,
columns = {
#ColumnResult(name = "date"),
#ColumnResult(name = "revenue")
}
)
}
)
#NamedNativeQuery(name = "calculateRevenueForGasStationName",
query = "select fueling.date, fueling.price*fueling.volume as revenue from gas_station " +
"left join fueling " +
"on gas_station.id = fueling.gas_station " +
"where fueling.date between ?1 and ?2 and gas_station.name=?3 " +
"group by fueling.date",
resultSetMapping = "revenue")
Here is the spring data interface method that should be linked to a name = "calculateRevenueForGasStationName"
#Query(nativeQuery = true)
List<Revenue> calculateRevenueForGasStationName(Date from, Date to, String name);
It seems problem with your class properties. Can you please revisit your Revenue.class property details.
Please make sure
1) "date" property has declared as java.util.Date
2) revenue has declared as Double
3) Sample code is
`#SqlResultSetMapping(
name = "revenue",
classes = { #ConstructorResult(
targetClass = Revenue.class,
columns = {
#ColumnResult(name = "date", type = java.util.Date.class),
#ColumnResult(name = "revenue",type = Double.class)
} ) } )`

What advantage has JPA 2.1 #ConstructorResult and #SqlResultSetMapping over JPQL SELECT NEW SomeConstructor(...)?

I'm wondering what's the benefit of using #SqlResultSetMapping and #ConstructorResult? Is it better, and if, why, from using JPQL SELECT NEW SomeConstructor ?
For example, is that better:
#Table(name = "person")
#Entity
#SqlResultSetMappings(
#SqlResultSetMapping(name = "contactLess",
classes = #ConstructorResult(columns = {
#ColumnResult(name = "id", type = Long.class),
#ColumnResult(name = "full_name", type=String.class)
}, targetClass = Person.class)
)
)
#NamedNativeQueries({
#NamedNativeQuery(name = "Person.findWithoutContacts",
query = "SELECT c.id, c.full_name FROM person c ",
resultSetMapping = "contactLess", resultClass = Person.class)
})
than this ( spring data in this case):
#Query("SELECT NEW Person(c.id, c.fullName) FROM Person c")
public List<Person> findAll();
If you have several JPQLs (and/or query builders) refering to one entity, than using annotations will make your code easier to refactor. JPQL also has no compile safety.

jpa native query control entity(part 2)

Cont. on jpa native query retrieve multiple entities
My database (testing)
company - ID {PK}, name
staff - ID{PK}, name, companyID{FK}
department - ID{PK}, name, companyID{FK}, staffID{FK}
project - ID{PK}, name, staffID{FK}
First, I want to backup the company table.
String query = "SELECT c.ID as companyid, c.name as companyname FROM company c";
Query q = em.createNativeQuery(query, "MAPPING");
List<CompanyDTO> list = q.getResultList();
Company.java
#SqlResultSetMapping(name = "MAPPING", classes = {
#ConstructorResult(
targetClass = CompanyDTO.class,
columns = {
#ColumnResult(name = "companyid"),
#ColumnResult(name = "companyname")
})
})
...
Second, I want to backup the staff table.
String query = "SELECT s.ID as staffid, s.name as staffname, s.companyID as companyID
FROM staff s JOIN company c ON c.ID = s.companyID";
Query q = em.createNativeQuery(query, "MAPPING");
List<CompanyDTO> list = q.getResultList();
Company.java
#SqlResultSetMapping(name = "MAPPING", classes = {
#ConstructorResult(
targetClass = CompanyDTO.class,
columns = {
#ColumnResult(name = "staffid"),
#ColumnResult(name = "staffname"),
#ColumnResult(name = "companyID")
})
})
...
Now I don't want to fix my table and class. How do I control the ? from the following?
SELECT ... FROM ?
List<?> list = q.getResultList();
Any help please...

Categories

Resources