选择多对多x的所有元素将导致多对多y中的重复

时间:2014-05-05 17:47:13

标签: spring hibernate spring-data-jpa

我遇到了这个奇怪的问题,希望有人可以帮助我。 也许我做错了什么或忽略了什么?

每当我选择所有n种材料时,我选择的模型会被列出n次。 反之亦然,当我选择所有n个模型时,材料会被列出n次。

例如:Material1(已选中) 材料2(选中) 材料3(选中)

Model1(已选中) MODEL2 Model3

结果:

Material1 材料2 材料3

型号1 型号1 型号1

我使用的是Spring 4.0.3,Spring Data JPA 1.4.3,Hibernate 4.3.1,MySQL 5.1.28,Thymeleaf 2.1.2 发布的DTO是正确的,仅包含所选材料和模型。 数据库中的数据也是正确的!

@Getter
@ToString
@Entity
@Table(name = "SKUS")
public class Sku extends BaseEntityAudit {

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

    @Column(name = "CODE", nullable = false)
    protected String code;

    @Column(name = "NAME", nullable = false)
    protected String name;

    @Column(name = "RETAIL_PRICE", nullable = true)
    protected BigDecimal retailPrice;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
    @JoinTable(name = "SKU_MODELS",
            joinColumns = {@JoinColumn(name = "SKU_ID", referencedColumnName = "ID")},
            inverseJoinColumns = {@JoinColumn(name = "MODEL_ID", referencedColumnName = "ID")})
    protected List<SkuModel> availableModels;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
    @JoinTable(name = "SKU_MATERIALS",
            joinColumns = {@JoinColumn(name = "SKU_ID", referencedColumnName = "ID")},
            inverseJoinColumns = {@JoinColumn(name = "MATERIAL_ID", referencedColumnName = "ID")})
    protected List<Material> availableMaterials;

    public static Builder getBuilder(String code, String name) {
        return new Builder(code, name);
    }

    public void update(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public void updatePrice(BigDecimal retailPrice) {
        this.retailPrice = retailPrice;
    }

    public void updateMaterials(List<Material> materials) {
        if (!materials.equals(availableMaterials)) {
            this.availableMaterials.clear();
            this.availableMaterials = materials;
        }
    }

    public void updateModels(List<SkuModel> models) {
        if (!models.equals(availableModels)) {
            this.availableModels.clear();
            this.availableModels = models;
        }
    }

    public static class Builder {
        private Sku built;

        public Builder(String code, String name) {
            built = new Sku();
            built.code = code;
            built.name = name;
        }

        public Builder retailPrice(BigDecimal retailPrice) {
            built.retailPrice = retailPrice;
            return this;
        }

        public Builder models(List<SkuModel> models) {
            built.availableModels = models;
            return this;
        }

        public Builder materials(List<Material> materials) {
            built.availableMaterials = materials;
            return this;
        }

        public Sku build() {
            return built;
        }
    }
}

public interface SkuRepository extends JpaRepository<Sku, Long> {}

// SkuService
@Transactional(readOnly = true, rollbackFor = {NotFoundException.class})
@Override
public Sku findById(Long id) throws NotFoundException {
    LOGGER.debug("Finding a sku entry with id: {}", id);

    Sku found = skuRepository.findOne(id);
    LOGGER.debug("Found sku entry: {}", found);

    if (found == null) {
        throw new NotFoundException("No sku found with id: " + id);
    }

    return found;
}

@Transactional(rollbackFor = {NotFoundException.class})
@Override
public Sku update(SkuDTO updated) throws NotFoundException {
    LOGGER.debug("Updating sku with request information: {}", updated);

    Sku model = findById(updated.getId());

    model.update(updated.getCode(), updated.getName());
    model.updatePrice(updated.getRetailPrice());
    model.updateMaterials(updated.getMaterials());
    model.updateModels(updated.getModels());

    LOGGER.debug("Updating sku with information: {}", model);
    skuRepository.save(model);
    return model;
}

@RequestMapping(value = REQUEST_MAPPING_SKU_DETAILS, method = RequestMethod.GET)
public String findById(@PathVariable(PARAMETER_SKU_ID) Long id, Model uiModel) throws NotFoundException {
    LOGGER.debug("Rendering sku page for sku entry with id: {}", id);

    Sku found = skuService.findById(id);
    LOGGER.debug("Found sku entry with information: {}", found);

    uiModel.addAttribute(MODEL_ATTRIBUTE_SKU, found);

    return VIEW_SKU_DETAILS;
}

@RequestMapping(value = REQUEST_MAPPING_SKU_EDIT, method = RequestMethod.POST)
public String processUpdateSkuForm(@Valid @ModelAttribute(MODEL_ATTRIBUTE_SKU) SkuDTO dto, BindingResult result, RedirectAttributes attributes) throws NotFoundException {
    LOGGER.debug("Updating a sku entry with information: {}", dto);

    if (result.hasErrors()) {
        LOGGER.debug("Update sku entry form was submitted with validation errors. Redirecting back to form view.");
        attributes.addFlashAttribute("org.springframework.validation.BindingResult." + MODEL_ATTRIBUTE_SKU, result);
        attributes.addFlashAttribute(MODEL_ATTRIBUTE_SKU, dto);
        attributes.addAttribute(PARAMETER_SKU_ID, dto.getId());
        return createRedirectViewPath(REQUEST_MAPPING_SKU_EDIT);
    }

    Sku updated = skuService.update(dto);
    LOGGER.debug("Updated the information of a sku entry to: {}", updated);

    attributes.addAttribute(PARAMETER_SKU_ID, updated.getId());
    return createRedirectViewPath(REQUEST_MAPPING_SKU_DETAILS);
}

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题。

我相信这是因为Spring生成的查询并没有使用&#39; DISTINCT&#39;什么时候加入,但我不知道解决方案。您可以使用Set&lt;&gt;而不是列表&lt;&gt;