How do you use a RepositoryItemWriter to delete objects - spring-boot

I have configured a RepositoryItemWriter so that I can use it to delete a number of products. Here is what my basic configuration looks like:
#Repository
public interface ProductRepository extends CrudRepository<Product, Integer>{
}
#Bean(name = "productRepositoryItemWriter")
RepositoryItemWriter<Product> productRepositoryWriter(ProductRepository repository) {
RepositoryItemWriter<Product> writer = new RepositoryItemWriter<Product>();
writer.setRepository(repository);
writer.setMethodName("deleteAllById");
return writer;
}
I am assuming I should call write on the product Ids. But I'm not sure if that's correct.
How should I use the repositoryItemWriter? Is the setMethod correct?

Related

Is there a way to override JPA saveAll method to used customized UPSERT query?

I am trying to override the JpaRepository saveAll method to use the custom UPSERT query in java SpringBoot. Is it possible?
As it's only one repository you can create a custom repository like this. I assume that the Entity name is User:
Your interface with only this saveAll Method
interface CustomizedUserRepository {
void savAllWithUpsert(Iterator<User> entities);
}
Then you have to implement the interface
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
public void savAllWithUpsert(Iterator<User> entities) {
// Your custom implementation
}
}
The most important part of the class name that corresponds to the fragment interface is the Impl postfix.
And finally use but all together:
interface UserRepository extends JpaRepository<User, Long>, CustomizedUserRepository {
}
Please also read the full docuementaion: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behavior
I used JdbcTemplate (NamedParameterJdbcTemplate)
//Bean
#Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
JdbcTemplate template = new JdbcTemplate(hikariDataSource);
template.setQueryTimeout(Integer.parseInt(queryTimeout));
return new NamedParameterJdbcTemplate(template);
}
Then
//Autowire NamedParameterJdbcTemplate
MapSqlParameterSource[] paramsArray =
mapperClass.mapDTOstoSqlParameterSource(items);
namedParameterJdbcTemplate.batchUpdate(SQL_qUERY, paramsArray);
Then
//Mapper class
public static MapSqlParameterSource[]
mapDTOstoSqlParameterSource(List<ItemDTO> items) {
List<MapSqlParameterSource> params = new ArrayList<>();
for (ItemDTO obj : items) {
MapSqlParameterSource source = new MapSqlParameterSource();
source.addValue("queryPara1", obj.getID());
source.addValue("queryPara2", obj.getSomething());
params.add(source);
}
return params.toArray(MapSqlParameterSource[]::new);
}

Querying mongodb collection SpringWebFlux with reactivemongodb

I am developing simple spring webflux demo application with reactive mongodb and i want to read all data of Employee by name except containing name field "joe","Sara","JOE","SARA" and i have following code like:
//repository interface
public interface EmployeeRepository extends ReactiveMongoRepository<Employee, String>{
Flux<Employee> findAllByName(String name);
}
//Service class
public class EmplyeeService
{
private EmployeeRepository employeeRepository;
public Flux<Employee> findAllByOrganizationName(String name)
{
return employeeRepository.findAllByName(name);
}
public Flux<String> getAllNameExceptSome(String name)
{
Employee emp1=new Employee();
List<Flux<Employee>> emp=Arrays.asList(employeeRepository.findAllByName(name));
Flux<Flux<Employee>> emp2=Flux.fromIterable(emp)
.filter(name->name.equalsIgnoreCase("joe"));
return emp2;
}
}
First of all, unless some particular situations, you should avoid these data structures:
List<Flux<Employee>>
Flux<Flux<Employee>>
However you are not leveraging Spring Data. You can achieve you result simply changing your repository to:
public interface EmployeeRepository extends ReactiveMongoRepository<Employee, String> {
// this find all Employee except those matching names provided as param
Flux<Employee> findAllByNameNotIn(List<String> nameList);
// this find all Employee matching names provided as param
Flux<Employee> findAllByNameIn(List<String> nameList);
}
Invoking this method you will obtain the list of Employee already filtered by name.

Spring - Access a Service interface programmatically

