Spring Async breaks JPA - detached entity passed to persist - java

Using H2 and JPA my REST app worked well before Ansyc, but after implementation breaks the JPA persistence model.
Here is the case:
My repository has a method JpaRepository.save() but when called from a separate thread, it throws InvalidDataAccessApiUsageException error.
My Controller calls the Service which calls the Repository to insert a new object, and I get the following error:
InvalidDataAccessApiUsageException: detached entity passed to persist: TransactionalEntity; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: TransactionalEntity]
CONTROLLER:
#Autowired
#Qualifier("depositIntentService")
private TransactionIntentService depositIntentService;
#PostMapping("/services/transactions/deposit")
public CompletableFuture<ResponseEntity<TransactionIntent>> deposit(#Valid #RequestBody TransactionClientRequest request) {
CompletableFuture<TransactionIntent> depositIntentFuture =
transactionIntentFactory.createDepositIntent(
request.entity.id,
Money.of(CurrencyUnit.of(request.money.currency), request.money.amount));
return depositIntentFuture.thenApply(intent -> {
TransactionIntent publishedIntent = depositIntentService.attemptPublish(intent); //<-- causes error
ResponseEntity.ok(publishedIntent)
});
}
SERVICE:
#Component
#Repository
public abstract class TransactionIntentServiceImpl implements TransactionIntentService{
#Autowired
private TransactionIntentRepository transactionIntentRepo;
#Transactional
public TransactionIntent attemptPublish(TransactionIntent intent){
transactionIntentRepo.save(intent); //<-- Throws error: ...detached entity passed to persist
}
}
REPOSITORY
#Repository
public interface TransactionIntentRepository extends JpaRepository<TransactionIntent, Long>{
}
Any ideas how to support JPA persistance in an Async environment?
Thanks!
Update1
FACTORY
#Component
public class TransactionIntentFactory {
#Autowired
private UserService userService;
#Async("asyncExecutor")
public CompletableFuture<TransactionIntent> createDepositIntent(long beneficiaryId, Money money) {
CompletableFuture<User> bank = userService.findByUsername("bankItself#bank.com");
CompletableFuture<User> user = userService.find(beneficiaryId);
CompletableFuture<Void> allUserFutures = CompletableFuture.allOf(bank, user);
return allUserFutures.thenApply(it -> {
User userSource = bank.join();
User userBeneficiary = user.join();
TransactionIntent intent = new TransactionIntentBuilder()
.status(new TransactionIntentStatus(TRANSFER_STATUS.CREATED, "Deposit"))
.beneficiary(userBeneficiary)
.source(userSource)
.amount(money)
.build();
return intent;
});
}
}
ENTITY
#Entity
public class TransactionIntent {
#Id
#GeneratedValue
public long id;
public final Money amount;
public final Date createdAt;
#OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionIntentStatus status;
#OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity beneficiary; //to
#OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
public final TransactionalEntity source; //from
TransactionIntent(){
this.amount= null;
this.createdAt = null;
this.status = null;
this.beneficiary = null;
this.source = null;
}
public TransactionIntent(TransactionIntentBuilder builder) {
this.amount = builder.amount;
this.createdAt = new Date();
this.status = builder.status;
this.beneficiary = builder.beneficiary;
this.source = builder.source;
}
}

Related

repoistory.save() getting invoked with invalid entry when unit testing

