SpringData MongoDB Query on nested object and list object - java

I want to find a Type document by the code of job and by the list of code of category, i tried the below query but it didn't work
#Document
public class Type {
#Id
private String id;
#DBRef
private Job job;
#DBRef
private List<Category> categories;
}
public class Job {
#Id
private String id;
private String code;
}
public class Category {
#Id
private String id;
private String code;
}
public interface TypeRepository extends MongoRepository<Type, String> {
#Query("{ 'job.code': ?0, 'category.code': { $in: ?1 }}")
Type findByJobAndCategoriesCode(String codeJob, List<String> codeCategories);
}

try using this one
public interface TypeRepository extends MongoRepository<Type, String> {
Type findOneByJobCodeAndCategoriesCodeIn(String codeJob, List<String> codeCategories);
}

Related

How to map extended classes in MapStruct

Gotta question regarding mapStruct. I have case where I extend class from base entity and not sure how to map it. Here is my case.
BaseEntity:
public class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id")
private Long id;
}
BaseDto:
public class BaseDto {
private Long id;
}
UserEntity:
public class User extends BaseEntity {
private String name;
private String lastName;
private String username;
private String password;
private String profilePicturePath;
}
UserDto:
public class UserDto extends BaseDto {
private String name;
private String lastName;
private String username;
private String password;
private String profilePicturePath;
}
And mapper is like this:
#Mapper(uses = {BaseMapper.class})
public interface UserMapper {
User userDtoToUser(UserDto userDto);
UserDto userToUserDto(User user);
}
BaseMapper:
#Mapper
public interface BaseMapper {
BaseEntity dtoToEntity(BaseDto baseDto);
BaseDto entityToDto(BaseEntity baseEntity);
}
Problem is that I don't get ID property mapped.
Thank you for your time.
EDIT:
There is no error shown, in mapper implementation (generated code) there is no mapping for that ID:
#Override
public User userDtoToUser(UserDto userDto) {
if ( userDto == null ) {
return null;
}
UserBuilder user = User.builder();
user.name( userDto.getName() );
user.lastName( userDto.getLastName() );
user.username( userDto.getUsername() );
user.password( userDto.getPassword() );
user.profilePicturePath( userDto.getProfilePicturePath() );
return user.build();
}
I'm guessing (as you have not put buider code) the problem is that your builder class does not include parent class field. MapStruct makes some assumption while generating code for mapper. From documentation -
The default implementation of the BuilderProvider assumes the
following:
The type has a parameterless public static builder creation method
that returns a builder. So for example Person has a public static
method that returns PersonBuilder.
The builder type has a parameterless public method (build method)
that returns the type being build In our example PersonBuilder has a
method returning Person.
In case there are multiple build methods, MapStruct will look for a
method called build, if such method exists then this would be used,
otherwise a compilation error would be created.
If you are using Lombok, you can solve this by using #SuperBuilder as -
#SuperBuilder
#Getter
#ToString
public class UserDto extends BaseDto {
private String name;
private String lastName;
private String username;
private String password;
private String profilePicturePath;
}
#Getter
#SuperBuilder
class BaseDto {
private Long id;
}
#SuperBuilder
#Getter
#ToString
public class User extends BaseEntity {
private String name;
private String lastName;
private String username;
private String password;
private String profilePicturePath;
}
#Setter
#Getter
#SuperBuilder
class BaseEntity {
private Long id;
}
And generated could looks like -
#Override
public User userDtoToUser(UserDto userDto) {
if ( userDto == null ) {
return null;
}
UserBuilder<?, ?> user = User.builder();
user.id( userDto.getId() );
user.name( userDto.getName() );
user.lastName( userDto.getLastName() );
user.username( userDto.getUsername() );
user.password( userDto.getPassword() );
user.profilePicturePath( userDto.getProfilePicturePath() );
return user.build();
}

convert a DTO to Entity with using mapper class

