当键是具有另一个实体列表的实体时,HashMap 无法识别键

HashMap not recognizing key, when key is an entity with a list of another entity

我有一个电子商务类型的应用程序(Spring 启动)正在进行中,我正在使用 HashMap 来跟踪购物车中的商品和商品数量。将商品添加到购物车时,hashmap 无法识别相似的商品,而是创建一个新条目而不是添加到商品计数中。 我知道这在某种程度上与 Jpa 和哈希码的生成方式有关。我尝试了与 POJOs 相同的情况(没有 jpa 或任何东西)并且密钥被识别。我尝试重写 equals(Object o) 和 hashCode() 方法,如下所示(以忽略有问题的列表),但即使它现在生成相同的哈希码(如下所示)也无济于事。我会很高兴让这个工作,提前谢谢你!

项目:

@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Item extends AbstractPersistable<Long> {

    private String name;

    private Long productNumber;

    private Double price;

    private Double discountPrice;

    private Double discountFactor;

    private Integer stock;

    @Column(length = 10000)
    private String description;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Image> images = new ArrayList<>();

    private Boolean isHidden;

    private Boolean isService;

    @ManyToOne
    private ItemCategory category;

    public Item(String name, Double price, String description, int stock, ItemCategory category) {

        this.name = name;

        this.price = price;

        this.description = description;

        this.stock = stock;

        this.category = category;
    }

    >>getters and setters<<
      
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        Item item = (Item) o;

        if (name != null ? !name.equals(item.name) : item.name != null) {
            return false;
        }
        if (productNumber != null ? !productNumber.equals(item.productNumber) : item.productNumber != null) {
            return false;
        }
        if (discountPrice != null ? !discountPrice.equals(item.discountPrice) : item.discountPrice != null) {
            return false;
        }
        if (discountFactor != null ? !discountFactor.equals(item.discountFactor) : item.discountFactor != null) {
            return false;
        }
        if (stock != null ? !stock.equals(item.stock) : item.stock != null) {
            return false;
        }
        if (description != null ? !description.equals(item.description) : item.description != null) {
            return false;
        }
        if (isHidden != null ? !isHidden.equals(item.isHidden) : item.isHidden != null) {
            return false;
        }
        if (isService != null ? !isService.equals(item.isService) : item.isService != null) {
            return false;
        }

        return category != null ? category.equals(item.category) : item.category == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (productNumber != null ? productNumber.hashCode() : 0);
        result = 31 * result + (discountPrice != null ? discountPrice.hashCode() : 0);
        result = 31 * result + (discountFactor != null ? discountFactor.hashCode() : 0);
        result = 31 * result + (stock != null ? stock.hashCode() : 0);
        result = 31 * result + (description != null ? description.hashCode() : 0);
        result = 31 * result + (isHidden != null ? isHidden.hashCode() : 0);
        result = 31 * result + (isService != null ? isService.hashCode() : 0);
        result = 31 * result + (category != null ? category.hashCode() : 0);
        return result;
    }

图片:

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Image extends AbstractPersistable<Long> {

    @Lob
    @Basic(fetch = FetchType.LAZY)
    private byte[] content;

    @ManyToOne
    @JoinColumn(name = "item_id")
    private Item item;

    private Boolean isMainPicture;

    private int ordinal;

}

购物车:

@Component
@AllArgsConstructor
@NoArgsConstructor
@Data
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ShoppingCart {

    private Map<Item, Long> items = new HashMap<>();

    public void addToCart(Item item) {

        Long itemCount = this.items.getOrDefault(item, 0L) + 1L;

        this.items.put(item, itemCount);

    }

    public void removeFromCart(Item item) {

        if (this.items.get(item) == 1L) {

            this.items.remove(item);
            
            return;
        }

        Long itemCount = this.items.get(item) - 1L;

        this.items.put(item, itemCount);
    }

    public Double getSum() {

        return this.items.keySet().stream()
                .map(item -> (item.getPrice() * this.items.get(item)))
                .reduce(0.0, (currentSum, nextCost) -> currentSum + nextCost);

    }

}

@Controller 中的 viewCart 方法:

@GetMapping("/cart")
public String viewCart(Model model) {
        System.out.println("!!!!!!!!!!!!!!!!!!");
        shoppingCart.getItems().keySet().stream().forEach(key -> System.out.println(key.toString() + "; hashcode = " + key.hashCode()));

        model.addAttribute("items", shoppingCart.getItems());

        return "cart";
    }

在 HashMap 中有两个相似项目的 viewCart 方法之后的控制台:

!!!!!!!!!!!!!!!!!!
Entity of type mortar.euroshopper.eCommerceApplication.Item with id: 6; hashcode = 34943583
Entity of type mortar.euroshopper.eCommerceApplication.Item with id: 6; hashcode = 34943583

感谢 M. Deinum 的评论解决了问题!在此处找到说明:https://vladmihalcea.com/the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate/