Hibernate single table inheritance - base class 嵌套为 属性 inside a subclass throws PropertyAccessException
Hibernate single table inheritance - base class nested as a property inside a subclass throws PropertyAccessException
我有以下 class 结构,其中包含 2 个基础 classes(过滤器和映射)。
@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: Could not set field value
[com.xxx.filter.BFilter@6197da84] value by reflection : [class
com.xxx.map.AMap.filter] setter of com.xxx.map.AMap.filter
我尝试稍微调试一下 Hibernate(v5.4.18) 库,它以某种方式假定 Map.class 的 filter
属性 是 BFilter 的实例,而不是基于 Map subclass 类型的动态 subclass.
这是 Hibernate 生成的查询(已编辑以删除额外字段并加入 tables):
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 没有 select 过滤器 table 的 dtype
列。 => 导致问题。
这是使用 psql 查询的结果:
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 列已在过滤器 table 上正确设置):
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)
如果我使用 subclasses 创建条件,我可以毫无问题地查询数据库:
dao.getCurrentSession().createCriteria(AMap.class)
要么
dao.getCurrentSession().createCriteria(BMap.class)
但这不是我想要的。
如何让 Hibernate 识别正确的子class?
还请显示生成的查询。我猜你的数据可能被弄乱了,即你有一个 AMap
指的是 BFilter
而不是 AFilter
。也许您需要通过在 Filter
.
上注释 @DiscriminatorOptions(force = true)
来强制使用鉴别器
更新:
关键是字段在子类型中具有不同的名称。 Hibernate 支持隐式向下转换,即可以使用 select m.filter from Map m
并且可以解析为向下转换的关联。由于有多个可能的向下转换具有 属性,因此存在冲突。我实际上在 Hibernate 中实现了对这部分的支持,但我猜想在这种特殊情况下鉴别器根本就没有。
我有以下 class 结构,其中包含 2 个基础 classes(过滤器和映射)。
@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: Could not set field value [com.xxx.filter.BFilter@6197da84] value by reflection : [class com.xxx.map.AMap.filter] setter of com.xxx.map.AMap.filter
我尝试稍微调试一下 Hibernate(v5.4.18) 库,它以某种方式假定 Map.class 的 filter
属性 是 BFilter 的实例,而不是基于 Map subclass 类型的动态 subclass.
这是 Hibernate 生成的查询(已编辑以删除额外字段并加入 tables):
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 没有 select 过滤器 table 的 dtype
列。 => 导致问题。
这是使用 psql 查询的结果:
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 列已在过滤器 table 上正确设置):
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)
如果我使用 subclasses 创建条件,我可以毫无问题地查询数据库:
dao.getCurrentSession().createCriteria(AMap.class)
要么
dao.getCurrentSession().createCriteria(BMap.class)
但这不是我想要的。
如何让 Hibernate 识别正确的子class?
还请显示生成的查询。我猜你的数据可能被弄乱了,即你有一个 AMap
指的是 BFilter
而不是 AFilter
。也许您需要通过在 Filter
.
@DiscriminatorOptions(force = true)
来强制使用鉴别器
更新:
关键是字段在子类型中具有不同的名称。 Hibernate 支持隐式向下转换,即可以使用 select m.filter from Map m
并且可以解析为向下转换的关联。由于有多个可能的向下转换具有 属性,因此存在冲突。我实际上在 Hibernate 中实现了对这部分的支持,但我猜想在这种特殊情况下鉴别器根本就没有。