I am trying to learn spring data elasticsearch, and created a sample project. Right now, I am trying to get familiar with the mechanics of sorting.
Simply put, I have a Person class, that has a firstName and lastName field. I am trying to sort on the lastNameField.
Here is my Person class:
#Document(indexName = "entities", type = "person", shards=1, replicas=0)
public class Person {
#Id
private String id;
#Field(type=FieldType.String, index=FieldIndex.not_analyzed)
private String firstName;
#Field(type=FieldType.String, index=FieldIndex.not_analyzed)
private String lastName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Here is my DAO logic:
#Override
public Page<Person> getPeople(int pageNumber, int pageSize, Direction direction, String...sortFields) {
return personRepository.findAll(new PageRequest(pageNumber, pageSize, direction, sortFields));
}
The personRepository is an empty interface that extends PagingAndSortingRepository
And the actual call:
int pageSize = 1;
int currentPageNumber = -1;
boolean morePages = true;
while(morePages){
Page<Person> results = personDataHandler.getPeople(currentPageNumber+1, pageSize, Direction.DESC, "firstName");
List<Person> people = results.getContent();
if(!CollectionUtils.isEmpty(people)){
for(Person currentPerson: people){
System.out.println("[firstName: "+currentPerson.getFirstName()+", lastName: "+currentPerson.getLastName()+"]");
}
}
currentPageNumber++;
morePages = results.hasNext();
}
Could having a page size of 1 be the issue?
Related
I converted UUID to string (String id) and put the conversion inside a method.
I also declared other String variables such as FirstName etc and put in on an ArrayList:
Code
The code does work. But I'm confused why the string email was showing second on the list.
public class StudentController {
#Autowired
StudentService studentService = new StudentService();
#GetMapping
public List<Student> displayStudent(){
return studentService.getStudent();
}
}
public class StudentService {
Student student = new Student();
private List<Student> studentList = Arrays.asList(
new Student(student.genID(),"Elvis" , "Presley" ,"Elvis#gmail.com")
);
public List<Student> getStudent(){
return studentList;
}
}
public class Student {
UUID uuid = UUID.randomUUID();
private String id;
private String FirstName;
private String LastName;
private String email;
public Student() {}
//Method Converting UUID into string
public String genID(){
id = uuid.toString();
return id;
}
public Student(String id) {
this.id = id;
}
public Student(String id, String firstName, String lastName, String email) {
this.id = id;
FirstName = firstName;
LastName = lastName;
this.email = email;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return FirstName;
}
public void setFirstName(String firstName) {
FirstName = firstName;
}
public String getLastName() {
return LastName;
}
public void setLastName(String lastName) {
LastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Expected
I expected data to be in this order
ID , FirstName , LastName , email
Actual Output JSON
JSON is an unordered collection, as specified on https://www.json.org/json-en.html , so you don't have to worry about it. It might depend on library though.
Specify the serialized order of properties
The order of properties during serialization can be defined in Jackson.
Either at class-level specifically using annotation #JsonPropertyOrder.
Or globally for your ObjectMapper using a feature:
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
Example
In your case you can achieve expected order using the annotation on your class:
#JsonPropertyOrder({'id', 'firstName', 'lastName', 'email'})
public class Student {
// body of your class
}
Or separately with an index on your fields:
public class Student {
#JsonProperty(index=10)
private String id;
// not ordered specifically
private String firstName;
private String lastName;
#JsonProperty(index=20)
private String email;
// remainder of your class
}
See also
Jackson ObjectMapper - specify serialization order of object properties
Order of JSON objects using Jackson's ObjectMapper
Jackson JSON - Using #JsonPropertyOrder annotation to define serialized properties ordering
I am trying to get some specific column values using projection by joining two unrelated entities. But I am not getting any values.
Repository code is:-
#Repository
public interface PersonRepository extends CrudRepository<Person, Long> {
#Query("SELECT p.id,p.firstName,p.lastName,a.city FROM Person p INNER JOIN Address a on p.id = a.personId")
public List<PersonAndAddressSummary> findAllPersonSummary();
}
Person class
#Entity
public class Person {
#Id
private long id;
private String firstName;
private String lastName;
private long phone;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getPhone() {
return phone;
}
public void setPhone(long phone) {
this.phone = phone;
}
}
Address class
#Entity
public class Address {
#Id
private int id;
private String street;
private String state;
private int personId;
private String country;
private int houseNo;
private String city;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public int getPersonId() {
return personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public int getHouseNo() {
return houseNo;
}
public void setHouseNo(int houseNo) {
this.houseNo = houseNo;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
Projection interface
public interface PersonAndAddressSummary {
public String getId();
public String getFirstName();
public String getLastName();
public String getCity();
}
After executing this Spring Boot application, the output I am getting is this.
[{"lastName":null,"firstName":null,"city":null,"id":null},{"lastName":null,"firstName":null,"city":null,"id":null},{"lastName":null,"firstName":null,"city":null,"id":null}]
Though there are records available which match perfectly for each Person in Address class(data available in person and address table).
If there is no join between two entities then you can't get data of other entity.Every repository is class specific in jpa. You have to define different projection for each class.
#Repository
public interface PersonRepository extends CrudRepository<Person, Long> {
#Query("SELECT p FROM Person p")
public List<PersonAndSummary> findAllPersonSummary();
}
#Repository
public interface AddressRepository extends CrudRepository<Address, Long> {
#Query("SELECT a FROM Address a where a.personId=:personId")
public AddressSummary findAddressSummary(#Param("personId") int personId);
}
public interface PersonSummary {
public String getId();
public String getFirstName();
public String getLastName();
}
public interface AddressSummary {
public String getCity();
}
public interface PersonAndAddressSummary extends PersonSummary, AddressSummary{
}
Now in your service class find list of personSummary. Now iterate this list and get AddressSummary by personId.
List<PersonSummary> personSummaryList = yourRepositoryName.findAllPersonSummary();
List<PersonAndAddressSummary> list = new ArrayList<>();
for(PersonSummary summary: personSummaryList){
AddressSummary addressSummary = repositoryName.findAddressSummary(summary.getId());
//now add required fields in your list
}
I am trying to find a specific object. I'm using the following code, but it seem like get only sends back a Boolean that verifies that there is a key with this name, but not an array of Boolean values that I need to use in my program:
private Map<User, ArrayList<Boolean>> userDayOfVacationMap;
public ArrayList<Boolean> getUserVacationList(User key){
return this.userDayOfVacationMap.get(key);
}
Is there a method for this?
Here is the User object:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String firstName;
private String lastName;
#OneToMany(mappedBy="user", cascade = CascadeType.ALL)
public Set<Vacation> vacations;
public User(String firstName, String lastName) {
this.firstName=firstName;
this.lastName=lastName;
}
public User(){}
public Set<Vacation> getVacations() {
return vacations;
}
public void setId(int id){
this.id = id;
}
public Integer getId(){
return this.id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
However, I can't add a variable in this function, because it would add non-useful information into my database.
Can anyone explain me how to add advanced queries in crudrepository for example in my case I want to search users by their firstname.
Below is my AppUsers Class
public class AppUsers {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int id;
#Column(name = "firstname")
public String firstName;
#Column(name = "lastname")
public String lastName;
public AppUsers() {
}
public AppUsers(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
This is the AppUsers Repository :
package com.developer.SpringMySQL.models;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface AppUsersRepo extends PagingAndSortingRepository<AppUsers,Integer> {
}
and this is the controller :
#Controller
public class MainController {
private AppUsersRepo usersRepository;
#Autowired
AppUsersRepo appRepo;
#RequestMapping("/")
public ModelAndView doHome() {
ModelAndView mv = new ModelAndView("index");
mv.addObject("lists", appRepo.findAll());
return mv;
}
}
It's naming convention on the repository method.
In your case you need to create a method in the Repository interface :
Set findByFirstName(String pFirstName);
See following links for more infos on the naming convention :
https://spring.io/guides/gs/accessing-data-mysql/
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
in Spring JPA you can do it like this:
Set<AppUsers> findByFirstName(String firstName);
Or in more complex you can use mysql like this (example from project of mine):
#Query("SELECT NEW ps.exalt.timeoff.server.response.BasicInformation(e.id,e.name,e.email,e.profilePicture) FROM Employee e join e.roles r where r.id = 5 AND e.id > 0 AND activated= :enable")
Page<BasicInformation> findAllEmpWithApprovers(Pageable pageRequest,#Param("enable")boolean enable);
for more info check docs: http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
I am using Spring boot and trying to implement many to many relationship between User and Skill. I have a table users_skills with columns user_id and skill_id. I keep getting "JoinColumn cannot be resolved to a type" error in #JoinColumn annotations in STS when trying to implement the relationship. Below is my User class
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String email;
private String firstName;
private String lastName;
private List<Skill> skills = new ArrayList<Skill>();
protected User() {}
public User(String email,String firstName, String lastName) {
this.email = email;
this.firstName = firstName;
this.lastName = lastName;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id ;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email ;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName ;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName ;
}
#ManyToMany
#JoinTable(name="users_skills",
joinColumns={#JoinColumn(name="user_id")},
inverseJoinColumns={#JoinColumn(name="skill_id")})
public List<Skill> getSkills(){
return skills;
}
public void setSkills(List<Skill> skills) {
this.skills = skills ;
}
}
Just write this at the head of your class
import javax.persistence.JoinColumn;
Sometime eclipse doesn't show the link to import it in context menu, but it's there. Hope it will help someone.