I'm using java validation API to validate fields in my Note class:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "note")
public class Note {
#Id
#Column(name = "id", nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "date", columnDefinition = "DATE")
private LocalDate date;
#NotBlank(message = "Enter a topic")
#Column(name = "topic")
private String topic;
#NotBlank(message = "Content can't be empty")
#Column(name = "content")
private String content;
#Column(name = "type")
private NoteType noteType;
#NotNull
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinColumn(name = "user_id")
#JsonIgnore
private User user;
}
NoteService:
#Service
#AllArgsConstructor
public class NoteService {
#Autowired
private NoteRepository noteRepository;
#Autowired
private UserRepository userRepository;
public void addNote(#Valid Note note) {
note.setUser(getLoggedInUser());
if (validateNote(note)) {
noteRepository.save(note);
}
}
public List<Note> getNotes() {
return getLoggedInUser().getNotes();
}
public Note editNote(Note newNote, Long id) {
noteRepository.editNoteById(newNote, id);
return newNote;
}
public List<Note> getNotesByTopic(String topic) {
List<Note> notes = noteRepository.getNotesByTopicAndUser(topic, getLoggedInUser());
return notes;
}
public boolean validateNote(Note note) {
return validateNoteType(note.getNoteType())
&& note.getDate() != null;
}
public boolean validateNoteType(NoteType type) {
return type.equals(NoteType.NOTE)
|| type.equals(NoteType.SKILL);
}
public User getLoggedInUser() {
return userRepository.findByEmail(SecurityContextHolder.getContext().getAuthentication().getName());
}
}
Test:
#ExtendWith(MockitoExtension.class)
#ExtendWith(SpringExtension.class)
class NoteServiceTest {
#Mock
private NoteRepository noteRepositoryMock;
#Mock
private UserRepository userRepositoryMock;
#Mock
SecurityContext mockSecurityContext;
#Mock
Authentication authentication;
private NoteService noteService;
#BeforeEach
void setUp() {
noteService = new NoteService(noteRepositoryMock, userRepositoryMock);
Mockito.when(mockSecurityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(mockSecurityContext);
}
#Test
void shouldAddNote() {
LocalDate date = LocalDate.now();
Note note = new Note(0L, date, "test", "", NoteType.NOTE, null);
noteService.addNote(note);
Mockito.verify(noteRepositoryMock).save(note);
}
}
The field user in the Note class is annotated with #NotNull and I'm passing a null user to this note but the note is still getting saved. Same thing when I pass an empty string. Any idea why that is happening? I'm new to unit testing
I'm new to unit testing - your perfectly valid question has nothing to do with unit testing.
#NotNull does nothing on it own. Its actually a contract stating the following:
A data member (or anything else annotated with #NotNull like local variables, and parameters) can't be should not be null.
For example, instead of this:
/**
* #param obj should not be null
*/
public void MyShinyMethod(Object obj)
{
// Some code goes here.
}
You can write this:
public void MyShinyMethod(#NotNull Object obj)
{
// Some code goes here.
}
P.S.
It is usually appropriate to use some kind of annotation processor at compile time, or something that processes it at runtime. But I don't really know much about annotation processing. But I am sure Google knows :-)
You need to activate validation on you service class with the #Validated annotation so the validation of parameters kicks in.
#Service
#AllArgsConstructor
#Validated
public class NoteService {
...
See Spring #Validated in service layer and Spring Boot: How to test a service in JUnit with #Validated annotation? for more details.
If for some reason you need to manually perform the validation you can always do something like this:
#Component
public class MyValidationImpl {
private final LocalValidatorFactoryBean validator;
public MyValidationImpl (LocalValidatorFactoryBean validator) {
this.validator = validator;
}
public void validate(Object o) {
Set<ConstraintViolation<Object>> set = validator.validate(o);
if (!set.isEmpty()) {
throw new IllegalArgumentException(
set.stream().map(x -> String.join(" ", x.getPropertyPath().toString(), x.getMessage())).collect(
Collectors.joining("\n\t")));
}
}
}
So your noteRepository is Mocked, so you it's not actually calling save on your repository.
Mockito.verify(noteRepositoryMock).save(note);
All you are verifying here is that a call to save is made, not that it was successful.

Facing exception HibernateException: identifier of an instance of <Class> was altered from <old> to <new> spring

I'm using spring with lombok and mapstruct and postgresSQL.
I'm facing an error on a udirectional #ManyToOne relationship on Parent / Child relationship, with my class Client
Here is my Client class :
#Getter
#Setter
#Table(name = "client")
public class Client extends AbstractEntity {
private String name;
#ManyToOne(cascade = CascadeType.ALL)
private Address address;
private boolean headOffice;
#ManyToOne(cascade= CascadeType.ALL)
#JoinColumn(name="client_parent_id")
public Client clientParent;
}
Here is my abstractEntity to generate Id and some data:
#MappedSuperclass
#Getter
#Setter
#RequiredArgsConstructor
public class AbstractEntity {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
private String id;
#CreationTimestamp
private Timestamp createdDate;
#UpdateTimestamp
private Timestamp modifiedDate;
}
Here is my client Service :
#Service
public class ClientService {
private final ClientRepository clientRepository;
private final ClientMapper clientMapper;
ClientService(ClientRepository clientRepository, ClientMapper clientMapper) {
this.clientRepository = clientRepository;
this.clientMapper = clientMapper;
}
Client getClient(String id) throws FunctionalException {
return this.clientRepository.getById(id)
.orElseThrow(
() -> new FunctionalException("Client not found")
);
}
public ClientDto createOrUpdateClient(ClientDto clientDto, String id) throws FunctionalException {
Client client;
if (id == null) {
verifyInExistence(clientDto);
client = this.clientMapper.toEntity(clientDto);
} else {
client = this.getClient(id);
this.clientMapper.updateClientFromDto(clientDto, client);
}
verifyParent(client, clientDto.getClientParentId());
return this.clientMapper.toDto(this.clientRepository.save(client));
}
private void verifyParent(Client client, String parentId) {
if (parentId != null) {
client.setClientParent(this.getClient(parentId));
} else {
client.setClientParent(null);
}
}
private void verifyInExistence(ClientDto clientDto) throws FunctionalException {
clientRepository.findByName(clientDto.getName()).ifPresent(s -> {
throw new FunctionalException(String.format("Client '%s' already exist", clientDto.getName()));
});
}
}
And my Rest Controller :
#RestController
#RequestMapping(path = "/api/client")
public class ClientResource {
private final ClientService clientService;
ClientResource(ClientService clientService) {
this.clientService = clientService;
}
#PostMapping
ClientDto addClient(#RequestBody ClientDto clientDto) throws FunctionalException {
return this.clientService.createOrUpdateClient(clientDto, null);
}
#PutMapping(path = "/{id}")
ClientDto updateClient(#PathVariable String id, #RequestBody ClientDto clientDto) throws FunctionalException {
return this.clientService.createOrUpdateClient(clientDto, id);
}
}
When i'm posting a new client with a parent or without a parent it's okay, all goes right.
But when I try to update (by using put in clientResource) in order to remove relationship between a child and parent entity I have an Hibernate Exception like this :
HibernateException: identifier of an instance of xxxx.model.Client was altered from 7fa60bf2-e176-4b96-aae4-cbfa6461cb0e to null
I read a lot of post but i'm not in the case my Id are well generated i just don't understand why i can't set null to parent to define a chil without parent. I tried also to add childrens as OneToMany but didn't understand the need to do this.
Thanks a lot for all your reponse ! :) And sorry for the bad english.
The error message indicates that the id value of the entity Client is being changed to null. This is most likely happening in this line:
this.clientMapper.updateClientFromDto(clientDto, client);
When doing an update on an existing object, you should not change its id (see this). Either you need to make sure the clientDto does not have a null id value, or you need to exclude setting the id of client from the clientDto.
Another note: if you're using generated identifier values (#GeneratedValue(generator = "UUID")) then it may be a good idea to remove the setter on the id field, because the value will be generated automatically:
#Setter(AccessLevel.NONE)
private String id;

Trigger #OneToMany lazy fetch

I have an ExampleRequest entity that can optionally have one or more ExampleRequestYear. It's currently configured this way (unrelated fields and gettters/setters omitted for brevity, please let me know if you need anything else):
#Entity
#Table(name = "EXAMPLE_REQUEST")
#SequenceGenerator(name = "EXAMPLE_REQUEST_ID_SEQ", sequenceName = "EXAMPLE_REQUEST_ID_SEQ", allocationSize = 1)
#Cacheable(false)
public class ExampleRequest implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "EXAMPLE_REQUEST_ID_SEQ")
#Column(name="EXAMPLE_REQUEST_ID", nullable = false)
private Long exampleRequestId;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "exampleRequest")
private List<ExampleRequestYear> exampleRequestYearList;
public ExampleRequest() {
}
public List<ExampleRequestYear> getExampleRequestYearList() {
if(this.exampleRequestYearList == null){
this.exampleRequestYearList = new ArrayList<ExampleRequestYear>();
}
return this.exampleRequestYearList;
}
public void setExampleRequestYearList(List<ExampleRequestYear> exampleRequestYearList) {
this.exampleRequestYearList = exampleRequestYearList;
}
public ExampleRequestYear addExampleRequestYear(ExampleRequestYear exampleRequestYear) {
getExampleRequestYearList().add(exampleRequestYear);
exampleRequestYear.setExampleRequest(this);
return exampleRequestYear;
}
public ExampleRequestYear removeExampleRequestYear(ExampleRequestYear exampleRequestYear) {
getExampleRequestYearList().remove(exampleRequestYear);
exampleRequestYear.setExampleRequest(null);
return exampleRequestYear;
}
}
#Entity
#Table(name = "EXAMPLE_REQUEST_YEAR")
#IdClass(ExampleRequestYearPK.class)
public class ExampleRequestYear implements Serializable {
#Id
#Column(nullable = false)
private Integer year;
#Id
#ManyToOne
#JoinColumn(name = "EXAMPLE_REQUEST_ID", referencedColumnName = "EXAMPLE_REQUEST_ID")
private ExampleRequest exampleRequest;
public ExampleRequestYear() {
}
public void setExampleRequest(ExampleRequest exampleRequest) {
this.exampleRequest = exampleRequest;
}
public ExampleRequest getExampleRequest() {
return exampleRequest;
}
}
Part of the code was auto-generated by the IDE and I'm still wrapping my head around JPA so there're probably design mistakes all around.
My app works (apparently) when I create a new ExampleRequest:
ExampleRequest exampleRequest = new ExampleRequest();
ExampleRequestYear exampleRequestYear = new ExampleRequestYear(2020);
request.addExampleRequestYear(exampleRequestYear);
However, I can't figure out how to edit an existing ExampleRequest because I'm unsure on how I'm meant to retrieve the linked entities. According to articles I've read, lazy fetching should be automatic, yet when I try this:
ExampleRequest exampleRequest = employeeRequestsController.getExampleRequestById(123);
System.out.println(exampleRequest.getExampleRequestYearList().size());
... I get a null pointer exception upon .size() because the getter runs but neither initialises an empty list, nor retrieves items from DB:
public List<ExampleRequestYear> getExampleRequestYearList() {
if(this.exampleRequestYearList == null){
// Field is null and conditional is entered
this.exampleRequestYearList = new ArrayList<ExampleRequestYear>();
// After initialisation, field is still null!
}
return this.exampleRequestYearList;
}
Also, switch to FetchType.EAGER solves this particular problem entirely. What am I missing?
Further details regarding app design. The Resource classes that handle HTTP requests interact with a set of Controller classes like this:
#Stateless(name = "ISomeActionController", mappedName = "ISomeActionController")
public class SomeActionController implements ISomeActionController {
#EJB
private IFooDAO fooDao;
#EJB
private IBarDAO barDao;
#Override
public ExampleRequest getExampleRequestById(Long exampleRequestId) {
return fooDao.getEntityById(exampleRequestId);
}
}
It's in the DAO classes where EntityManager is injected an used:
#Local
public interface IGenericDAO<T> {
public T persistEntity(T o);
public T persistEntityCommit(T o);
public void removeEntity(T o);
public void removeEntity(long id);
public T mergeEntity(T o);
public List<T> getEntitiesFindAll();
public List<T> getEntitiesFindAllActive();
public T getEntityById(Object id);
}
public interface IFooDAO extends IGenericDAO<ExampleRequest> {
public void flushDAO();
public ExampleRequest getExampleRequestById(Long exampleRequestId);
}
#Stateless(name = "IFooDAO", mappedName = "IFooDAO")
public class FooDAO extends GenericDAO<ExampleRequest> implements IFooDAO {
public FooDAO() {
super(ExampleRequest.class);
}
#Override
public void flushDAO(){
em.flush();
}
#Override
public ExampleRequest getExampleRequestById(Long exampleRequestId){
String sql = "...";
Query query = em.createNativeQuery(sql, ExampleRequest.class);
//...
}
}

