问题描述
我有以下类结构和 2 个基类(Filter 和 Map)。
@Entity
public abstract class Filter {
}
@Entity
public class AFilter extends Filter {
}
@Entity
public class BFilter extends Filter {
}
@Entity
public abstract class Map {
public abstract Filter getFilter();
}
@Entity
public class AMap extends Map {
@OnetoOne(cascade = CascadeType.ALL,orphanRemoval = true)
private AFilter filter;
@Override
public AFilter getFilter() {
return filter;
}
public void setFilter(AFilter filter) {
this.filter = filter;
}
}
@Entity
public class BMap extends Map {
@OnetoOne(cascade = CascadeType.ALL,orphanRemoval = true)
private BFilter filter;
@Override
public BFilter getFilter() {
return filter;
}
public void setFilter(BFilter filter) {
this.filter = filter;
}
}
当我查询数据库并且结果集有一个 AMap 实例时,我得到以下异常:
@Override
public List<Map> getMaps() {
Criteria criteria = dao.getCurrentSession().createCriteria(Map.class);
return criteria.list();
}
org.hibernate.PropertyAccessException: 无法设置字段值 [com.xxx.filter.BFilter@6197da84] 反射值:[class com.xxx.map.AMap.filter] com.xxx.map.AMap.filter 的 setter
我尝试稍微调试 Hibernate(v5.4.18) 库,不知何故它假定 Map.class 的 filter
属性是 BFilter 的实例,而不是基于 Map 子类类型的动态子类。
这是 Hibernate 生成的查询(经过编辑以删除额外的字段和连接表):
select this_.id as id2_103_4_,this_.name as name15_103_4_,this_.status as status16_103_4_,this_.filter_id as filter_25_103_4_,this_.DTYPE as dtype1_103_4_,claimfilte5_.id as id2_89_3_,claimfilte5_.companyId as companyi3_89_3_,claimfilte5_.tableName as tablenam5_89_3_,claimfilte5_.zoomLevel as zoomleve6_89_3_ from public.Map this_ left outer join public.Filter claimfilte5_ on this_.filter_id=claimfilte5_.id
查看查询,Hibernate 没有为过滤表选择 dtype
列。 => 导致问题。
id2_103_4_ | name15_103_4_ | status16_103_4_ | filter_25_103_4_ | dtype1_103_4_ | id2_89_3_ | companyi3_89_3_ | tablenam5_89_3_ | zoomleve6_89_3_
------------+---------------+-----------------+------------------+---------------+-----------+-----------------+-----------------+-----------------
245921700 | 123123 | t | 245921702 | BMap | 245921702 | 16 | B |
250077365 | Test2 | t | 250077367 | BMap | 250077367 | 4 | B |
250365744 | Test | t | 250365746 | BMap | 250365746 | 0 | B |
250367720 | test3 | f | 250367722 | BMap | 250367722 | 0 | B |
254371277 | gdal new test | t | 254371279 | BMap | 254371279 | 0 | B |
254371748 | test4 | t | 254371750 | AMap | 254371750 | 0 | A |
(6 rows)
当我手动添加 dtype 列时(以显示 dtype 列在过滤器表上设置正确):
id2_103_4_ | name15_103_4_ | status16_103_4_ | filter_25_103_4_ | dtype1_103_4_ | id2_89_3_ | companyi3_89_3_ | tablenam5_89_3_ | zoomleve6_89_3_ | dtype
------------+---------------+-----------------+------------------+---------------+-----------+-----------------+-----------------+-----------------+--------------
245921700 | 123123 | t | 245921702 | BMap | 245921702 | 16 | B | | BFilter
250077365 | Test1 | t | 250077367 | BMap | 250077367 | 4 | B | | BFilter
250365744 | Test | t | 250365746 | BMap | 250365746 | 0 | B | | BFilter
250367720 | test3 | f | 250367722 | BMap | 250367722 | 0 | B | | BFilter
254371277 | gdal new test | t | 254371279 | BMap | 254371279 | 0 | B | | BFilter
254371748 | test4 | t | 254371750 | AMap | 254371750 | 0 | A | | AFilter
(6 rows)
如果我使用子类创建条件,我可以毫无问题地查询数据库:
dao.getCurrentSession().createCriteria(AMap.class)
要么
dao.getCurrentSession().createCriteria(BMap.class)
但这不是我想要的。
如何让 Hibernate 识别正确的子类?
解决方法
还请显示生成的查询。我猜您的数据可能被搞砸了,即您有一个 AMap
指的是 BFilter
而不是 AFilter
。也许您需要通过在 @DiscriminatorOptions(force = true)
上注释 Filter
来强制使用鉴别器。
更新:
关键点是字段在子类型中具有不同的名称。 Hibernate 支持隐式向下转换,即可以使用 select m.filter from Map m
并解析向下转换的关联。由于有多种可能的向下转换具有该属性,因此存在冲突。我实际上在 Hibernate 中实现了对这部分的支持,但我猜在那种特殊情况下只是缺少鉴别器。