I am writing query using In operator in spring boot using JPA
select * from data where name in ("XYZ","XY")
I am unable to implement DAO implementation for the following input in spring boot with JPA.
{"name":["XYZ","XY"]}
Controller
#PostMapping("/embdata/dto/name")
public List getByBatchIdsWithDTO(#RequestBody EmbDataDTO dto){
return service.getBatchIds(dto);
}
Service Method:
List<Data> obj=repo.findBybatchID(List<String> name)
Repo Interface:
List<Data> findByBatchIdIn(List wageId);
My entity Class
#Entity
#Data
#Table(name="data")
public class Data{
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
int id;
#Column(name="name")
String name;
#Column(name="address")
String address;
}
My DTO class:
#Data
public class EmbDataDTO {
private int id;
private String name;
private String address;
}
please help me to implement for the following input.
Your repo should look like :
#Repository
#Transactional
class YourRepo {
List<Data> findByBatchIdIn(List wageId) {
Query q = entityManager.createQuery("select * from data where name in (:list)");
q.setListParameter("list", wageId);
return q.execute();
}
}
At least something like that.
Related
I'm doing a spring boot experiment and using MySQL.
For example, if I have a list of users, but I want to get the specified names, how can I write the SQL query that only indicates this situation?
This is my model class :
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
#Column(name="first_name")
public String name;
#Column (name="last_name")
public String last_name;
}
This is my JPA interface :
public interface CommentRepository extends JpaRepository<User , Long >{
// All C.R.U.D database methods
}
Finally, my controller area is as below :
#RestController
#RequestMapping(path="/api/v1/users")
public class CommentController {
#Autowired
CommentRepository repository ;
#GetMapping(path="/list")
public List<User> users() {
return repository.findAll();
}
}
Maybe you didn't understand my problem, I just want to write a customizable query of my own.
For example, I want to pull the data with the method I designed, while I normally pull the data by numbers with the find by id method.
You can either use methods that will be translated into queries or write your queries in the #Query annotation.
Please read the docs: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories
I use Micronaut Data with JPA and have two entities. The first one is Recipe:
#Entity
public class Recipe {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
#ManyToOne
private Category category;
#OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Step> steps;
// + other fields, getters and setters
}
The second one is ParseError which refers to Recipe:
#Entity
#Table(name = "parse_error")
public class ParseError implements Serializable {
#Id
#ManyToOne(fetch = FetchType.LAZY)
private Recipe recipe;
#Id
#Enumerated(EnumType.ORDINAL)
#Column(name = "problem_area")
private ProblemArea problemArea;
private String message;
// + other fields, getters and setters
}
Now I would like to provide DTO in API with ParseError properties but not with whole Recipe entity because it contains ManyToOne and OneToMany relations which are not needed in this case. So I created projection DTO for that:
#Introspected
public class ParseErrorDto {
private Integer recipeId;
private String recipeName;
private ParseError.ProblemArea problemArea;
private String message;
// + getters and setters
}
And added listAll() method into ParseErrorRepository:
#Repository
public interface ParseErrorRepository extends CrudRepository<ParseError, Integer> {
List<ParseErrorDto> listAll();
}
But it seems that Micronaut Data is not able to project properties from nested entities or I missed something in the DTO or the repository method:
ParseErrorRepository.java:22: error: Unable to implement Repository
method: ParseErrorRepository.listAll(). Property recipeId is not
present in entity: ParseError
I also tried to create RecipeDto:
#Introspected
public class RecipeDto {
private Integer id;
private String name;
// + getters and setters
}
And updated ParseErrorDto accordingly:
#Introspected
public class ParseErrorDto {
private RecipeDto recipe;
private ParseError.ProblemArea problemArea;
private String message;
// + getters and setters
}
Again no success:
ParseErrorRepository.java:22: error: Unable to implement Repository
method: ParseErrorRepository.listAll(). Property [recipe] of type
[RecipeDto] is not compatible with equivalent property declared in
entity: ParseError
Is Micronaut Data able to handle this use case by DTO projection? If not then is there another way how can I solve it in Micronaut Data?
Now (in latest version 1.0.0.M1) it is not possible. So I created feature request issue for that: https://github.com/micronaut-projects/micronaut-data/issues/184
Current workaround is to map entity bean into DTO bean in Java stream or reactive stream for example and do the properties mapping manually or by Mapstruct.
Update: Here is an answer to question from comments with an example how to do the workaround using Mapstruct:
Add Mapstruct dependency into build.gradle:
implementation "org.mapstruct:mapstruct:$mapstructVersion"
annotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"
testAnnotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"
Define mapper:
import org.mapstruct.Mapper;
#Mapper(
componentModel = "jsr330"
)
public interface ParseErrorMapper {
ParseErrorDto entityToDto(#NotNull ParseError parseError);
EntityReference recipeToDto(#NotNull Recipe recipe);
}
And here is a usage of that mapper in the controller:
#Controller("/parse-error")
public class ParseErrorController {
private final ParseErrorRepository repository;
private final ParseErrorMapper mapper;
public ParseErrorController(ParseErrorRepository repository, ParseErrorMapper mapper) {
this.repository = repository;
this.mapper = mapper;
}
#Get("all")
#Transactional
public Page<ParseErrorDto> getAll(final Pageable pageable) {
return repository.findAll(pageable).map(mapper::entityToDto);
}
}
I have a two table Company and CompanyRepo like below
COMAPNY
COMPANY_REPO
I have entities for those two tables like this :
#Entity
#Table(name="COMAPNY")
public class Company implements Serializable {
#Id
#Column(name="COMPANY_ID")
private Long companyId;
#Column
private String companyName;
#OneToMany(mappedBy="COMPANY")
private List<CompanyRepo> companyRepo;
}
#Entity
#Table(name="COMAPNY_REPO")
public class CompanyRepo implements Serializable {
#Id
#Column(name="COMPANY_REPO_ID")
private Long companyRepoId;
#Column
private String COMPANY_ID;
#Column
private String DEPT_ID;
#ManyToOne
#JoinColumn(name="COMPANY_ID")
private Company company;
}
Now i want to execute below query using a Hibernate relationship mapping
select Company_name from company as C ,company_repo as cr where c.company_id=cr.company_id and dept_id=10
I wrote a JPA repository like below by using a #OneToMany in Company table and #ManyToOne in CompanyRepo. But in resultant I am getting multiple COMPANYobject inside COMPANY_REPO Object.Does my relationship mapping is correct ?
public interface CompanyRepository extends JpaRepository<CompanyRepo, Long> {
public CompanyRepo findByDeptId(Long deptId);
}
Given your current database design, try something such as the following:
public interface CompanyRepository extends JpaRepository<Company, Long> {
#Query(value="SELECT * from company as C WHERE c.company_id = (SELECT cr.company_id FROM company_repo as cr WHERE cr.dept_id = ?1)", nativeQuery=true)
public Company findByDeptId(Long deptId);
}
The #Query annotation is a very powerful and flexible way to define methods in Repository interface. If you need more complex logic, I would recommend reading about the use and possibilities of the annotation. See here.
Based on your entity class your have multiple
COMPANY_ID that is not a proper way to declare your column name.
#Column
private String COMPANY_ID;
#ManyToOne
#JoinColumn(name="COMPANY_ID")
private Company company;
So please change your #Column
private String COMPANY_ID; to #Column("comp_id)
private String companyId;
If you want to get the CompanyRepo based on Company type then you need to change your query to fetch the dept id.
And your #Column
private String DEPT_ID; is String datatype so pass String to your repository.
#Query(" select companyRepo.company from CompanyRepo as companyRepo where companyRepo.DEPT_ID = :deptId")
public Company findByDeptId(String deptId);
I have a little beginner's mistake in my project. I'm building a RESTful service with Spring Boot and my get method doesn't work.
I made an Entity called Project, that looks like this:
#Entity
#Table(name="project")
public class ProjectDto {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private long id;
#Column(name="caption")
private String caption;
..GETTERS AND SETTERS FOLLOW..
, than I created ProjectRepository like this:
#Repository
public interface ProjectRepository extends JpaRepository<ProjectDto, Long> {
public static final String GET_TIMELINE_PROJECT_CAPTIONS_QUERY = "SELECT
p.id, p.caption FROM ProjectDto p ORDER BY p.creationDate DESC";
#Query(GET_TIMELINE_PROJECT_CAPTIONS_QUERY)
public List<ProjectDto> getTimelineProjectCaptions();
}
..and a Controller
#RestController
#RequestMapping("/project")
public class ProjectController {
#Autowired
private ProjectRepository projectRepository;
#CrossOrigin(origins = "http://localhost:4200")
#RequestMapping(value = "/timeline", method = RequestMethod.GET)
public List<ProjectDto> getTimelineProjectCaptions() {
return projectRepository.getTimelineProjectCaptions();
}
}
but that gives[[5,"sddf"],[3,"asdf"],[2,"gb"],[1,"bg"]], which apparently isn't JSON
It is JSON. It's an array of arrays, which is what your query actually returns.
If you want an array of ProjectDto objects, the query should be
SELECT p FROM ProjectDto p ORDER BY p.creationDate DESC
Not sure why you're naming your entities with a Dto suffix. Entities are not DTOs. A DTO is a Data Transfer Object, i.e. an object specifically designed for data transfer.
You can use Projections.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.interfaces
If this is your Table
#Entity
#Table(name="project")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private long id;
#Column(name="caption")
private String caption;
#Temporal(TemporalType.DATE)
#Column(name="creationDate")
private Date creationDate;
// .. other columns ..
// ..GETTERS AND SETTERS FOLLOW..
Add an Interface-based projections
public interface ProjectCaption {
Long getId();
String getCaption();
}
Then add AS keyword on your query and change the return of your method
#Repository
public interface ProjectRepository extends JpaRepository<Project, Long>{
#Query("SELECT p.id AS id, p.caption AS caption FROM Project p ORDER BY p.creationDate DESC")
public List<ProjectCaption> getTimelineProjectCaptions();
}
You can try changing your method to something like this:
#RequestMapping(value = "/timeline", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<ProjectDto>> getTimelineProjectCaptions() {
return new ResponseEntity<List<ProjectDto>>(projectRepository.getTimelineProjectCaptions(), HttpStatus.OK);
}
Spring LdapRepository save() method throws exception when I'm trying to update an existing object in LDAP database.
org.apache.directory.api.ldap.model.exception.LdapEntryAlreadyExistsException: ERR_250_ENTRY_ALREADY_EXISTS
What method should I use to update existing ldap objects?
Person class:
#Entry(objectClasses = { "inetOrgPerson", "organizationalPerson", "person", "top" })
public class Person implements Serializable {
public Person() {
}
#Id
private Name dn;
#Attribute(name = "cn")
#DnAttribute(value = "cn")
#JsonProperty("cn")
private String fullName;
#Attribute(name = "uid")
private String uid;
private String mail;
#Attribute(name = "sn")
private String surname;
//setters and getters
}
Person repo interface:
public interface PersonRepo extends LdapRepository<Person> {
}
That's how I'm updating person:
personRepo.save(person);
Default implementation for Spring LDAP repositories is SimpleLdapRepository, that checks the property annotated with #Id to determine if the objects is new - and perform create, or old - and perform update.
I'm guessing that Person.dn is null when you're trying to perform update.
You also can take the control over this by implementing org.springframework.data.domain.Persistable and place your logic in the isNew() method.
See the implementation details.