i have several interfaces which extend a single interface.
I need to add, during a #PostCostruct method, these interfaces to a Map.
The problem is that i need to retrieve the #Service class name from the DB and i don't know ho to put the interface in the map...
I'll try to explain it better
I have a general service interface
public interface IVehicleServiceGeneral{
//methods...
}
then i have several interfaces which extend the general one.
public interface IService1 extends IVehicleServiceGeneral{
}
public interface IService2 extends IVehicleServiceGeneral{
}
the concrete implementations of these classes are annotated with #Service("service1Name"), #Service("service2Name") and so on...
Then from the DB i retrieve my Suppliers
public class Supplier {
private long id;
private String serviceName;
//getters and setters
}
Finally i need to create the map, because i need to access the implementations at runtime based on the Supplier, i created a ContextAware class to get my beans by name, but the interfaces are not beans... I also tried to put the #Qualifier on the interface, but obviously it does not work... How can I put the interface in the map?
#PostConstruct
private void createServiceMap(){
serviceMap = new HashMap<OBUSupplier, IVehicleServiceGeneral>();
List<Supplier> suppliers = supplierService.findAll();
for(Supplier s : suppliers) {
serviceMap.put(s, contextAware.getBean(s.getServiceName()));
}
}
You can create IVehicleServiceGeneral instance map like this:
class SomeClass {
Map vehicleServiceGeneralInstanceMap = new HashMap();
SomeClass(Set<IVehicleServiceGeneral> instances) {
instances.forEach(i -> vehicleServiceGeneralInstanceMap.put(i.getServiceName(), i));
}
private void createServiceMap() {
Map serviceMap = new HashMap<OBUSupplier, IVehicleServiceGeneral>();
List<Supplier> suppliers = supplierService.findAll();
for(Supplier s : suppliers) {
serviceMap.put(s, vehicleServiceGeneralInstanceMap.get(s.getServiceName()));
}
}
The only thing you require is IVehicleServiceGeneral#getServiceName which your Service1, 2 need to override with proper names that present in DB.

Using QueryDslRepositorySupport in combination with interface repositories

since I didn't get a reply on the spring forum I'll give it a try here.
Is there a way to have a common interface repository which is extended by interfaces the following way:
#NoRepositoryBean
public interface CommonRepository<T> extends JpaRepository<T, Long>, QueryDslPredicateExecutor<T> {
T getById(final long id);
}
#Repository
public interface ConcreteRepository extends CommonRepository<ConcreteEntity> {
List<ConcreteEntity> getByNameAndAddress(final String name, final String address);
}
public class ConcreteRepositoryImpl extends QueryDslRepositorySupport implements ConcreteRepository {
private BooleanExpression nameEquals(final QConcreteEntity entity, final String name) {
return entity.eq(name);
}
public List<ConcreteEntity> getByNameAndAddress(final String name, final String address) {
QConcreteEntity entity = QConcreteEntity.concreteEntity;
return from(entity).where(entity.name.eq(name).and(entity.address.eq(address))).list(entity);
}
}
The problem with the implementation is that I have to implement getById(final long id)
in each concrete class. I don't want to do that. Normally, spring data automatically knows about each entity. Also I want to have the functionality of QueryDslRepositorySupport.
In my example it normally generates something like:
select .. from concreteentity en where en.id = ...
Is there a way to solve it? I already stumbled upon
Spring Jpa adding custom functionality to all repositories and at the same time other custom funcs to a single repository
and
http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations
but I don't think these solutions are helpful and I don't entirely understand how I can use them to solve the problem.
Thanks,
Christian
One way to create a generic getById under QuerydslRepositorySupport is like this
T getById(long id) {
return getEntityManager().find(getBuilder().getType(), id)
}

How to create count query on MongoRepository

I am creating a MongoRepository and need to create a count query. Can someone provide an example of what is the best way to do this via the SpringData MongoDB MongoRepository facility? All the examples I was able to find reference returning a List but not counts.
Here is what I am trying to do (obviously it does not work):
public interface SchoolRepository extends MongoRepository<School, String> {
#Query("db.school.count({studentStatus: ?0});")
int getCountOfStudents(int studentStatus);
}
Thanks.
-AP_
I found this question as I was trying to do something similar. Unfortunately, given what I see in org.springframework.data.repository.query.parser.PartTree:
private static final Pattern PREFIX_TEMPLATE = Pattern.compile("^(find|read|get)(\\p{Upper}.*?)??By");
It does not appear to be supported.
Instead, we can add custom behaviour to the repository (see reference manual section 1.4.1) by creating a new interface and a class that implements it.
public interface SchoolRepository extends CrudRepository<School, String>, SchoolRepositoryCustom {
// find... read... get...
}
public interface SchoolRepositoryCustom {
int getCountOfStudents(int studentStatus);
}
#Service
public class SchoolRepositoryImpl implements SchoolRepositoryCustom {
#Autowired
private SchoolRepository schoolRepository;
public int getCountOfStudents(int studentStatus) {
// ...
}
}
Note that the class is named SchoolRepositoryImpl, not SchoolRepositoryCustomImpl.

Resources