Let's say I have an object that's being passed from some UI to my graphQL
class Person{
String name;
String age;
String address;
}
This is a preexisting user, and I was sent the name and the address, but not the age. Can I tell JPA "Hey, if you see a NULL field, please do not overwrite it, just ignore it and update the other fields"
#GraphQLMutation(name = "createPerson")
public List<Person> createPeople(#GraphQLArgument(name = "people") List<Person> people) {
return personDao.saveAll(people);
}
#Repository
public interface StrategyDAO extends JpaRepository<Strategy, Integer>{
#PleaseDontOverWriteNulls
void saveAll(List<Person>)
}
The annotation in my repository is representative of what would be great to have but which I haven't been able to find.
Related
Consider the entity below.
PS: The model has more fields but for the question to be short I have posted only the relevant fields
Class Employee {
private String name;
private String country;
private String region;
private String department
#OneToMany
private Set<Skill> skills;
}
Class Skill {
private name;
}
I am using spring boot Specification API to filter employees on different fields like region, country, and so on.
public class EmployeeSpec implements Specification<Employee> {
#Override
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
String fielName = //some field name
String fieldValue = //some field value
switch (fielName ) {
case "country":
return cb.equal(root.get("country"), fieldValue);
case "department":
return cb.equal(root.get("department"), fieldValue);
case "region":
return cb.equal(root.get("region"), fieldValue);
}
}
I want to order the results such that employee with maximum skills comes first. I am not sure how to implement this using Specification.
You can use CriteriaBuilder.size(..). For your case, the code will look like:
cq.orderBy(cb.desc(cb.size(root.get("skills"))));
I have a repository
public interface PersonRepository extends JpaRepository<Person, Long> {}
and the Entity looks like this:
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
public class Person {
#Id
private Long id;
#NotBlank
private String name;
}
I want to have a method which checks if all "persons" exist in database table by id, this what I have so far:
void checkIfAllPersonsExist(List<Long> personIds) {
var persons = personRepository.findAllById(personIds);
if (personIds.size() != persons.size()) {
personIds.removeAll(persons.stream().map(Persons::getId).collect(toList()));
throw new NotFoundException("Persons with id's [id:%s] does not exist", personIds);
}
}
I wonder if Spring JPA Repository can provide anything more elegant? Like specific named query which returns id's which does not exist?
If you want to just know that there are some ids that not exist you can count them
#Query("select COUNT(p.id) from Person p where p.id in :ids")
Long countIds(List<Long> ids);
Or equivalent based on
long countByIdIn(Collection<Long> ids);
Or return list of ids that exists
#Query("select p.id from Person p where p.id in :ids")
List<Long> getExistenIds(List<Long> ids);
And then filter out what you need.
personIds.removeAll(personRepository.getExistenIds(personIds));
if (!personIds.isEmpty()) {
throw new NotFoundException("Persons with id's [id:%s] does not exist", personIds);
}
First of all, your repository should extend JpaRepository<Person, Long> instead of JpaRepository<Person, String >, because your entity's id type is Long.
In and NotIn keywords can help you to achive your goal. Please check them out in this document: Query Creation - Spring Data JPA - Reference Documentation
I modified your code a little bit and it works for me.
Repository class:
public interface PersonRepository extends JpaRepository<Person, Long> {
List<Person> findByIdIn(Collection<Long> ids);
}
And sample snippet:
#Component
public class Bootstrap implements CommandLineRunner {
#Autowired
private PersonRepository repository;
#Override
public void run(String... args) throws Exception {
savePersons();
testFindMethod();
}
private void savePersons() {
Person person1 = Person.builder().id(1L).name("Name 1").build();
Person person2 = Person.builder().id(2L).name("Name 2").build();
Person person3 = Person.builder().id(3L).name("Name 3").build();
Person person4 = Person.builder().id(4L).name("Name 4").build();
repository.save(person1);
repository.save(person2);
repository.save(person3);
repository.save(person4);
}
private void testFindMethod() {
List<Long> toFind = new ArrayList<>();
toFind.add(1L);
toFind.add(2L);
toFind.add(3L);
checkIfAllPersonsExist(toFind);
toFind.add(7L);
checkIfAllPersonsExist(toFind);
}
void checkIfAllPersonsExist(List<Long> personIds) {
List<Person> persons = repository.findByIdIn(personIds);
if (personIds.size() != persons.size()) {
System.out.println("Sizes are different");
} else {
System.out.println("Sizes are same!");
}
}
}
And this is console output:
Sizes are same!
Sizes are different
I hope this will help you.
With this JPA repository method you can get the elements which ids doesn't exists:
List<Person> findByIdNotIn(List<Long> personIds);
If you want to remove them like in your example, you can use this one:
List<Person> deleteByIdNotIn(List<Long> personIds);
I hope it helps!
#Entity
public class A{
//some properties
}
#Entity
public class B{
//Some properties
}
I want to fetch selected columns from two tables using JPA, I know how to fetch single Entity table data through Repository and Controllers.
Repository:
public interface extends JPARepository<A, Long>{
List<A> findAll();}
Controller:
public class class_name{
#AutoWired
private JPARepository repo;
#RequestMapping("/data")
public List<A> getData(){
return repo.findAll();
}
}
Above code is to fetch single table data. Now, I want to fetch selected columns from both the tables.
Note: A, B Entities have mappings
What you can do is to use #Query annotation on one of your methods in the repository and performs something like this:
public Name {
String firstName;
String telephone;
public Name(String firstName,String telephon) {
//initialize fields
}
}
#Query(select new dummy.Name(u.name,c.telephone) from User u join fetch u.contact c where u.externalId= ?1 )
public Name getName(String externalId){}
You can return easily List instead of using constructor query , but i find it cleaner this way.
I have Spring Boot + DocumentDB application in which we need to implement a search API, The Search fields are part of nested Json are as below:
{
"id":"asdf123a",
"name":"XYZ",
add{
"city":"ABC"
"pin":123456,
}
}
I need to search with name="XYZ" and city="ABC", I'm trying with below code but somehow not able to retrieve the record.
But I'm able to retrieve with just by Name or ID, but not with name and city or just city which is part of nested JSON.
Employee{
private String id;
private String name;
private Address add
/*Getter and Setters {} */
}
Address{
private String city;
private Long pin;
/*Getter and Setters {} */
}
public class EmployeeController {
EmployeeRepository repository;
#Autowire
EmployeeController (EmployeeRepository repository){
this.repository = repository;
}
#GetMapping(value = "/search", produces = APPLICATION_JSON_VALUE_WITH_UTF8)
public ResponseEntity<?> Search (#RequestParam ("name")String name,
#RequestParam("city") String city){
return new ResponseEntity <> (repository
.findByNameLikeAndAddressCityLike(
name, city),
HttpStatus.OK
);
}
}
#Repository
public interface EmployeeRepository extends DocumentDbRepository<Employee,
String> {
Optional<Employee>findByNameLike(String name); // Perfectly working
Optional<Employee>findByAddressCityLike(String city); // Not working
Optional<Employee>findByNameLikeAndAddressCityLike(String name, String
city); // Not Working
}
Also Just like Spring JPA we use #Query to fire custom/ native query are there any DocumentDB Annotation present if so please guide me with example or Docuemnt. Looking for help
I have the following MongoDB Repository
public interface TeamRepository extends MongoRepository<Team, TeamId> {
....
}
And the following classes:
public abstract class DbId implements Serializable {
#Id
private final String id;
public DbId(final String id) { this.id = id;}
public String getId() { return id;}
}
public class TeamId extends DbId {
public TeamId(final String id) {
super(id)
}
}
As you can see, I have like a custom id for the repository (I have MongoRepository instead of something like MongoRepository). But, when I am trying to save a Team object, I get an error saying that MongoDB does not know how to generate DBId. Any clue?
MongoDb (or any database) would not know how to generate a string ID without you informing it what the value of the string is.
The default #Id is a string representation of ObjectId, which can be auto-generated by MongoDB. If you are changing the type of string ObjectId to a class, then at least the class needs to define:
** Conversion to string (serialisable), for example:
#Override
public String toString() {
return String.format(
"TeamID[uniqueString=%s]",
myUniqueString);
}
** How to generate the Id.
You can define a method in your TeamRepository i.e. save() to specify how your string can be generated. Alternatively you can check out
https://www.mkyong.com/mongodb/spring-data-mongodb-auto-sequence-id-example/
Where the example specify getNextSequenceId() to generate NumberLong custom id. Hopefully that guides you to your answer.