Hibernate Saves twice the same entity - java

I have three entities with bi-directional Many-To-One mapping:
#MappedSuperclass
#Getter
#Setter
abstract class Media {
#Id
#Column
#GeneratedValue(strategy = GenerationType.SEQUENCE)
protected Long id;
#Column(name = "imdb_id")
private String imdbId;
#Column(name = "api_movie_id")
private String apiMovieId;
#Column
private Long metadataItemIdentity;
#Column
protected String title;
#Column(name = "original_title")
protected String originalTitle;
#Column
protected String studio;
#Column
protected Double rating;
#Column(length = 500)
protected String description;
#Column(name = "content_rating")
protected String contentRating;
#Column
protected String genres;
#Column
protected String director;
#Column
protected Long duration;
#Column
protected String writer;
#Column
protected String stars;
#Column(name = "year_of_release")
protected Integer year;
#Column(name = "country_code")
protected String countryCode;
#Column(name = "is_ok")
protected boolean isOk = true;
#Column(name = "audio_lang")
protected String audioLanguage = "";
#Column(name = "sub_lang")
protected String subtitlesLanguage = "";
#Column(name = "api_name")
protected String apiName;
}
#Entity(name = "seasons")
#Getter
#Setter()
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Season {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column
protected Long id;
#Column
private Long metadataItemIdentity;
#ManyToOne
#JoinColumn(name = "fk_series")
private Series series;
#OneToMany(mappedBy = "season", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Episode> episodes;
private Integer number;
}
#Entity(name = "series")
#Getter
#Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Series extends Media {
#OneToMany(mappedBy = "series", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
List<Season> seasons;
}
And now the logic for saving:
#Service
#Slf4j
public class SeriesMigrateServiceImpl implements SeriesMigrateService {
private final SeriesService seriesService;
private final MetaDataItemRepository metaDataItemRepository;
private final ModelMapper modelMapper;
#Autowired
public SeriesMigrateServiceImpl(SeriesService seriesService,
MetaDataItemRepository metaDataItemRepository,
ModelMapper modelMapper) {
this.seriesService = seriesService;
this.metaDataItemRepository = metaDataItemRepository;
this.modelMapper = modelMapper;
}
#Override
public void migrateSeries() {
List<Series> allSeries = this.getAllSeriesFromSqlite();
allSeries.forEach(this::populateSeasons);
seriesService.saveSeries(allSeries);
}
private void populateSeasons(Series series) {
List<Season> allSeasons = this.getAllSeasonsForSeriesFromSqlite(series);
allSeasons.forEach(season -> season.setSeries(series));
allSeasons.forEach(this::populateEpisodes);
series.setSeasons(allSeasons);
}
private void populateEpisodes(Season season) {
List<Episode> allEpisodes = this.getAllEpisodesForSeasonFromSqlite(season);
allEpisodes.forEach(episode -> episode.setSeason(season));
season.setEpisodes(allEpisodes);
}
private List<Series> getAllSeriesFromSqlite() {
return metaDataItemRepository
.findAllSeries().stream()
.map(item -> this.convert(item, Series.class))
.collect(Collectors.toList());
}
private List<Season> getAllSeasonsForSeriesFromSqlite(Series series) {
return metaDataItemRepository
.findAllByParentIdentityAndMetadataType(series.getMetadataItemIdentity(), 3).stream()
.map(item -> this.convert(item, Season.class))
.collect(Collectors.toList());
}
private List<Episode> getAllEpisodesForSeasonFromSqlite(Season season) {
return metaDataItemRepository
.findAllByParentIdentityAndMetadataType(season.getMetadataItemIdentity(), 4).stream()
.map(item -> this.convert(item, Episode.class))
.collect(Collectors.toList());
}
private <T> T convert(MetaDataItem item, Class<T> classType) {
return modelMapper.map(item, classType);
}
}
What happens is that sometimes Hibernate saves twice the entities for example if i have 840 media files Hibernate saves 1680 ? And the thing that bothers me most is that sometimes works correctly sometimes doesn't ? Any suggestions?
*EDIT
#Service
public class SeriesServiceImpl implements SeriesService {
private final SeriesRepository seriesRepository;
#Autowired
public SeriesServiceImpl(SeriesRepository seriesRepository) {
this.seriesRepository = seriesRepository;
}
#Override
#Transactional
public List<Series> saveSeries(List<Series> series) {
return seriesRepository.save(series);
}
}

