CrudRepository不会删除具有关系的Object

时间:2018-06-12 13:11:06

标签: java spring-mvc spring-boot junit junit4

我有一个基本的SpringBoot应用程序。使用Spring Initializer,JPA,嵌入式Tomcat,Thymeleaf模板引擎和包作为可执行的JAR文件。 我创建了这个Repository类:

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

和此服务类

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

     @Autowired
     protected MenuRepository menuRepository;

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

和这个Junit测试:

@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);

    }
}

但是Junit失败了,因为没有删除对象并且没有抛出异常!

正如所建议的,我在这个方面有这个......

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

即使我在运行测试时在控制台中看到了这一点:

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`))

和菜单类:

@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;
...
}

5 个答案:

答案 0 :(得分:2)

您正在同时使用@OneToMany@ManyToOne定义Menu和MenuPrice之间的双向关系。当您具有生物定向关系时,需要设置双方。在测试中,您要在MenuPrice中设置Menu,但不将MenuPrice添加到Menu的MenuPrice Set中。创建menuPrice后,请包括以下语句menu.MenuPrice.add(menuPrice);。由于您已指定save(),因此您也不需要多个Cascade.All。请尝试以下操作:

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);

}

在某些情况下,您不需要双向关系,可以删除@OneToMany,但这取决于您的业务逻辑需要如何导航到子级或通过JPA查询。

答案 1 :(得分:1)

确保在子对象中:MenuPrice,MenuPriceSummary你有CascadeType.ALL,类似

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

答案 2 :(得分:0)

想一想:

@Transactional(readOnly = true)
public class MenuService {

但我的主要问题是:你在春季启动应用程序中使用了@Transactional注释是什么?

答案 3 :(得分:0)

尝试从MenuService删除@Transactional( readOnly = true )。这可以防止潮红。

否则我会尝试en Lopes的方法。有不同的CascadeTypehttps://docs.oracle.com/javaee/6/api/javax/persistence/CascadeType.html

答案 4 :(得分:0)

更简单的方法是将@PreRemove添加到父级,将子级值设置为null:我的概念是@OneToOne关系,其中Registration对象有一个Subscription对象。他们俩都有彼此的外键。

Registration类内部:

@PreRemove
private void preRemove() {
    setSubscription(null);
}