Spring #RedisHash findAll() return null values - java

I'm using Redis to store students with entity:
#RedisHash("Student")
public class Student implements Serializable {
#Id
private Long id;
#Indexed
private String name;
private Integer age;
// getters
// setters
// Constructor with full parameters
}
and repository:
#Repository
public interface StudentRepository extends CrudRepository<Student, Long> {
}
I can save a list of students to Redis database and get that list without any error:
#Autowired
StudentRepository repo;
List<Student> students = new ArrayList<>();
Student student1 = new Student(........);
students.add(student1);
Student student2 = new Student(........);
students.add(student2);
repo.findAll().forEach(){
System.out.println(student);
}
The problem is when other project of mine (I'm building apps with micro-service architecture), I use findAll() function to get that list of students, it returns a list of two null elements. If I use findByName(String name), it still returns desired result.
Anyone who used to face this problem can help me, thank you in advanced ?

Turns out my Student class on the other project has the same #RedisHash("Student") but different full class name (same class name but different package). I think this issue belongs to the library.
Updated: cause #RedisHash doesn't work like expected, I found the way: that is adding #TypeAlias("Student") to the entity Student, therefore you can place Student anywhere in your source code

Related

How to search in parent entity scope when using spring boot data rest

Now I know how to findBySomething on root level entity.
Let's say I have a one to many relation of class -> student
I can now students/search/findByName?name=Tom
But it will give me Tom in all classes. Can I do something like
classes/1/students/search/findByName?name=Tom
It gives error right now.
in StudentController
#GetMapping("/classes/{classId}/students/search/findByName")
public ResponseEntity<?> findStudent(#PathParam("name") String name,
#PathVariable("classId") String classId) {
return ResponseEntity.ok(studentService.findByNameAndClassId(name, classId));
}
in StudentService
public List<Student> findByNameAndClassId(String name, String classId) {
return studentRepository.findByNameAndClassId(name, classId);
}
in StudentRepository (I use mongoDB; if u use SQL , extends JpaRepository)
#Repository
public interface CustomUserRepo extends MongoRepository<Student, String> {
List<Student> findByNameAndClassId(String name, String classId);
}
As far as I understand,
You need to access the parent entity,
It can be easily achieved using HQL queries, please look below code.
#Query("select student from Student student where student.professor = ?1")
List<String> getProfessors(String[] professors);
I hope, it helps!

How can i fix output of Classes with relationship using Dtos in spring boot?

my class
public class Teacher
has ManyToMany relationship with Students :
public class Student
when i return teachers i want only their student ids , instead of full information about their students.
we have two Dtos (DataTransferObject) : StudentDto and TeacherDto with some variables.
what can i do to solve this problem?
I want Students as well to return only names or ids of Teachers. instead they return full dto list of teachers.
thanks.
In your TeacherDto you shouldn't have list of StudentDtos but rather list of Integer (if Integer is type of id). Than you should implement some mapping logic, for example in the constructor, like this:
public class TeacherDto {
private final Set<Integer> studentIds;
public TeacherDto(Teacher teacher) {
this.studentIds = teacher.getStudents().stream()
.map(Student::getId)
.collect(Collectors.toSet());
}
public Set<Integer> getStudentIds() {
return studentIds;
}
}
If you have many different DTOs, there is a lot of libraries which help you automate mapping between them.

How to using function postgres in UnitTest when using spring boot

I have a function auto generate student_no using PostgreSQL. It working perfect when I use it in Postgres and Spring boot. But I have a problem when I use it in unit tests. In Postgres when I use the following command:
Insert into students(firstName,lastName,age)
values ('Nguyen','Tran',12)
in database student_no auto generator look like "28372". It is the same with Spring boot. When I call method: studentRepository.save(student) it autogenerates student_no. But when I the following UnitTest:
#Slf4j
public class StudentTest {
#Mock
private StudentRepository studentRepository;
#Test
public void testGenerateStudentBooking_validRequest() {
Student student = new Student("Nguyen","Tran",23);
Student student = studentRepository.save(student);
}
}
When I save and debug, student_no isn't generated. I can't understand why?
class Student:
#Entity
#NoArgsConstructor
#RequiredArgsConstructor
public class Student {
#Id
private String id;
private String firstName;
private String lastName;
private Integer age;
private String student_no;
}
StudentRepository
public inteface StudentRepository extends CrudRepository(Student,Integer) {
Student findStudentByStudentNo(String StudentNo);
}
Student test
#Slf4j
public class StudentTest {
#Mock
private StudentRepository studentRepository;
#Test
public void testGenerateStudentBooking_validRequest() {
Student student = new Student("Nguyen","Tran",23);
Student student = studentRepository.save(student);
//Student.studentNo is null :(
Student student1 = studentRepository.findStudentByStudentNo(student.getStudentNo);
}
}
if possible how can I tell hibernate that booking_no will be automatically generated and hibernate will not do anything with it. Or in other words how to automatically generate booking_no using the function in Postgres when using UnitTest.
There are two ways to solve your problem
You can use H2 in memory database for integration testing, so you don't need to mock StudentRepository
Second way is mocking the StudentRepository the one you are following now.
The problem in second approach is you need to define the stubbing for mocked objects saying that whenever StudentRepository.save() method is called return student object with randomly generated id
#Slf4j
public class StudentTest {
#Mock
private StudentRepository studentRepository;
#Test
public void testGenerateStudentBooking_validRequest() {
Random random = new Random();
when(this.studentRepository(ArgumentMatchers.any()))
.thenReturn(new Student("Nguyen","Tran",23,random.nextInt(900) + 100 ));
//random.nextInt(900) + 100 will generate a random integer from 0 to 899, then add 100
Student student = new Student("Nguyen","Tran",23);
Student student = studentRepository.save(student);
You can also use ThreadLocalRandom to generate random int value between 100(including) and 1000 (excluding)
ThreadLocalRandom.current().nextInt(100, 1000);

Mapstruct: join on id

I am using Mapstruct to map from generated DTOs (metro, xsd) to our business domain objects. My difficulty is that the DTOs don't actually reference child objects but instead use IDs to reference associated instances.
Trying to break this down to a simplified case, I have come up with an example:
SchoolDTO has a lists of teachers and courses. The teacher of a
course is only referenced through a teacherId in each course.
In the business domain School only has a list of teachers who each
hold a list of their courses.
Class diagram: UML: DTO / Domain
Initially I was hoping to solve this in mapstruct syntax with something like a join on foreignId and teacher id (or some qualifiedBy association), pseudo code as follows:
#Mapping(source="courses", target="teachers.courses", where="teacher.id = course.teacherId")
DTOs:
public class SchoolDto {
List<TeacherDto> teachers;
List<CourseDto> courses;
}
public class TeacherDto {
String id;
String name;
}
public class CourseDto {
String name;
String teacherId;
}
Domain:
public class School {
List<Teacher> teachers;
}
public class Teacher {
String name;
List<Course> courses;
}
public class Course {
String name;
}
I am right now working around it with fairly big #AfterMapping methods but I feel this isn't such an exceptional use case - so maybe I am missing something rather obvious. What is the correct/intended way to solve these type of "joins" in a mapping with Mapstruct?
I doubt that you can do this without an #AfterMapping. MapStruct is "just" for mapping one object to another one, it doesn't support any kind of queries to find or join data.
If you are not already using it this sounds like a good use-case for using a context. Then the #AfterMapping is not really big:
#Mapper
public abstract class SchoolMapper {
public School toSchool(SchoolDto school) {
return toSchool( school, school.getCourses() );
}
protected abstract School toSchool(SchoolDto school, #Context List<CourseDto> courses);
#Mapping(target = "courses", ignore = true) // see afterMappingToTeacher
protected abstract Teacher toTeacher(TeacherDto teacher, #Context List<CourseDto> courses);
protected abstract Course toCourse(CourseDto course);
#AfterMapping
void afterMappingToTeacher(#MappingTarget target, TeacherDto source, #Context List<CourseDto> courses) {
// omitted null-checks
List<Course> courses = new ArrayList<>();
for(CourseDto course : courses) {
if(course.getTeacherId().equals(source.getId())) {
courses.add( toCourse(course) );
}
}
target.setCourses( courses );
}
}
(when using Java >= 8 you can use an interface with default methods)
In case you need to query things multiple times you can things create an own class as a context which for example has own methods for finding all courses by a teacher ID.

How does ORMlite manage inheritance between Java classes? [duplicate]

I'm trying to use inheritance with ORMLite and I can't work out if it is supported or not from looking at the documentation and googling.
What I want to do is have
public abstract class Person{
public int id;
public String name;
}
public class Student extends Person{
public String school;
public String year;
// other student stuff
}
public class Teacher extends Person{
public String title;
// other teacher stuff
}
What I can't work out (assuming it's supported) is how to annotate the 3 classes for ORMLite.
Do I only need to annotate the concrete classes with #DatabaseTable(tableName = "Student") or do I need the abstract class also?
I keep getting errors like:
04-24 10:18:30.857: E/AndroidRuntime(30495): Caused by: java.lang.RuntimeException: java.sql.SQLException: Unknown field 'name' from the Android sqlite cursor, not in:[year, school]
The #DatabaseTable annotation is only necessary on the Student or Teacher tables and would not be used if it was on the Person base class.
What you need to have is a #DatabaseField annotation on the id and name fields in Person. For example:
public abstract class Person{
#DatabaseField(generatedId = true)
public int id;
#DatabaseField
public String name;
}
ORMLite should walk the class hierarchy and any fields from the base class should be included in the Student and Teacher tables. If you edit your question to show the #DatabaseField or other annotations, I can comment more.
Ok for that but now, how to implements, in that example, a fourth class containing a List<AbstractPerson> ?
I precise my question :
public class ClassRoom {
#ForeignCollectionField(foreignFieldName="asYouWant")
public Collection<Person> peoples;
}
peoples.add(new Student());
peoples.add(new Teacher());
peoples.add(new Student());
because when ormlite will try to access peoples like :
for (Person person : classRoom.peoples)
{
if (person.getType() == Student)
//do stuff
else if (person.getType() == Student)
//do other stuff
}
It won't be able to get personDAO because it doesn't exist (abstract)...
I get all my database functionnal with good Id's and relation, it's just a data access question ?

Categories

Resources