I am just trying to avoid writing query and fetch data based on method name convention. Below is my Entity
#Entity
class Product{
#Id
private Integer productId;
private String productName;
private String productStrategy;
}
I have below repository:
interface ProductRepository extends JPARepository<Product,Integer>{
public Product findByProductStrategy(String productStrategy);
}
Above method and repository is working fine for me. But I am using only productName from the above result. So is there any way using which i can just fetch the productName instead of fetching hole record.
Note: I know, we can achieve it using #Query by writing HQL query or native query. But i want to do it without writing query, just with the method name convention.
Consider using Projections from spring data
Create a projection interface for your entity with the field that you want. In your case, it should look something like
public interface ProductName {
String getProductName();
}
and then change your repository to have the return type of the projection interface itself. Spring will take care of the rest.
public interface ProductRepository extends JPARepository<Product,Integer>{
public ProductName findByProductStrategy(String productStrategy);
}
Related
I am using Spring Boot application. I am using following method to return List<String> using #Query
annotation.
#Query("select c.name from Customer c")
List<String> findAllNames();
Is there a way to get the above result without #Query or #NativeQuery annotations?
Spring Data JPA supports this quite well. You can define a POJO that represents the (reduced) object (the projection) you want of the entity, then define a method that describes the query, returns the appropriate type, and Spring Data will generate all the code necessary to execute the query and map the results.
Here's an example of a custom repository interface that uses this technique (untested pseudo-code):
public class CustomerSummary {
private String name;
// constructor and getters
}
#Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<CustomerSummary> getAllSummaries();
}
I'm not sure if you can use "simple" types such as String in the return type, but I wouldn't be surprised if that is supported.
Also, you might have to tweak the exact method naming of `` to make sure Spring Data correctly interprets it as you want. Here is some additional reference documentation.
You could use projection to select only name property:
interface CustomerNameProjection {
String getName();
}
and then use it in Repository class:
List<CustomerNameProjection> findAllProjectedBy();
edit: corrected repository method name
Inject EntityManager and call createQuery.
entityManager.createQuery("select c.name from Customer c")
.getResultList()
Edit: I think it would be helpful to explain my goal here first. My goal is to reduce and avoid model/#Entity bloat when using stored procedures with Hibernate. You can get raw data back from the persistent EntityManager when using a stored procedure, but that data will not be mapped. If you send in a stripped down model to Hibernate, Hibernate will only send you back the columns which are annotated as #Column on the #Entity model (almost forcing you to create a new #Entity for every stored procedure!) You can attempt to map this data with a DTO that has more properties, but they won't map to anything because all the fields which were not included on the model will return null.
I've been struggling to find an answer to this in my research. We use an MSSQL database and Spring with JPA/javax/Hibernate persistence, but do not rely on Hibernate for its ORM. All CRUD operations are done using stored procedures. We have several models (Spring #Entity) which work well for retrieving and mapping data. For example, a basic user model.
import javax.persistence;
#Entity
public class User {
#Id
#Column
private int userID;
#Column
private String userName;
#Column
private Date userDOB;
public User(UserDTO userDTO){
userName = userDTO.getUserName();
userID = userDTO.getUserID();
// Extra column userDOB, and no way to map accountDetails from the DTO
}
public int getUserID(){...}
public String getUserName(){...}
public Date getUserDOB(){...}
}
This works well when the stored procedure selects columns in a way that matches up with the model, however in cases where we want to selectively query data using joins, the columns (names and number of columns) often don't match up with the models. In this case, it makes sense to have DTOs to actually map the receiving data from the database using a constructor in the related Model. However, Spring doesn't like injecting the DTO directly (because it complains it isn't an entity), and injecting the model directly into the stored procedure query will fail, since the columns (number of columns!) don't match up.
public class UserDTO {
private String accountDetails;
private int userID;
private String userName;
public int getUserID(){...}
public String getUserName(){...}
}
I've tried using ModelMapper, but the first argument is an Object (the data), which isn't obtainable, since the data can't be mapped. I can of course call StoredProcedureQuery without a Model hint, and receive the raw data, but it will not be mapped.
public class UserRepo {
import javax.persistence;
public List<UserDTO> getUserAccountInfo(){
StoredProcedureQuery query = entityManager.createQuery(storedProcedureSelectUserAccount, User.class);
query.execute(); // Will fail here with SQL Server error: Unknown column userDOB.
List<UserDTO> result = query.getResults();
return result;
}
}
Others have suggested using raw Selects or other String based mapping strategies, but I would really appreciate some advice on retrieving and mapping the returned data using a DTO with the already written Stored Procedures. Thank you!
In my application I use DTOs. My current solution in pseudocode is this - works well:
ResponseEntity<EntityDTO> RestController.get(String uuid){
EntityDTO dto = Service.get(uuid) {
Entity entity = Repository.loadEntity(id);
return EntityDTO.from(entity);
}
return ResponseEntity<EntityDTO>( dto , HttpStatus.OK);
}
Recently I saw an other solution without the transformation step in the service layer.
E.g. your Entity looks like this
:
#Entity
public class Book {
Long id;
String title;
String text;
.....
}
And the text is too 'heavy' to send it with the hole book you usually would create a DTO like this:
public class SlimBookDTO {,
static SlimBookDTO from(Book book) {
return new SlimBookDTO(book.id, book.title);
}
Long id;
String title;
.....
}
The "new" (for me) Solution is to create only an interface like this:
public interface SlimBookDTO {
Long getId();
String getTitle();
}
And your BookRepository gets a new method:
#Repository
public interface BookRepository extends JpaRepository<Book , Long> {
List<SlimBookDTO> findAllByTitle(String title);
}
With this method I don't need the service layer any more for direct requests. Is this common? Does somebody has experience with this? Has it some downsides that I can't see in a small application but will face in larger scale?
Those are couple of ways of returning data from the database.
You create DTO and map necessary fields and return
Other is create an interface which is directly a kind of return type from Repository. this is what we call as JPA interface projection.
For second one, you know in detail by referring below link
https://www.baeldung.com/spring-data-jpa-projections
JPA interface projections are very useful when we query two or more entities in the Repository class
This is totally fine for simple GETs if the objects are straightforward enough, although of course you can't add additional logic, formatting or constraints. But as long as you don't need to do that, this will work well.
I don't think Hibernate analyzes the dto to only select a few fields though, so if you want to improve the performance too you can define the queries yourself, i.e. #Query("select new com.bla.SlimbookDTO(book.id, book.title) from Book book"), at the cost of not being able to just use automagically generated queries anymore based on the method name.
I am trying to stream in an entire database (about 22,000 records) via Spring JPA. Using the FindAll() method I can get them in, but they are all brought into memory at once. I want to stream them.
I have tried streamAll():
#Repository
public interface GroupJsonRepository extends CrudRepository<GroupJson, String> {
Stream<GroupJson> streamAll();
}
but I get a bizarre error:
No property streamAll found for type GroupJson!
My object is:
#Entity
#Table(name = "GroupJson")
public class GroupJson {
#Id
private String id;
private String hash;
private String jsonData;
private ZonedDateTime lastUpdatedTimeStamp;
...
Is there another repository I can use that does this? I can only find CrudRepository. OR, is there some other magic JPA key words that work? I am using Spring boot 1.5.9 and I am streaming data elsewhere, but I am using a custom call:
Stream<Authority> findByPartitionKey(Long partitionKey);
You can use query if too,
#Query("select gj from Customer gj")
Stream<GroupJson> streamAll();
You have to include the "By" part in the method declaration to enable Spring Data to parse your method name. Thats the reason why you get your strange error. Spring Data interprets streamAll as a property in your entity.
#Repository
public interface GroupJsonRepository extends CrudRepository<GroupJson, String> {
Stream<GroupJson> streamAllBy();
}
In Spring CrudRepository, do we have support for "IN clause" for a field? ie something similar to the following?
findByInventoryIds(List<Long> inventoryIdList)
If such support is not available, what elegant options can be considered? Firing queries for each id may not be optimal.
findByInventoryIdIn(List<Long> inventoryIdList) should do the trick.
The HTTP request parameter format would be like so:
Yes ?id=1,2,3
No ?id=1&id=2&id=3
The complete list of JPA repository keywords can be found in the current documentation listing. It shows that IsIn is equivalent – if you prefer the verb for readability – and that JPA also supports NotIn and IsNotIn.
If inventoryId has the primary key, you can simply use yourRepo.findAll(inventoryIdList).
For any method in a Spring CrudRepository you should be able to specify the #Query yourself. Something like this should work:
#Query( "select o from MyObject o where inventoryId in :ids" )
List<MyObject> findByInventoryIds(#Param("ids") List<Long> inventoryIdList);
Yes, that is supported.
Check the documentation provided here for the supported keywords inside method names.
You can just define the method in the repository interface without using the #Query annotation and writing your custom query. In your case it would be as followed:
List<Inventory> findByIdIn(List<Long> ids);
I assume that you have the Inventory entity and the InventoryRepository interface. The code in your case should look like this:
The Entity
#Entity
public class Inventory implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
// other fields
// getters/setters
}
The Repository
#Repository
#Transactional
public interface InventoryRepository extends PagingAndSortingRepository<Inventory, Long> {
List<Inventory> findByIdIn(List<Long> ids);
}