Hibernate #Formula returns an old value in PUT response

My Spring boot app has 2 Entities - Document and Card. Card has column dtFrom. Clients have to work with column daysOnDtConfirm (Document.dtConfirm - dtFrom). Annotation #Formula for GET requests works great, but in PUT response returns an old value of daysOnDtConfirm. How return a new value?
#Entity
#Table(name="document")
public class Document extends BaseEntity{
private String name;
#Column(name = "dt_confirm")
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
#JsonFormat(shape = JsonFormat.Shape.STRING)
private LocalDateTime dtConfirm ;
#Column(name = "contragent_name")
private String contragentName;
....
//CARD
#OneToMany(mappedBy="document" , fetch = FetchType.EAGER)
private List<Card> cards = new ArrayList<Card>();
public List<Card> getCards() {
if (this.cards == null) {
this.cards = new ArrayList<Card>();
}
return this.cards;
}
public void setCard(Card card) {
getCards().add(card);
card.setDocument(this);
}
public int getNrOfCards() {
return getCards().size();
}
....
}
And
#Entity
#Table(name="card")
public class Card extends BaseEntity {
#ManyToOne
#JsonIgnore
#JoinColumn(name = "document_id")
private Document document;
private String name;
private double quantity;
#Column(name = "dt_from")
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
#JsonIgnore
private LocalDate dtFrom ;
#Formula("(select IFNULL(DATEDIFF(Document.dt_confirm , dt_from), 0) from
Document where Document.id = document_id )")
private int daysOnDtConfirm;
...
public void setDtFrom(LocalDate dtFrom) {
this.dtFrom = dtFrom;
}
public void setDtFrom(int daysOnDtConfirm) {
if (this.document.getDtConfirm() != null){
LocalDate dateTo = this.document.getDtConfirm().toLocalDate();
this.dtFrom = dateTo.minusDays(daysOnDtConfirm);
}
}
...
}
Service :
#Service
public class DocumentServiceImpl implements DocumentService {
#Autowired
DocumentRepository documentRepository;
#Autowired
CardRepository cardRepository;
...
#Override
#Transactional
public void changeCard(Document document, Card card) {
//IF ID is NULL then isNew==true!!!!
if (card.isNew()){
card.setDocument(document);
card.setDtFrom(card.getDaysOnDtConfirm());
document.setCard(card);
cardRepository.saveAndFlush(card);
}
else{
Card cardEdit = cardRepository.findOne(card.getId());
if (cardEdit != null) {
cardEdit.setDocument(document);
cardEdit.setName(card.getName());
cardEdit.setUnit(card.getUnit());
cardEdit.setQuantity(card.getQuantity());
//cardEdit.setDtFrom(card.getDtFrom());
cardEdit.setDtFrom(card.getDaysOnDtConfirm());
cardEdit.setDescription(card.getDescription());
cardRepository.saveAndFlush(cardEdit);
}
}
#Override
#Transactional
public Document changeDocumentAndCards(Document document) {
Document documentEdit = changeDocument(document);
List<Card> cards = document.getCards();
//check if the same rows in DB and Client, DELETE difference
deleteCardsFromDocument(document);
//if not empty received from client rows then change
if (!cards.isEmpty()) {
for (Card card : cards) {
changeCard(documentEdit, card);
}
}
return documentEdit;
}
...
}
RestController:
#RestController
#RequestMapping("/api/docs")
public class DocController {
#Autowired
DocumentService documentService;
#RequestMapping(value = "",
method = RequestMethod.GET,
produces = {"application/json", "application/xml"})
#ResponseStatus(HttpStatus.OK)
public #ResponseBody
List<Document> getAllDocument(HttpServletRequest request, HttpServletResponse response) {
List<Document> list = new ArrayList<>();
Iterable<Document> documents = this.documentService.getDocumentAll();
documents.forEach(list::add);
return list;
}
....
#RequestMapping(value = "/{id}",
method = RequestMethod.PUT,
consumes = {"application/json", "application/xml"},
produces = {"application/json", "application/xml"})
#ResponseStatus(HttpStatus.OK)
public Document updateDocument(//#ApiParam(value = "The ID of the existing Document resource.", required = true)
#PathVariable("id") Long id,
#RequestBody Document document,
HttpServletRequest request, HttpServletResponse response) {
Document documentEdit = documentService.changeDocumentAndCards(document);
return documentEdit;
}
...
}
The issue seems to come from the changeDocument(Document document) method. The return value of saveAndFlush() call should be assigned back to documentEdit
UPDATE
The issue is that hibernate will not re-calculate the #Formula field after it is updated. It just fetches it from cache.
The only way I managed to get this working on my machine was to refresh the card entity after updating it. For that to work I needed to add an entity manager in the service class.
In your DocumentServiceImpl (actually could be any service class) class add the following:
public class DocumentServiceImpl implements DocumentService {
//...
#PersistenceContext
private EntityManager em;
#Transactional
public void refreshEntity(Object entity) {
em.refresh(entity);
}
Then, you should call this refreshEntity() method after an update, so that hibernate doesn't fetch it from cache.
This way it worked for me. Hope it helps you.

Can't remove entity with JPA

I'm trying to remove an entity from memory (at the moment I don't use DB) with JPA, when I use remove and then try to find the deleted entity it shows null, but when I use findAll method it retrieve all data (with removed entity)...
Profile.java
#Entity
#Table(name = "profile")
public class Profile {
#Id
#GeneratedValue
private Long id;
private String nombre;
private Boolean restrictedAccess;
private Boolean canValidate;
// private Set<AccessField> accessFields = new HashSet<AccessField>();
// private Set<AccessEntity> accessEntities = new HashSet<AccessEntity>();
#OneToMany(mappedBy = "profile", fetch = FetchType.EAGER)
private Set<AccessMenu> menuSections = new HashSet<AccessMenu>();
#OneToMany(mappedBy = "profile", fetch = FetchType.EAGER)
private Set<User> users = new HashSet<User>();
[getters and setters]
ProfileRepository
#Repository
#Transactional
public class ProfileRepository {
#PersistenceContext
private EntityManager entityManager;
public Profile save(Profile p) {
p = this.entityManager.merge(p);
this.entityManager.flush();
return p;
}
public void delete(Long id){
Profile profile = this.entityManager.find(Profile.class, id);
this.entityManager.remove(profile);
}
public List<Profile> findAll() {
CriteriaQuery cq = this.entityManager.getCriteriaBuilder().createQuery();
cq.select(cq.from(Profile.class));
return (List<Profile>) this.entityManager.createQuery(cq).getResultList();
}
public Profile findById(Long id){
return this.entityManager.find(Profile.class, id);
}
}
Controller method
#RequestMapping(value="profile/delete/{idProfile}", method = RequestMethod.GET)
public String delete(#PathVariable String idProfile,RedirectAttributes ra, Model model){
profileRepo.delete(Long.valueOf(idProfile));
model.addAttribute("profiles", profileRepo.findAll());
return "profile/list";
}
if you are are trying to delete an entity by using Id in the controller, do it like profileRepo.deleteById(Long.valueOf(idProfile));
this, not like this profileRepo.delete(profileRepo.findById(Long.valueOf(idProfile)));
Also use your repository functions like these,
public void deleteArtistById(Long artistId) {
Artist artist = manager.find(Artist.class, artistId);
if (artist != null) {
manager.getTransaction().begin();
manager.remove(artist);
manager.getTransaction().commit();
}
}
public void deleteArtist(Artist artist) {
manager.getTransaction().begin();
manager.remove(artist);
manager.getTransaction().commit();
}
You can take a look at this link for more detail:
http://kodejava.org/how-do-i-delete-entity-object-in-jpa/
At last I found a solution, the problem was when I tried to remove Profile, users and menuSections have related data, so finally I put in menuSections a cascade = CascadeType.REMOVE and in users set profile property to null

Categories