I have a Entity class something like this:
#Entity
public class Website {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String url;
public Website() {
//Constructor
//getters and setters
}
here is the DTO class:
public class WebsiteDto {
private Integer id;
private String name;
private String url;
public WebsiteVo() {
//Constructor
//getters and setters
}
I have the WebsiteMapper something like this:
#Component
public class WebsiteMapper {
public List<WebsiteDto> getWebsiteList() {
return repository.findAll().stream().map(w -> {
WebsiteDto dto = new WebsiteVo(w.getId(), w.getName(), w.getUrl());
return dto;
}).collect(Collectors.toList());
I also have Repository Interface:
public interface WebsiteRepository extends JpaRepository<Website, Integer> {
}
I want now to convert DTO to entity using my class WebsiteMapper. Because I did the conversion in this class. How I can do it?
How about using BeanUtils provided by spring org.springframework.beans.BeanUtils, something like this
public List<WebsiteDto> getWebsiteList() {
return repository.findAll().stream().map(w -> {
WebsiteDto dto = new WebsiteVo();
BeanUtils.copyProperties(w, dto); // copys all variables with same name and type
return dto;
})
.collect(Collectors.toList());
}
Hi I guess you wish to converting your entity to DTO. It's quite simple. Create static methods in your DTO class or any util class. The return type should be your DTO type.
e.g.
public class WebsiteDto {
private Integer id;
private String name;
private String url;
public static WebsiteDto export(Website website) {
// Return a new instance of your website DTO
return new WebsiteDto(
website.getId(),
website.getName(),
website.getUrl()
);
}
public static List<WebsiteDto> export(List<Website> websites) {
// Return a new instance of your website DTO list
return websites.stream().map(website -> {
return new WebsiteDto(
website.getName(),
website.getUrl()
}).collect(Collectors.toList());
}
}
NOTE You can also convert your DTO to entity using similar method.

Spring Data JPA and Projection getting ConverterNotFoundException for TupleConverter

Is there a way to write and register a TupleConverter converter in Spring Data? I'm getting this exception when I have an #Query annotation in the Repository interface and asking for Projection.
The Interface:
public interface ProjectRepository extends JpaRepository<Project, Integer> {
#Query("select p.projectId, p.projectName, p.techstack from Project p")
public List<ProjectItem> findAllForTest();
}
The DTO:
public class ProjectItem {
private final Integer projectId;
private final String projectName;
private final String techstack;
#JsonCreator
public ProjectItem(
#JsonProperty("projectId") Integer projectId,
#JsonProperty("projectName") String projectName,
#JsonProperty("techstack") String techstack
) {
this.projectId = projectId;
this.projectName = projectName;
this.techstack = techstack;
}
public Integer getProjectId() {
return projectId;
}
public String getProjectName() {
return projectName;
}
public String getTechstack() {
return techstack;
}
}
The exception
No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [project.item.ProjectItem]] with root cause
Use a JPQL Constructor Expression:
#Query("select new com.company.path.to.ProjectItem(p.projectId, p.projectName, p.techstack) from Project p")
You're close. If you just want a DTO with a few of the items from the original item, just use the interface projection technique with methods having the same signatures as the Project class method items you want:
public interface ProjectTestSummary {
public Integer getProjectId();
public String getProjectName();
public String getTechstack();
}
And in your DAO:
public interface ProjectRepository extends JpaRepository<Project, Integer> {
public List<ProjectTestSummary> findAllProjectedBy();
}

Spring data repository projection findByEntity

That is the JPA entity MyEntity.
Entity
class MyEntity{
private Integer id;
private Date date;
private Double montant;
#ManyToOne(fetch = FetchType.LAZY)
private User creator;
}
class User {
private Integer id;
private String name;
private String image;
private Integer age;
private String anotherField;
}
I would like to retrieve a list of MyEntity with some attributes of its creator (just the id, the name and its image).
So I created a Projection interface.
interface Projection{
public Integer getId();
public Date getDate();
public Double getMontant();
public User getCreator();
interface User {
public Integer getId();
public String getName();
public String getImage();
}
}
here JPA repository implementation :
public interface CommandeRepository extends JpaRepository<EbCommande, Integer> {
<T> Collection<T> findById(Integer id, Class<T> type);
<T> Collection<T> findByCreator(User client, Class<T> type);
}
The first query works as I hope.
On the other hand with the second, when I loop on the list of MyEntity returned, each access to the User attribute triggers a request to the database fetching all the attributes of the User.
I do not understand how JPA projections work anymore.
Help please!

How to append custom data to ebean entity?

Suppose I have following class
#Entity
public class Customer extends Model {
#Id
public int id;
public String email;
#ManyToOne
public List<Order> orders;
public HashMap<String, Object> additionalData;
public static Finder<String, Customer> find = new Finder<String, Customer>(String.class, Customer.class);
public static List<Customer> getCustomersWithOpenOrders(){
return find
.fetch("orders")
// with "order.state = 'open'" count > 0
// add total sum of all orders to 'additionalData' collection
.findList();
}
}
How to store sum of all orders in additionalData collection?
Maybe you should take a look at the Formula annotation.
But for using this, you have to create a new property in order to store this value, then you can put this value in your map:
#Entity
public class Customer extends Model {
#Id
public Integer id;
public String email;
#ManyToOne
public List<Order> orders;
#Transient
#Formula(...) // write the query to compute the sum
public Integer totalOrders;
public HashMap<String, Object> additionalData;
public static Finder<Integer, Customer> find = new Finder<Integer, Customer>(Integer.class, Customer.class);
public static List<Customer> getCustomersWithOpenOrders(){
...// call the finder
additionalData.put("sum", totalOrders);
...
}
...
}

Categories