Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CrudRepository does not delete an Object with relationship

Tags:

I have a basic SpringBoot app. using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file. I have created this Repository class:

@Repository
public interface MenuRepository extends CrudRepository<Menu, Long> {
..
}

and this service class

@Service
@Transactional(readOnly = true)
public class MenuService {

     @Autowired
     protected MenuRepository menuRepository;

     @Transactional
     public void delete (Menu menu) {
         menuRepository.delete  (menu);
     }
     ..
}

and this Junit Test:

@ContextConfiguration(classes={TestSystemConfig.class})
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MenuGestApplication.class) 
public class MenuServiceTests {
...
@Test
    public void testDelete () {

        Menu menu = new menu(); 
        menu.setmenuId("bacalla-amb-tomaquet");
        menuService.save(menu);

        MenuPrice menuPrice = new menuPrice(menu);
        menuPrice.setPrice((float)20.0);
        menuPriceService.save(menuPrice);

        MenuPriceSummary menuPriceSummary = new menuPriceSummary(menu);
        menuPriceSummary.setFortnightlyAvgPrice((float)20.0);

        menuPriceSummaryService.save(menuPriceSummary);

        menu = menuService.findBymenuId("bacalla-amb-tomaquet");

        assertNotNull (menu);

        menuService.delete (menu);

        menu = menuService.findBymenuId("bacalla-amb-tomaquet");

        assertNull (menu);

    }
}

But the Junit is failing because the object is not deleted and no exception is thrown !

I have this in the proerty, as suggested..

@OneToMany(mappedBy="menu", cascade = CascadeType.ALL,  orphanRemoval = true, fetch=FetchType.LAZY)
    private List<MenuPrice> price;

even that I see this in the console when running the tests:

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`elcormenu`.`t_menu_price`, CONSTRAINT `FK19d0sljpshu4g8wfhrkqj7j7w` FOREIGN KEY (`menu_id`) REFERENCES `t_menu` (`id`))

and the Menu class:

@Entity
@Table(name="t_menu")
public class Menu  implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JsonProperty("id")
    private Long id;    

    @JsonProperty("MenuId")
    private String MenuId;

    @OneToMany(mappedBy = "Menu", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @JsonIgnore
    private Set<MenuPrice> MenuPrice = new HashSet<>();

    @OneToOne(mappedBy = "Menu", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JsonIgnore
    private MenuPriceSummary summary;
...
}
like image 241
en Peris Avatar asked Jun 12 '18 13:06

en Peris


People also ask

What does the CrudRepository do?

The CrudRepository interface provides methods for CRUD operations, so it allows you to create, read, update and delete records without having to define your own methods. The PagingAndSortingRepository provides additional methods to retrieve entities using pagination and sorting.

What is true about CrudRepository and JpaRepository in Spring data JPA?

Each of these defines its own functionality: CrudRepository provides CRUD functions. PagingAndSortingRepository provides methods to do pagination and sort records. JpaRepository provides JPA related methods such as flushing the persistence context and delete records in a batch.

Which is better CrudRepository or JpaRepository?

Crud Repository doesn't provide methods for implementing pagination and sorting. JpaRepository ties your repositories to the JPA persistence technology so it should be avoided. We should use CrudRepository or PagingAndSortingRepository depending on whether you need sorting and paging or not.


1 Answers

You are defining a Bidirectional relationship between Menu and MenuPrice by using both @OneToMany and @ManyToOne. When you have a biodirectional relationship you need to set both sides. In the test you are setting Menu in MenuPrice but not adding the MenuPrice to Menu's MenuPrice Set. Include the following statement menu.MenuPrice.add(menuPrice); after you create menuPrice. You also do not need multiple save() since you have specified Cascade.All. Try the following:

public void testDelete () {

    Menu menu = new menu(); 
    menu.setmenuId("bacalla-amb-tomaquet");

    MenuPrice menuPrice = new menuPrice(menu);
    menuPrice.setPrice((float)20.0);

    // Not needed
    // menuPriceService.save(menuPrice);

    // Add menuPrice to menu's menuPrice set
    menu.menuPrice.add(menuPrice);

    MenuPriceSummary menuPriceSummary = new menuPriceSummary(menu);
    menuPriceSummary.setFortnightlyAvgPrice((float)20.0);

    // Set menuPriceSummary in menu        
    menu.summary = menuPriceSummary;

    // Not needed
    //menuPriceSummaryService.save(menuPriceSummary);

    // Saving menu will save it children too
    menuService.save(menu);

    menu = menuService.findBymenuId("bacalla-amb-tomaquet");

    assertNotNull (menu);

    menuService.delete (menu);

    menu = menuService.findBymenuId("bacalla-amb-tomaquet");

    assertNull (menu);

}

In may cases, you don't need bidirectional relationships and can remove the @OneToMany, but this depends on how your business logic needs to navigate to the children or query it via JPA.

like image 187
Jean Marois Avatar answered Oct 25 '22 05:10

Jean Marois