【问题标题】:Hibernate single table inheritance - base class nested as a property inside a subclass throws PropertyAccessExceptionHibernate 单表继承 - 作为属性嵌套在子类中的基类抛出 PropertyAccessException
【发布时间】:2021-05-28 18:05:03
【问题描述】:

我有以下具有 2 个基类(过滤器和映射)的类结构。


@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 的设置器

我尝试稍微调试一下 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 列。 => 导致问题。

这是使用 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 列设置正确):

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 识别正确的子类?

【问题讨论】:

  • 你有 AFilter 过滤器和 BFilter 过滤器的 getter 和 setter 吗?
  • 是的,我愿意。我已更新问题以显示它们。
  • 是 Map 和 Filter 抽象类吗?您能否尝试在 Map 中添加方法 public abstract void setFilter(Filter filter);
  • 是的,它们是抽象类(更新了问题)。不幸的是,即使我添加了抽象设置器,也会出现同样的错误。
  • @nilgun 您如何解决实施问题?你怎么知道是 A 级还是 B 级?

标签: java hibernate single-table-inheritance


【解决方案1】:

还请显示生成的查询。我猜你的数据可能是乱七八糟的,即你有一个AMap,它指的是BFilter,而不是AFilter。也许您需要通过在Filter 上注释@DiscriminatorOptions(force = true) 来强制使用鉴别器。

更新:

关键是字段在子类型中具有不同的名称。 Hibernate 支持隐式向下转换,即可以使用select m.filter from Map m,这将解决向下转换的关联。由于有多个可能的向下转换具有该属性,因此存在冲突。我实际上在 Hibernate 中实现了对这部分的支持,但我猜在这种特殊情况下,鉴别器根本就没有了。

【讨论】:

  • 我添加了查询。您还可以查看数据。你是对的,问题出在查询中,它首先没有从过滤器中带来dtype 列。在 Filter 类上添加 @DiscriminatorOptions(force = true) 并不能解决问题。
  • 您可以尝试将AMap 和BMap 类中的字段重命名为例如filterA 和 filterB?
  • 我已经尝试过了(重命名filter 字段和AMap 和BMap 子类中的getter/setter)并且它有效。但是我不能使用抽象的 Map.getFilter 方法。
  • 您可以另外添加该方法。关键是字段在子类型中具有不同的名称。
  • 更改字段名称但将 getter 和 setter 保留为 getFilter/setFilter 解决了问题。我还必须再创建两列 afilter_id、bfilter_id 并为每个子类型正确设置它们。我仍然不明白为什么现有的有效 Java 代码不起作用。你认为这是 Hibernate 的一个错误吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多