Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring repository auto casts entities with different class types

I'm using MongoRepository interface to extend my custom repositories for different entities. Now I faced with problem, let's assume an example: I have 2 entities:

@Document(collection = "person")
public class Employee {
    private String position;
}

and

@Document(collection = "person")
public class Manager {
    private String major;
}

repositories for both:

@Repository
public interface ManagerRepository extends MongoRepository<Manager, String> {}

and

@Repository
public interface EmployeeRepository extends MongoRepository<Employee, String> {}

Everything goes well when I saving 2 models:

{
    "_id" : ObjectId("5541f988d4c603ebac18a147"),
    "_class" : "com.igmtechnology.gravity.core.init.test.Manager",
    "major" : "majority"
}
{
    "_id" : ObjectId("5541f988d4c603ebac18a148"),
    "_class" : "com.igmtechnology.gravity.core.init.test.Employee",
    "position" : "developer"
}

But when I'm doing findAll() from one of repositories I'm getting 2 objects and one of them spring is automatically casting to another one. How can avoid this auto casting? Or how can specify which class I need to get?

like image 303
maxi Avatar asked Apr 30 '15 10:04

maxi


People also ask

What is difference between JpaRepository and CrudRepository?

CrudRepository provides CRUD functions. PagingAndSortingRepository provides methods to do pagination and sort records. JpaRepository provides JPA related methods such as flushing the persistence context and delete records in a batch.

What does @repository do in spring?

Spring @Repository annotation is used to indicate that the class provides the mechanism for storage, retrieval, search, update and delete operation on objects.

Can we use @repository in interface?

We don't. It is redundant to annotate the interfaces/classes with @Repository which extend/implement JpaRepository or some other predefined interfaces extending Repository , both because of @EnableJpaRepositories and the fact that they extend/implement Repository interface.

Is @repository mandatory in spring boot?

It is indeed not necessary to put the @Repository annotation on interfaces that extend JpaRepository ; Spring recognizes the repositories by the fact that they extend one of the predefined Repository interfaces.


1 Answers

For both of the repositories, you can use the @Query annotation to specify a MongoDB JSON query string that will be used instead of query derived from the method's name (you must know that there's a convention for parsing the repository's method names and for building MongoDB queries).

So, by using @Query, you can do:

@Repository
public interface ManagerRepository extends MongoRepository<Employee, String>

  @Query(value="{ '_class' : 'com.igmtechnology.gravity.core.init.test.Manager' }")
  List<Person> findAllManagers();

}

Behind the scenes, this will generate a query, similar to this one:

db.person.findAll({'_class' ; 'com.igmtechnology.gravity.core.init.test.Manager'});

However, there's a minor problem with this code. If you change the fully-qualified class name of Manager, then the query would not throw a RuntimeException, but would return nothing. In this case you can use a wildcard within the @Query.

@Query(value="{ '_class' : ?0 }")
List<Person> findAllManagers(String className);

Then, when you invoke the method, you can just do:

managerRepository.findAllManagers(Manager.class.getName());

The provided Manager.class.getName() will replace the ?0 wildcard and your query will built properly.

Same goes for the Employee repository with the difference that you have to provide the fully-qualified class name of Employee in the @Query's value attribute.

More info:

  • Spring-data MongoDB repositories
like image 107
Konstantin Yovkov Avatar answered Sep 29 '22 10:09

Konstantin Yovkov