I have two projection interface,
First, ProductMinimal.java:
public interface ProductMinimal {
long getId();
String getName();
Long getOwnerId();
String getOwnerName();
String getFeaturedImage();
}
and second ProductStatistic.java
public interface ProductStatistic extends ProductMinimal {
int getTotalVisit();
}
When i use this repository:
Page<ProductStatistic> findMostView(Pageable pageable);
I get result, but wrongly mapped:
[{
name=1, WRONG
id=Name, WRONG
ownerId=administrator, WRONG
ownerName=21_d20024e8-970f-4738-9cea-8dda22d0afdd.jpg, WRONG
featuredImage=1, WRONG
totalVisit=21
}]
it should be:
[{
name=Name,
id=1,
ownerId=1,
ownerName=administrator,
featuredImage=21_d20024e8-970f-4738-9cea-8dda22d0afdd.jpg,
totalVisit=21
}]
but when I put all method in ProductMinimal to ProductStatistic and remove parent interface in ProductStatistic, so ProductStatistic all its own attribute:
public interface ProductStatistic {
long getId();
String getName();
Long getOwnerId();
String getOwnerName();
String getFeaturedImage();
int getTotalVisit();
}
using new this ProductStatistic, now I get expected result.
[{
name=Name,
id=1,
ownerId=1,
ownerName=administrator,
featuredImage=21_d20024e8-970f-4738-9cea-8dda22d0afdd.jpg,
totalVisit=21
}]
I don't like using this way, rewrite all existing property.
What I expect is to be able extends property from ProductMinimal, so i don't need to rewrite code.
Why using interface-based projection that extends other interface projection give wrong result?
Related
I have an entity class User with 20 fields, some of them being confidential fields. I have a controller class, which has a method getUser to fetch all the user from DB and send the JSON respone. Below is the sample code for the same:
#GetMapping("/getUsers")
public UserDT getUsers( Model theModel) {
List<User> userList;
userList = userService.findAll();
return userList;
}
When I run the above code, it returns all the fields from User table/User Entity Class. Instead of sending all the fields, I would like to send selected fields say Field1 to Field5 only.
Ultimate goal is to have multiple views for the same Entity Class. For URL1 I would like to show only field1 to field5 of User table, But for URL2 I would like to show Field9 , Filed15, Field20.
Do I need to create multiple Entity Class for each URL? Please guide me with the best practice to be followed in such scenario.
Assuming you are using Spring Data JPA, use projections.
So create different projections for your different URLs write a method that returns the projection (or a dynamic one as in the documentation).
public interface NamesOnlyProjection {
String getFirstName();
String getLastName();
}
public interface UserinfoProjection {
String getUsername();
String getPassword();
String getDepartment();
}
Then in your repository do something like this
public interface PersonRepository extends JpaRepository<Person, Long> {
<T> List<T> findAll(Class<T> type);
}
Then you can do something like this in your controller/service
#RestController
public class PersonController {
private final PersonRepository persons;
#GetMapping("/people/names")
public List<NamesOnlyProjection> allNames() {
return persons.findAll(NamesOnlyProjection.class);
}
#GetMapping("/people/users")
public List<UserinfoProjection> allNames() {
return persons.findAll(UserinfoProjection.class);
}
}
Model Class Vehicle
#Column(name="type",nullable=false)
private String type;
#Column(name="last_service_date",nullable=false)
private String lastServiceDate;
#Column(name="seats",nullable=false)
private Long seats;
#Column(name="bags_capacity",nullable=false)
private Long bagsCapacity;
#Column(name="milage",nullable=false)
private Long milage;
//for Franchise object id
private transient Long fId;
#ManyToOne
#JoinColumn(name="franchise_id")
private Franchise fkFranchiseId;
#Repository
public interface VehicleRepository extends JpaRepository<Vehicle,Long>
{
}
I am using spring data jpa repositories and want to search Vehicle by type and foreignKey=>(zipcode) how can i find
Just add a method in your Vehicle JPA repository interface as follow:
findAllByTypeAndFkFranchiseIdZipCode(String type, String zipCode);
And also you are welcome to check docs of Spring Data Jpa
List<Vehicle> findAllByTypeAndFkFranchiseId_ZipCode(String type, String zipCode);
You can use JPA repo method name query documented here https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
public interface VehicleRepo extends JpaRepository<Vehicle, String> {
List<Vehicle> findAllByTypeAndFkFranchiseIdZipCode((String type, String zipCode);
Page<Vehicle> findAllByTypeAndFkFranchiseIdZipCode((String type, String zipCode,Pageable page);
}
for those who have a more complex object and want to keep their code, u can also use #Query for fetching data.
u just need to do this like this:
#Repository
public interface VehicleRepo extends JpaRepository<Vehicle, String> {
#Query("from Vehicle v where v.type = :type and v.fkFranchise.zipCode = :zipCode")
List<Vehicle> findAllByTypeAndZipCode(String type, String zipCode);
}
I have object like this:
#Entity
public class DocumentationRecord {
#Id
#GeneratedValue
private long id;
private String topic;
private boolean isParent;
#OneToMany
private List<DocumentationRecord> children;
...
}
now I would like to get only topics and ids. Is there way to get it in format like this:
[
{
id: 4234234,
topic: "fsdfsdf"
},...
]
Because even using only this query
public interface DocumentationRecordRepository extends CrudRepository<DocumentationRecord, Long> {
#Query("SELECT d.topic as topic, d.id as id FROM DocumentationRecord d")
List<DocumentationRecord> getAllTopics();
}
I was only able to get record like this:
[
[
"youngChild topic",
317
],
[
"oldChild topic",
318
],
[
"child topic",
319
],
]
I don't like array of arrays I would like to get array of object with property id and topic. What is the nicest way to achieve that?
In Spring Data JPA you can use projections:
Interface based:
public interface IdAndTopic {
Long getId();
String getTopic();
}
Class based (DTO):
#Value // Lombok annotation
public class IdAndTopic {
Long id;
String topic;
}
Then create a simple query method in your repo:
public interface DocumentationRecordRepository extends CrudRepository<DocumentationRecord, Long> {
List<IdAndTopic> findBy();
}
You can create even dynamic query method:
List<T> findBy(Class<T> type);
Then use it like this:
List<DocumentationRecord> records = findBy(DocumentationRecord.class);
List<IdAndTopic> idAndTopics = findBy(IdAndTopic.class);
You can create a class with attributes id and topic and use constructor injection into query. Sth like below
#Query("SELECT NEW your.package.SomeObject(d.id, d.topic) FROM DocumentationRecord d")
I am using ElasticsearchRepository and want to query on boolean property.
Sample snippet here:
class TempBean
{
private boolean isActive;
}
interface MyEntityRepository implements CrudRepository<MyEntity, Long>
{
TempBean findByIsActiveTrue();
}
How to query on the active property without passing it as param to the abstract method?
This is possible if I would have JpaRepository as per this answer how-to-query-for-boolean-property-with-spring-crudrepository
It is possible, as can be seen in the docs. Just remove "Is" from your function:
interface MyEntityRepository implements CrudRepository<MyEntity, Long>
{
TempBean findByActiveTrue();
}
As a side note, I don't know about your schema but I would suggest you use Page<TempBean> as your return type, which would require PageRequest as an argument. This is in case more than one TempBean docs have "active":"true" and your function is likely to return more than one records.
I try to get data from mongoDb throw repository by two parameters which both I would like to be in box bounds:
model
#Document(collection = "houses")
public class House {
#Id
private String id;
#TextIndexed
private String name;
private String address;
private Double longitude;
private Double latitude;
/* getters and setters ommited*/ }
Repository
public interface HouseRepository extends PagingAndSortingRepository<House, String> {
#Query("{'name': {'$regex': '?0','$options' : 'i'}}")
Set<Hotel> findWithNameContains(String name);
Set<Hotel> findByLatitudeAndLongitudeWithin(Box bounds);
Set<Hotel> findByLatitudeAndLongitudeWithin(Circle circle);
}
but when I call:
Box bounds = new Box(geoLocation.getLocationCordinates().getNortheastBounds(),geoLocation.getLocationCordinates().getSouthwestBounds());
houseRep.findByLatitudeAndLongitudeWithin(bounds);
I get :
org.springframework.data.repository.query.ParameterOutOfBoundsException: Invalid parameter index! You seem to have declare too little query method parameters!
org.springframework.data.repository.query.Parameters.getParameter(Parameters.java:178)
org.springframework.data.repository.query.Parameters.getBindableParameter(Parameters.java:248)
org.springframework.data.repository.query.ParametersParameterAccessor.getBindableValue(ParametersParameterAccessor.java:107)
org.springframework.data.repository.query.ParametersParameterAccessor$BindableParameterIterator.next(ParametersParameterAccessor.java:150)
org.springframework.data.mongodb.repository.query.ConvertingParameterAccessor$ConvertingIterator.next(ConvertingParameterAccessor.java:176)
org.springframework.data.mongodb.repository.query.MongoQueryCreator.from(MongoQueryCreator.java:240)
org.springframework.data.mongodb.repository.query.MongoQueryCreator.and(MongoQueryCreator.java:133)
org.springframework.data.mongodb.repository.query.MongoQueryCreator.and(MongoQueryCreator.java:58)
org.springframework.data.repository.query.parser.AbstractQueryCreator.createCriteria(AbstractQueryCreator.java:109)
To say truth, do not where is problem, maybe someone can help.
The error results from lon/lat being individual properties. Using MongoDB you need to store location data either as array or in GeoJSON format.
loc : [ 37.7577 , -122.4376 ] //...legacy format
loc : { type : "Point", coordinates : [ 37.7577 , -122.4376 ] } //...GeoJSON
Using Spring Data you have to option to use a double [] or Point for legacy as well as GeoJsonPoint for GeoJSON representation (see. Reference: GeoSpatial Queries). This allows you to use derived query methods like
List<Hotel> findByLocationNear(Point point);
GeoResults<Hotel> findByLocationNear(Point point, Distance maxDistance);
List<Hotel> findByLocationWithin(Circle circle);
List<Hotel> findByLocationWithin(Box box);
List<Hotel> findByLocationWithin(Polygon polygon);