CrudRepository не удаляет объект с отношением - PullRequest
0 голосов
/ 12 июня 2018

У меня есть базовое приложение SpringBoot.используя Spring Initializer, JPA, встроенный Tomcat, шаблонизатор Thymeleaf и пакет в качестве исполняемого файла JAR.Я создал этот класс репозитория:

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

Ответы [ 4 ]

0 голосов
/ 21 июня 2018

Вы определяете двунаправленную связь между Menu и MenuPrice, используя @OneToMany и @ManyToOne.Когда у вас двунаправленные отношения, вам нужно установить обе стороны.В тесте вы устанавливаете Menu в MenuPrice, но не добавляете MenuPrice к набору MenuPrice меню.Включите следующий оператор menu.MenuPrice.add(menuPrice); после создания 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.

0 голосов
/ 13 июня 2018

убедитесь, что в дочерних объектах: MenuPrice, MenuPriceSummary у вас есть CascadeType.ALL, что-то вроде

@OneToMany(mappedBy="menu", cascade = CascadeType.ALL, fetch=FetchType.LAZY)
private List<MenuPrice> price;
0 голосов
/ 15 июня 2018

Попробуйте удалить @Transactional ( readOnly = true ) из MenuService.Это может предотвратить промывку.

В противном случае я бы попробовал подход en Lopes.Есть разные CascadeType: https://docs.oracle.com/javaee/6/api/javax/persistence/CascadeType.html

0 голосов
/ 12 июня 2018

Подумайте об этом:

@Transactional(readOnly = true)
public class MenuService {

Но мой главный вопрос: для чего вы использовали аннотацию @Transactional в приложении с весенней загрузкой?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...