这个让我很不舒服。
问题陈述:
从数据库中获取Marklar
时,返回的是重复的Foo
。具体来说,Foo
s的数量与bars
HashMap中的元素数量一样多。例如,如果我保存一个Marklar
,在它的FooCollection
中有oneFoo
,如果bars
是:
{0, "data1", 1, "data2", 2, "data3"}
当我读回来的时候,我会在FooCollection
中得到三个Foo
。这是怎么回事?
定义:
我有以下的类结构:
Foo<T>
^
|
| 1:M
FooContainer
^
|
| 1:1
<<Marklar>>
一个Marklar
有一个FooCollection
,它有几个Foo
。Foo
是一个泛型类,定义为:
@Getter
@Setter
@ToString
@Entity
public class Foo<T> {
@Id @GeneratedValue private Long id;
@ElementCollection(fetch = FetchType.EAGER)
private final Map<Integer, String> bars = new HashMap<>();
@Type(type = "java.lang.Class")
private final Class<T> clazz;
@Column(columnDefinition = "LONGTEXT")
@Convert(converter = PatternConverter.class)
private Pattern pattern;
public void addBar(Integer key, String bar) {
bars.put(key, bar);
}
public Foo(Class<T> clazz) {
this.clazz = clazz;
}
public Foo() {
this.clazz = null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Foo)) return false;
Foo<?> foo = (Foo<?>) o;
return Objects.equals(getId(), foo.getId())
&& Objects.equals(getBars(), foo.getBars())
&& Objects.equals(getClazz(), foo.getClazz())
&& Objects.equals(getPattern(), foo.getPattern());
}
@Override
public int hashCode() {
return Objects.hash(getId(), getBars(), getClazz(), getPattern());
}
}
问题陈述:
从数据库中获取Marklar
时,返回的是重复的Foo
s。具体来说,Foo
s的数量与bars
HashMap中的元素数量一样多。例如,如果我保存一个Marklar
,在它的FooCollection
中有oneFoo
,如果bars
是:
{0, "data1", 1, "data2", 2, "data3"}
当我读回来的时候,我会在FooContainer
中得到三个Foo
。这是怎么回事?
定义:
我有以下的类结构:
Foo<T>
^
|
| 1:M
FooCollection
^
|
| 1:1
<<Marklar>>
一个Marklar
有一个FooContainer
,它有几个Foo
。Foo
是一个泛型类,定义为:
@Getter
@Setter
@ToString
@Entity
public class Foo<T> {
@Id @GeneratedValue private Long id;
@ElementCollection(fetch = FetchType.EAGER)
private final Map<Integer, String> bars = new HashMap<>();
@Type(type = "java.lang.Class")
private final Class<T> clazz;
@Column(columnDefinition = "LONGTEXT")
@Convert(converter = PatternConverter.class)
private Pattern pattern;
public void addBar(Integer key, String bar) {
bars.put(key, bar);
}
public Foo(Class<T> clazz) {
this.clazz = clazz;
}
public Foo() {
this.clazz = null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Foo)) return false;
Foo<?> foo = (Foo<?>) o;
return Objects.equals(getId(), foo.getId())
&& Objects.equals(getBars(), foo.getBars())
&& Objects.equals(getClazz(), foo.getClazz())
&& Objects.equals(getPattern(), foo.getPattern());
}
@Override
public int hashCode() {
return Objects.hash(getId(), getBars(), getClazz(), getPattern());
}
}
FooContainer
:
@Getter
@Setter
@ToString
@Entity
public class FooContainer {
@Id @GeneratedValue private Long id;
@OneToMany(targetEntity = Foo.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private final List<Foo> foos = new ArrayList<>();
public void addFoo(Foo foo) {
foos.add(foo);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FooContainer)) return false;
FooContainer that = (FooContainer) o;
return Objects.equals(getId(), that.getId()) && Objects.equals(getFoos(), that.getFoos());
}
@Override
public int hashCode() {
return Objects.hash(getId(), getFoos());
}
}
Marklars
是从MarklarRepository
中获取的:
@Repository
public interface MarklarRepository extends JpaRepository<Marklar<?>, UUID> {}
Marklar
是一个抽象类:
@Getter
@Setter
@Entity
@ToString
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Marklar<T> {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
private UUID id;
@Convert(converter = UriConverter.class)
private final URI baseUri;
@Type(type = "java.lang.Class")
private final Class<T> clazz;
private boolean enabled = true;
public Marklar() {
this.baseUri = null;
this.clazz = null;
}
public Marklar(@NotNull URI baseUri, @NotNull Class<T> clazz) {
this.baseUri = baseUri;
this.clazz = clazz;
}
}
实现为DefaultMarklar
:
@Getter
@Setter
@ToString(callSuper = true)
@Entity
@RequiredArgsConstructor
public final class DefaultMarklar<T> extends Marklar<T> {
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final FooContainer fooContainer;
public DefaultMarklar() {
super();
this.fooContainer = null;
}
public DefaultMarklar(
@NotNull URI baseUri, @NotNull Class<T> clazz, @NotNull FooContainer fooContainer) {
super(baseUri, clazz);
this.fooContainer = fooContainer;
}
}
2条答案
按热度按时间9fkzdhlc1#
问题是
bars
被Hibernate认为是一个单独的包,同时急切地获取多个包可能会导致这样的基数问题。我从
Bars
Map中删除了fetch = FetchType.EAGER
,并在调用方法中添加了@Transactional
注解,一切都很好。另外,我将对延迟加载字段的直接引用(比如在toString()
方法中)替换为对它们各自getter的调用。ih99xse12#
按照@Tomas的建议,将获取类型从Lazy更改为Easy解决了重复问题,但它也会影响结果。
如果你想保持EagerType为EAGER,只需指定FechMode选择: