我为你感到困惑。
我正在制作一家药草店网络应用程序,这是我的数据库:
这些是我的JPA课程:
public class StoreJPA {
...
@OneToMany(mappedBy="storeJpa", cascade = CascadeType.ALL, orphanRemoval=true, fetch=FetchType.EAGER)
private Set<ProductJPA> specialOffers = new HashSet<ProductJPA>();
...
}
public class ProductJPA {
@ManyToOne
@JoinColumn(name="store_id")
private StoreJPA storeJpa;
@OneToMany(mappedBy="productJpa", cascade = CascadeType.ALL, orphanRemoval=true, fetch=FetchType.EAGER)
private Set<ContainsJPA> contains = new HashSet<ContainsJPA>();
...
private Set<HerbJPA> getHerbs(){
return contains.stream().map(h -> h.getHerbJpa()).collect(Collectors.toSet());
}
@Override
public int hashCode(){
long h = 1125899906842597L; // prime
for(ProductHasHerbJPA phh : contains){
h = 31*h + phh.getHerbJpa().getId();
}
return (int)(31*h + storeJpa.getId());
}
@Override
public boolean equals(Object o){
if(o!=null && o instanceof ProductJPA){
if(o==this)
return true;
return ((ProductJPA)o).getStoreJpa().getId()==storeJpa.getId() &&
((ProductJPA)o).getHerbs().equals(getHerbs()) // compare herbs they contain
}
return false;
}
...
}
public class ContainsJPA {
@Id
private Long id;
@ManyToOne
@JoinColumn(name="product_id")
private ProductJPA productJpa;
@ManyToOne
@JoinColumn(name="herb_id")
private HerbJPA herbJpa;
...
@Override
public int hashCode(){
long h = 1125899906842597L + productJpa.getId(); // <-- nullpointer exception
return (int)(31*h + herbJpa.getId());
}
@Override
public boolean equals(Object o){
if( o != null && o instanceof HerbLocaleJPA) {
if(o==this) {
return true;
}
return ((ProductHasHerbJPA)o).getHerbJpa().getId()==herbJpa.getId() &&
((ProductHasHerbJPA)o).getProductJpa().getId()==productJpa.getId();
}
return false;
}
...
}
添加带有草药列表的新产品效果很好。但是当我运行它并尝试在商店中购买产品时,我得到了NullPointerException:
com.green.store.entities.ContainsJPA.hashCode(ContainsJPA.java:64)处的java.lang.NullPointerException java.util.HashMap.hash(HashMap.java:339)处的java.util.HashMap.put(HashMap。 org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java)的java.util.AbstractCollection.addAll(AbstractCollection.java:344)的java.util.HashSet.add(HashSet.java:220)的java:612) :327),位于org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:234),位于org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:221),位于org.hibernate。 org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl上的engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:194)。org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:249)的org.hibernate.loader.plan.exec.process.internal.AbstractRowReader的endLoading(CollectionReferenceInitializerImpl.java:154) org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:133)的finishUp(AbstractRowReader.java:212) org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)处的org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:167)处的AbstractLoadPlanBasedLoader.java:122)在org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4087)在org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)在org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478)在org.hibernate.event.internal.DefaultLoadEventListener org.org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:278)的org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:121)的.load(DefaultLoadEventListener.java:219)在org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1239)处的hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)在org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1122)位于org.hibernate.type处的org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:672)处。org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:165)的EntityType.resolve(EntityType.java:457)org.org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:125)的EntityType.resolve(EntityType.java:457) org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:238)在org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:209)在org org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122)处的.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:133) org.hibernate.loader.entity.plan的.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)。org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4087)的org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)的AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:167) .org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478)在org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)在org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener) .java:116),位于org.hibernate.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89),位于org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1239),位于org.hibernate.internal.SessionImpl。 InstantLoad(SessionImpl.java:1097)...在org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4087)处org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)处加载(AbstractLoadPlanBasedEntityLoader.java:167) org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)的org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java)的.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478) :116)在org.hibernate.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)在org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1239)在org.hibernate.internal.SessionImpl.immediateLoad( SessionImpl.java:1097)...在org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4087)处org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)处加载(AbstractLoadPlanBasedEntityLoader.java:167) org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)的org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java)的.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478) :116)在org.hibernate.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)在org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1239)在org.hibernate.internal.SessionImpl.immediateLoad( SessionImpl.java:1097)...org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)上的persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4087)在org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java: 478)在org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)在org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:116)在org.hibernate.event.internal.DefaultLoadEventListener在org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1239)的.onLoad(DefaultLoadEventListener.java:89)在org.hibernate.internal.SessionImpl.immediateLoad(SessionImpl.java:1097)的...org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)上的persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4087)在org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java: 478)在org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)在org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:116)在org.hibernate.event.internal.DefaultLoadEventListener在org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1239)的.onLoad(DefaultLoadEventListener.java:89)在org.hibernate.internal.SessionImpl.immediateLoad(SessionImpl.java:1097)的...org的org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478)的org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)的DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508) .hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:116)在org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)在org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java) :1239),位于org.hibernate.internal.SessionImpl.immediateLoad(SessionImpl.java:1097)...org的org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478)的org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)的DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508) .hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:116)在org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)在org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java) :1239),位于org.hibernate.internal.SessionImpl.immediateLoad(SessionImpl.java:1097)...在org.hibernate的org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:116)处加载(DefaultLoadEventListener.java:219)在org.hibernate的org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)处加载org.hibernate.internal.SessionImpl.immediateLoad(SessionImpl.java:1097)的.internal.SessionImpl.fireLoad(SessionImpl.java:1239)...在org.hibernate的org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:116)处加载(DefaultLoadEventListener.java:219)在org.hibernate的org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)处加载org.hibernate.internal.SessionImpl.immediateLoad(SessionImpl.java:1097)的.internal.SessionImpl.fireLoad(SessionImpl.java:1239)...
获取产品的ID时,ContainsJPA的hashCode函数将引发此异常。考虑到数据库中的“包含”表具有此ID,为什么这样做呢?我不知道为什么会这样。请帮忙。
您的hashCode和equals实现不正确。
简而言之,它的问题是:
hashCode和equals均要求您不要将NPE丢掉。对于equals,这意味着您不能只打电话说,a.equals(b)
-您必须做到这一点a == null ? b == null : a.equals(b)
(并且因为“永不抛出”是可传递的,a.equals(b)
所以即使b为null也可以),或者使用辅助函数Objects.equal(a, b)
。
对于哈希码,这意味着为了哈希,必须将空值定义为具有一些预定义的值。同样,更一般而言,每当您具有“子对象”(例如某些非原始类型的字段)时,通常的想法是使用hashCode并等同于级联:Use productJPA.hashCode()
和not productJPA.getId()
。
平等同样适用。不要这样做:
(ProductHasHerbJPA)o).getHerbJpa().getId()==herbJpa.getId()
但是这样做:
Objects.equals(o.getHerbJpa(), herbJpa);
如果两个草本JPA的ID相等,则认为它们相等,那么equals()
应相应定义HerbJPA类的方法,否则,则定义不。知道如何计算2个HerbJPA实例是否相等不是您的ContainsJPA类的工作-HerbJPA本身可以做到这一点。通过这样做,您避免了很多空问题。
请注意,您可以让龙目岛为您处理所有这些样板。
接下来,我们讨论一些JPA尤其是平等问题。
在Java生态系统中(在JPA / Hibernate之外),执行equals / hashCode 的常见策略是查看属于对象标识一部分的所有字段,通常都是这些字段。问题是,它不适用于JPA:JPA对象上的大多数getter方法都是代理,如果您调用它们,则会导致数据库查询。通过充分互连的数据库结构(大量引用),这意味着单个equals
调用最终将查询您的数据库的一半,占用大量内存,并且需要半小时才能完成,这显然不是可行的解决方案。
关键问题是:对象实际上代表什么,据我所知,JPA没有给出明确的指导。
然后我们可以得出以下结论:
if (this == other) return true;
。除此以外...顺便提一下,这种视图也很方便,因为您完全避免了“ whoops it query the整个数据库”的问题。unid的获取并不昂贵,通常已经进行了预取。
如果是这种情况,我是否可以建议您的班级命名错误?应该是“ Herb”。也许是“ HerbJpa”(注意:大写的JPA违反了最常见的样式规则)。
那么最无意义的解决方案是AVOID检查UNID完全,只有在所有其他领域看(或者至少,所有其他的人,代表一些关于草药的身份。这通常他们的最多的是,但有时你可以得到定义了一些会引起数据库查询风暴的属性,例如“一个关联草药列表”(在数据库中用联接表表示)为“不是身份的一部分”。 db”是“ herb”概念的附带实现细节,因此不可能成为其标识的一部分!
这种观点的缺点当然是“数据库调用风暴”问题。
通常,我建议您将这些对象视为代表“表中的行”而不是“实际的草本植物”,在这种情况下,您的equals和hashCode方法变得相对简单,并且类的名称很好(嗯,应该是“ Jpa”,而不是“ JPA”,除此之外)。
@Override public int hashCode() {
return id == null ? super.hashCode() : (int) id;
// note, other answer's id %1000 is silly;
// it is needlessly inefficient, don't do it that way.
}
@Override public boolean equals(Object other) {
if (other == this) return true;
if (other == null || other.getClass() != ContainsJPA.class) return false;
return id == null ? false : id.equals(other.id);
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句