gpt4 book ai didi

list - 如何使用Hibernate PersistentBag不遵守List equals契约(Contract)?

转载 作者:行者123 更新时间:2023-12-03 14:48:58 24 4
gpt4 key购买 nike

我有一个带有列表的实体:

@Entity
public class Order {

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

@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name="orderId", nullable=false)
private List<Item> items;
}

@Entity
@Data
public class Item {

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@EqualsAndHashCode.Exclude
private Long id;

private String description;
}

我有一项服务,用于检查两个订单是否具有相同的项目,如果有,则返回这些项目;否则返回null:
public List<Item> getItemsIfSame(Order order1, Order order2) {
if (order1.getItems() != null && order1.getItems().equals(order2.getItems())) {
return order1.getItems();
}
return null;
}

我有一个单元测试,其中order1和order2具有相同的项目。和预期的一样,项目列表是从 getItemsIfSame方法返回的。

但是,当我运行我的应用程序并通过两个具有相同项目的订单时,将返回null。经过调试和研究,我发现 Order方法 getItems返回的实际类型是 org.hibernate.collection.internal.PersistentBag。它的文档指出:

Bag does not respect the collection API and do an JVM instance comparison to do the equals. The semantic is broken not to have to initialize a collection for a simple equals() operation.



并在源代码中进行确认,它仅调用 Object的equals方法(即使它实现了 List)。

我想我可以将所有元素从 PersistentBag复制到 ArrayList,然后进行比较,但有时我正在检查具有嵌套属性和列表的对象的相等性。有没有更好的方法来检查实体之间的列表是否相等?

最佳答案

解决方案#1:使用 Guava 的 Iterables#elementsEqual

Iterables.elementsEqual(
order1.getItems() != null ? order1.getItems() : new ArrayList<>(),
order2.getItems() != null ? order2.getItems() : new ArrayList<>());

解决方案2:使用 java.util.Objects#deepEquals
    Objects.deepEquals(
order1.getItems() != null ? order1.getItems().toArray() : order1,
order2.getItems() != null ? order2.getItems().toArray() : order2);

解决方案#3:使用新的 ArrayList对象
(order1.getItems() != null ? new ArrayList(order1.getItems()) : new ArrayList())
.equals(order2.getItems() != null ? new ArrayList(order2.getItems()) : new ArrayList());

解决方案#4 使用Apache的 CollectionUtils#isEqualCollection
    CollectionUtils.isEqualCollection(
order1.getItems() != null ? order1.getItems() : new ArrayList(),
order2.getItems() != null ? order2.getItems() : new ArrayList());

请注意, List#toArray 方法的Javadocs声明以下内容:

Returns an array containing all of the elements in this list in proper sequence (from first to last element). The returned array will be "safe" in that no references to it are maintained by this list. (In other words, this method must allocate a new array). The caller is thus free to modify the returned array.



因此,与解决方案2、3和4相比,使用 Iterables就地比较列表可能会使用更少的内存,而解决方案2、3和4都会隐式或显式地分配新的List或Arrays。

空检查也可以移出三元组,但是需要在两个 order对象上执行,因为所有这些解决方案都涉及调用非空安全的方法( Iterables#elementsEqualLists#toArraynew ArrayList(Collection<?> collection)CollectionUtils.isEqualCollection都将在引发NullPointerExceptions时用null调用)。

旁注:此问题由 long-standing hibernate bug跟踪

关于list - 如何使用Hibernate PersistentBag不遵守List equals契约(Contract)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55621145/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com