Related

Spring Boot Microservice Intellij don't work

Hi I’m new in SpringBoot and I created this microservice that doesn’t work.
when I try to run a get with postman I get this error ,can you help me?
"timestamp": "2022-09-29T15:24:02.783+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "org.springframework.data.crossstore.ChangeSetPersister$NotFoundException\r\n\tat com.poste.anagrafica.controller.UserController.listUserByRegistrationNumber(UserController.java:45)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:566)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:655)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:829)\r\n",
"message": "No message available",
"path": "/user/cerca/ciao"
}
I attach the classes
this is the database
the class entiy
#Entity
#Table(name = "USERS")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
public class User implements Serializable {
#Id
#Column(name = "user_id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "created_date")
private LocalDateTime createdDate;
#Column(name = "deleted", nullable = false)
private Long number;
#Column(name = "modified_date")
private LocalDateTime modifiedDate;
#Column(name = "birth_place")
private String birthPlace;
#Column(name = "birthday")
private Date birthDay;
#Column(name = "canNominate")
private Long canNominate;
#Column(name = "email")
private String email;
#Column(name = "firstName")
private String firstName;
#Column(name= "fiscalCode")
private String fiscalCode;
#Column(name = "hiringDate")
private Date hiringDate;
#Column(name ="last_name")
private String lastName;
#Column(name = "matricola")
private String matricola;
#Column(name = "position")
private String position;
#Column(name = "registration_number")
private String registrationNumber;
#Column(name = "replaced")
private Long replaced;
#Column(name = "terminationDate")
private Date terminationDate;
#Column(name = "user_status")
private String userStatus;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "application_role_id")
private Role applicationRoleID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "company_id")
private Company companyID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "direction_id")
private Direction directions ;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "level_id")
private Levels levelID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "referent_id")
private User referentID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "role_id")
private Role roleID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "task_id")
private EmployeeTask taskID;
}
the controller class, for configure the endpoint and the necessary method
#RestController
#RequestMapping("/user")
#Log
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
#Autowired
UserService userService;
#GetMapping(value = "/cerca/{registration_number}", produces = "application/json")
public ResponseEntity<UserDto> listUserByRegistrationNumber(#PathVariable("registration_Number") String registrationNumber)
throws ChangeSetPersister.NotFoundException
{
log.info("****** Ottengo l'user con numeroRegistrazione " + registrationNumber + " *******");
UserDto user = userService.SelByRegistrationNumber(registrationNumber);
if (user == null)
{
String ErrMsg = String.format("L'user con numeroRegistrazione %s non è stato trovato!", registrationNumber);
log.warning(ErrMsg);
throw new ChangeSetPersister.NotFoundException();
}
return new ResponseEntity<UserDto>(user, HttpStatus.OK);
}
}
the dto class
#Data
public class UserDto {
private Long userId;
private LocalDateTime createdDate;
private Long number;
private LocalDateTime modifiedDate;
private String birthPlace;
private Date birthDay;
private Long canNominate;
private String email;
private String firstName;
private String fiscalCode;
private Date hiringDate;
private String lastName;
private String matricola;
private String position;
private String registrationNumber;
private Long replaced;
private Date terminationDate;
private String userStatus;
private Role applicationRoleID;
private Company companyID;
private Direction directions ;
private Levels levelID;
private User referentID;
private Role role;
the repository class
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
#Query(value = "SELECT * FROM USERS WHERE REGISTRATION_NUMBER LIKE :registrationNumber", nativeQuery = true)
List<User> findByRegistrationNumberLike(#Param("registrationNumber") String registrationNumber);
User findByRegistrationNumber(String registrationNumber);
}
the service interface and serviceImpl
public interface UserService {
public Iterable<User> SelTutti();
public List<User> SelByRegistrationNumberLike(String registrationNumber);
public UserDto SelByRegistrationNumber(String registrationNumber);
}
#Service
public class UserServiceImpl implements UserService{
#Autowired
UserRepository userRepository;
#Autowired
ModelMapper modelMapper;
#Override
public Iterable<User> SelTutti() {
return userRepository.findAll();
}
#Override
public List<User> SelByRegistrationNumberLike(String registrationNumber) {
return userRepository.findByRegistrationNumberLike(registrationNumber);
}
#Override
public UserDto SelByRegistrationNumber(String registrationNumber) {
User user = userRepository.findByRegistrationNumber(registrationNumber);
UserDto userDto = null;
if (user != null)
{
userDto = modelMapper.map(user, UserDto.class);
userDto.setMatricola(userDto.getMatricola().trim());
userDto.setUserStatus(userDto.getUserStatus().trim());
}
return userDto;
}
and model map config
#Configuration
public class ModelMapConfig {
#Bean
public ModelMapper modelMapper(){
return new ModelMapper();
}
}
There is a typo in your controller:
//...
#GetMapping(value = "/cerca/{registration_number}", produces = "application/json")
public ResponseEntity<UserDto> listUserByRegistrationNumber(#PathVariable("registration_Number") String registrationNumber)
//...
Note: one time #PathVariable("registration_Number") is spelled with a capital 'N' and one time with lower case 'n': #GetMapping(value = "/cerca/{registration_number}"
Both must be the same.
Your mapping is:
/cerca/{registration_number}
So you have to call the microservices like this:
http://localhost:8080/cerca/<a valid registration number>

get API in spring boot with one to many relation

I have two models that are having one to many relation (customers have many invoices)
so i create one - many relation on it, this is my customer class :
#Entity
#Table(name = "customer")
public class Customer {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
private String email;
#Column(name = "mobile_number")
private String mobileNumber;
#Column(name = "is_deleted")
private boolean isDeleted;
#OneToMany
private Set <Invoice> invoices;
}
and this is invoices class :
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "status")
private String status;
#Column(name = "created_date")
private Timestamp createdDate;
#Column(name = "is_deleted")
private boolean isDeleted;
#ManyToOne
#JoinColumn(name = "customer_id")
private Customer customer;
}
and then i create GET API ( get customers ) but it's nor working and return this error :
nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.example.invoices.model.Customer["invoices"]), path=/customer/viewList}]
and this is my api :
public List<Customer> getAllCustomers() {
List<Customer> customers = cutomerRepository.findAll();
return customers;
}
and controller :
#GetMapping("/viewList")
public ResponseEntity<List<Customer>> getAllCustomers() {
List<Customer> customers = new ArrayList<>();
customers = customerService.getAllCustomers();
if (customers.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(customers, HttpStatus.OK);
}
You have a Bidirectional relation and therefore an endless loop if json tries to deserialize the Object.
You can use #JsonIgnore to break the loop or use DTOs to return at the endpoint
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "status")
private String status;
#Column(name = "created_date")
private Timestamp createdDate;
#Column(name = "is_deleted")
private boolean isDeleted;
#ManyToOne
#JsonIgnore
#JoinColumn(name = "customer_id")
private Customer customer;
}
DTO would look something like this (I like to use records for this but since I don't know if you use Java 17 I still use class):
Customer:
#Data
public class CustomerDTO {
private final int id;
private final long serialNumber;
private final String firstName;
private final String lastName;
private final String email;
private final String mobileNumber;
private final boolean isDeleted;
private final Set <Invoice> invoices;
public static CustomerDTO fromModel(Customer customer) {
return new CustomerDTO(
customer.getId(),
customer.getSerialNumber(),
customer.getFirstName(),
customer.getLastName(),
customer.getEmail(),
customer.getMobileNumber(),
customer.isDeleted(),
customer.getInvoices()
.stream()
.map(InvoiceDTO::fromModel)
.collect(Collectors.toSet())
);
}
}
Invoice (here you don't show the customer again):
#Data
public class InvoiceDTO {
private final int id;
private final String status;
private final Timestamp createdDate;
private final boolean isDeleted;
public static InvoiceDTO fromModel(Invoice invoice) {
return new InvoiceDTO(
invoice.getId(),
invoice.getStatus(),
invoice.getCreatedDate(),
invoice.isDeleted()
);
}
}
Controller:
#GetMapping("/viewList")
public ResponseEntity<List<CustomerDTO>> getAllCustomers() {
List<CustomerDTO> customers = new ArrayList<>();
customers = customerService.getAllCustomers()
.stream()
.map(CustomerDTO::fromModel)
.toList() //Depending on Java Version .collect(Collectors.toList());
if (customers.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(customers., HttpStatus.OK);
}
Do not open the entity class directly to the outside world
As DTO use for example:
public class InvoiceDTO {
private int id;
private long serialNumber;
private String status;
private Timestamp createdDate;
private boolean isDeleted;
private CustomerDTO customer;
}
See it applied in my GitHub repo FurnitureStoreApplication, example DTO classes in package dto:

MapStruct One to Many Relationship is not generated

I want to have a simple parent children relationship but somehow it does not work and I don't get what is missing.
Parent Mapper Interface (adding uses = {LayerMapper.class} does not change anything):
#Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
#DecoratedWith(MlpConfigMapperDecorator.class)
public interface MlpConfigMapper {
#Mapping(target = "epochNumber", source = "epochs")
#Mapping(target = "activationFunction", ignore = true)
MlpConfig toEntity(CustomMlpConfigRequest mlpConfigDto);
}
Parent decorator according to this answer (https://stackoverflow.com/a/60217018/10565504):
public abstract class MlpConfigMapperDecorator implements MlpConfigMapper {
#Autowired
#Qualifier("delegate")
private MlpConfigMapper delegate;
#Autowired
private ActivationFunctionService activationFunctionService;
#Override
public MlpConfig toEntity(CustomMlpConfigRequest mlpConfigDto) {
MlpConfig mlpConfig = delegate.toEntity(mlpConfigDto);
mlpConfig.setActivationFunction(activationFunctionService.findByType(mlpConfigDto.getActivationFunction()));
return mlpConfig;
}
}
The Parent DTO:
public class CustomMlpConfigRequest {
private String name;
private String description;
private int batchSize;
private int epochs;
private List<LayerDto> layers;
private String activationFunction;
}
The Child DTO:
public class LayerDto {
public String type;
public int orderNumber;
public int neuronsNumber;
}
Parent Entity:
public class MlpConfig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
private String description;
private int batchSize;
private int epochNumber;
#JoinColumn(nullable = false, name = "activationFunction_id")
#ManyToOne(fetch = FetchType.LAZY)
private ActivationFunction activationFunction;
#JsonManagedReference
#Column(nullable = false)
#OneToMany(mappedBy = "mlpConfig", cascade = CascadeType.ALL)
private List<Layer> layers;
#ManyToOne(fetch = FetchType.LAZY)
private User user;
private Date lastUpdated;
}
Child Entity:
public class Layer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private ELayer type;
private int neuronsNumber;
private int orderNumber;
#EqualsAndHashCode.Exclude
#ToString.Exclude
#ManyToOne(fetch = FetchType.LAZY, optional=false)
#JoinColumn(name = "mlpConfig_id", nullable=false)
#JsonBackReference
private MlpConfig mlpConfig;
}
Generated Child Entity Mapper Method (setChildren or setMlpConfig() in my case is missing):
#Override
public LayerDto layerToDto(Layer layer) {
if ( layer == null ) {
return null;
}
LayerDto layerDto = new LayerDto();
if ( layer.getType() != null ) {
layerDto.setType( layer.getType().name() );
}
layerDto.setOrderNumber( layer.getOrderNumber() );
layerDto.setNeuronsNumber( layer.getNeuronsNumber() );
return layerDto;
}
How do I get the mapper to set the parent in the child?
do you have Layer toEntity(LayerDto layerDto);
Also, on setter of layers on entity class, you should say, layers.forEach (layer -> layer.setmlpConfig(this));
Did you do that setting job? If you don't, layers of mplConfig entity can always be null when you try to get it.
In the end I fixed it myself. I don't know if it is best practice and probably the mapper should do it without manual help but at least it works:
public abstract class MlpConfigMapperDecorator implements MlpConfigMapper {
#Autowired
#Qualifier("delegate")
private MlpConfigMapper delegate;
#Autowired
private ActivationFunctionService activationFunctionService;
#Override
public MlpConfig mlpConfigToEntity(CustomMlpConfigRequest mlpConfigDto) {
MlpConfig mlpConfig = delegate.mlpConfigToEntity(mlpConfigDto);
mlpConfig.setActivationFunction(activationFunctionService.findByType(mlpConfigDto.getActivationFunction()));
//this is the difference. I set the config for the layer manually
mlpConfig.getLayers().forEach(e -> e.setMlpConfig(mlpConfig));
return mlpConfig;
}
}

Springboot How to query a many to many relationship

I have two entities lets call them Categories and Products. These two entities are mapped by a many to many relationship.
My problem is that i am trying to get category information from products. Trying this results in empty categories.
This is my code :
PersistenceEntity
#MappedSuperclass
public class PersistenceEntity implements Serializable {
private static final long serialVersionUID = 4056818895685613967L;
// Instance Variables
#Id
#Column(unique = true)
#GeneratedValue(strategy = GenerationType.TABLE)
protected Long id;
#JsonIgnore
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
protected Date creationDate = new Date();
...Getters and Setters omitted for brevity
}
Category
#Entity
#Table(name = "category")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Category extends PersistenceEntity{
private static final long serialVersionUID = 1L;
#Column(nullable = false)
private String categoryName;
#Column(nullable = false)
private Boolean active;
#Column(nullable = true)
private String picture;
#JsonIgnore
private MetaData metadata;
#ManyToMany(fetch = FetchType.EAGER,mappedBy = "categories")
private Set<Product> products;
...Getters and Setters omitted for brevity
}
Product
#Entity
#Table(name = "products",uniqueConstraints = { #UniqueConstraint(columnNames = "productCode")})
#JsonIgnoreProperties(ignoreUnknown = true)
public class Product extends PersistenceEntity {
private static final long serialVersionUID = 8727166810127029053L;
#Column(name = "product_name")
private String name;
private String productImageUrl;
#JsonIgnore
#ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
#JoinTable(name="category_products",
joinColumns={#JoinColumn(name="product_id", unique = false)},
inverseJoinColumns={#JoinColumn(name="category_id", unique = false)})
private Set<Category> categories;
...Getters and Setters omitted for brevity
}
ProductServiceImplementation
#Service
public class ProductService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private ProductRepository productRepository;
public List<Product> getProductsByShopId( Long id) {
List<Product> productList = new ArrayList<>();
productList = productRepository.findByShopId(id);
return productList;
}
public Set<Long> getCategoryIds(List<Product> products){
Set<Long> categoriesIDs = new HashSet<Long>();
for (Product product : products) {
product.getCategories().forEach(category -> {
categoriesIDs.add(category.getId());
});
}
return categoriesIDs;
}
}
The problem is getting the categoryIds that are mapped to the list of products.
How can i get CategoryIds from Product. My getCategoryIds function returns empty always
public Set<Long> getCategoryIds(List<Product> products){
Set<Long> categoriesIDs = new HashSet<Long>();
for (Product product : products) {
product.getCategories().forEach(category -> {
categoriesIDs.add(category.getId());
});
}
return categoriesIDs;
}

Child entity elements not persisting in one to many mapping with hibernate and spring data jpa

I have used spring boot with hibernate. And swagger to generate the dtos and the api interface.
There are two entities. The project entity is the parent and application entity is the child. Have create a onetomany relationship. But when i try to persist. I see not applications getting added for a project.
Project Entity:
#Entity
#Table(name="ProjectEntity")
public class ProjectEntity {
#Id
#Column(name = "ProjectGuid", length = 36, nullable = false, unique = true)
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name = "Name")
private String name;
#OneToMany(mappedBy="projectApp", cascade = CascadeType.ALL)
private List<ApplicationEntity> apps=new ArrayList<>();
public ProjectEntity() {
}
public ProjectEntity(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ApplicationEntity> getApps() {
return apps;
}
public void setApps(List<ApplicationEntity> apps) {
this.apps = apps;
}
}
Application Entity:
#Entity
#Table(name="ApplicationEntity")
public class ApplicationEntity {
#Id
#Column(name = "Name", length = 36, nullable = false, unique = true)
private String name;
private String repositoryUrl;
#ManyToOne
#Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
#JoinColumn(name = "ProjectGuid")
private ProjectEntity projectApp;
public ApplicationEntity() {
}
public ApplicationEntity(String name, String repositoryUrl) {
this.name = name;
this.repositoryUrl = repositoryUrl;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRepositoryUrl() {
return repositoryUrl;
}
public void setRepositoryUrl(String repositoryUrl) {
this.repositoryUrl = repositoryUrl;
}
public ProjectEntity getProjectApp() {
return projectApp;
}
public void setProjectApp(ProjectEntity projectApp) {
this.projectApp = projectApp;
}
}
Controller operation:
ProjectEntity project = projectService.getProject(projectName);
List<ApplicationEntity> appList = new ArrayList<>();
ApplicationEntity appEntity = new ApplicationEntity(app.getName(), app.getRepositoryUrl());
applicationRepository.save(appEntity);
appList.add(appEntity);
project.setApps(appList);
projectRepository.save(project);
You need to set the id of the ProjectEntity on the owning side (which is the ApplicationEntity)
appEntity.setProjectApp(project);
Otherwise hibernate (and your database) does not know to which parent a ApplicationEntity belongs.
Here is an example many to one relation with spring data jpa :
#Data
#MappedSuperclass
public class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
}
#Data
#Entity
public class Question extends BaseEntity{
private String questionText;
private int anketId;
private int subjectId;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "question")
List<Answer> answers;
}
#Data
#Entity
public class Answer extends BaseEntity{
private String answerText;
private String code;
private int score;
private int priority;
private boolean isValidAnswer;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "question_id", referencedColumnName = "id", insertable = false, updatable = false)
private Question question;
}
#DataJpaTest
public class QuestionRepositoryTest {
#Autowired
TestEntityManager entityManager;
#Autowired
QuestionRepository sut;
#Test
public void it_should_create_question_wiht_answers() {
Question question = new Question();
question.setSubjectId(1);
question.setAnketId(1);
question.setQuestionText("test question");
Answer answer = new Answer();
answer.setAnswerText("answer");
answer.setCode("1a");
answer.setPriority(0);
answer.setValidAnswer(true);
question.setAnswers(Arrays.asList(answer));
entityManager.persistAndFlush(question);
List<Question> questionList = sut.findAll();
assertThat(questionList).containsExactly(question);
assertThat(questionList.get(0).getAnswers().size()).isGreaterThan(0);
}
}

Categories

Resources