Hibernate和@JoinFormula:org.hibernate.mapping.Formula不能转换为org.hibernate.mapping.Column [英] Hibernate and @JoinFormula: org.hibernate.mapping.Formula cannot be cast to org.hibernate.mapping.Column

查看:165
本文介绍了Hibernate和@JoinFormula:org.hibernate.mapping.Formula不能转换为org.hibernate.mapping.Column的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图为旧数据库模式编写一个hibernate适配器。此架构没有专用的id列,但使用了大约三个其他列来连接数据。



在某些表上,我需要使用coalesce。这是我到目前为止:

关于定义:




  • 汽车可以有汽车用户或汽车用户组分配的元素。

  • 如果FORIGN_ELEMENT包含用户名,则定义为'u'

  • 如果FORIGN_ELEMENT包含组名,定义将为'g'

  • 这也意味着,一张表(CAR_TO_ELEMENT)被误用来将汽车映射到元素,并将汽车组映射到元素。我定义了一个超类CarElement和一个子类CarUserElement和CarGroupElement。
  • 状态是active或一个无趣的字符串

  • 我在其他地方设置了definitition和state,我们不需要担心这一点。

  • 在连接表上使用DEP_NR。如果它为零,则使用USR_DEP_NR。我在本地SQL中成功完成了 COALESCE(NULLIF()),并希望在Hibernate中使用Pojos实现相同的功能。


好的,我们来看看代码:

  @Entity 
@Table(name =CAR)
public class Car扩展TableEntry实现Serializable {
@Id
@Column(name =DEP_NR)
private int depnr;

@Id
@Column(name =USER_NAME)
@Type(type =TrimmedString)
private String username;
$ b @ManyToOne(fetch = FetchType.EAGER,targetEntity = CarGroup.class)
@JoinColumns(value = {
@JoinColumn(name =GROUP_NAME),
@JoinColumn(name =DEP_NR),
@JoinColumn(name =state),
})
私人CarGroup组;

@OneToMany(fetch = FetchType.EAGER,targetEntity = CarUserElement.class,mappedBy =car)
private Set< CarUserElement>要素;



  @Entity 
@Table(name =CAR_GROUP)
public class CarGroup extends TableEntry implements Serializable {
@Id
@Column(name =DEP_NR)
private int depnr;

@Id
@Column(name =GROUP_NAME)
@Type(type =TrimmedString)
private String group;

@ManyToOne(fetch = FetchType.EAGER,targetEntity = Car.class)
@JoinColumns(value = {
@JoinColumn(name =GROUP_NAME),
@JoinColumn(name =DEP_NR),
@JoinColumn(name =state),
})
private Set< Car>汽车;

@OneToMany(fetch = FetchType.EAGER,targetEntity = CarGroupElement.class,mappedBy =car)
private Set< CarGroupElement>要素;



  @MappedSuperclass 
public class CarElement extends TableEntry {
@Id
@ManyToOne(fetch = FetchType.EAGER,targetEntity = Element.class)
@JoinColumns(value = {
@JoinColumn(name =ELEMENT_NAME),
@JoinColumn(name =state),
})
私有元素元素;



  @Entity 
@Table(name =CAR_TO_ELEMENT)
public class CarUserElement extends CarElement {
@Id
@Column(name =DEFINITION)
private char定义;

@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumnsOrFormulas(value = {
@JoinColumnOrFormula(formula = @ JoinFormula(value =COALESCE NULLIF(DEP_NR,0),USR_DEP_NR),referencedColumnName =DEP_NR)),
@JoinColumnOrFormula(column = @ JoinColumn(name =FORIGN_ELEMENT,referencedColumnName =USER_NAME)),
@ JoinColumnOrFormula(column = @ JoinColumn(name =STATE,referencedColumnName =STATE))
})
private car car;

$ b



  @Table(name =CAR_TO_ELEMENT)
公共类CarGroupElement extends CarElement {
@Id
@Column(name =DEFINITION)
私人字符定义;

@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumnsOrFormulas(value = {
@JoinColumnOrFormula(formula = @ JoinFormula(value =COALESCE NULLIF(DEP_NR,0),USR_DEP_NR),referencedColumnName =DEP_NR)),
@JoinColumnOrFormula(column = @ JoinColumn(name =FORIGN_ELEMENT,referencedColumnName =GROUP_NAME)),
@ JoinColumnOrFormula(column = @ JoinColumn(name =STATE,referencedColumnName =STATE))
})
private car car;


我尝试了所有可用的hibernate版本(从3.5.1 [ @JoinColumnsOrFormulas ]的第一个版本高达4.xx),但我总是得到这个错误:

 线程main中的异常java.lang.ClassCastException:org.hibernate.mapping.Formula无法转换为org.hibernate.mapping.Column 
at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:351)
at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1338)
at org.hibernate。在org.hibernate.cfg.annotations处
。 CollectionBinder $ 1.secondPass(CollectionBinder.java:668)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPas
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1597)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1355)
在org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1737)
在org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1788)

其他hibernate用户似乎也有同样的问题:他们无法使用任何版本,查看此线程和其他stackoverflow问题:
https://forum.hibernate.org/viewtopic.php?f = 1& t = 1010559


为了更加完整,这里是我的TrimmedString类:
https://forum.hibernate.org/viewtopic.php?p=2191674&sid=049b85950db50a8bd145f9d ac49a5f6e#p2191674



预先感谢!



PS:只有一个DEP-NR-柱(即, DEP_NR USR_DEP_NR只需使用@JoinColumns)。但是我需要这个 coalesce(nullif())

解决方案

加入公式暂时在Hibernate中非常脆弱;我总是很难让它们正常工作。



这个解决方案帮助我经常创建数据库视图,这些数据视图暴露了正确的列(包括外键, t存在于原始表格中)。然后,我使用Hibernate / JPA映射类将实体映射到视图。

有时在使用这些实体时,生成的SQL中会有冗余连接,但数据库会优化这些查询在大多数情况下,这样的执行计划无论如何都是最优的。

另一种方法是使用 @Subselect s ,这是一些Hibernate视图,但我预计它们的性能会低于经典数据库视图。


I'm trying to write a hibernate adapter for an old database schema. This schema does not have a dedicated id column, but uses about three other columns to join data.

On some tables, I need to use coalesce. This is what I came up with so far:

About the definition:

  • A car can have elements, assigned by the car's user or by the car's group of users.
  • If FORIGN_ELEMENT holds a user's name, definition will be 'u'
  • If FORIGN_ELEMENT holds a group's name, definition will be 'g'
  • This also means, one table (CAR_TO_ELEMENT) is misused to map cars to elements and cargroups to elements. I defined a superclass CarElement and subclasses CarUserElement and CarGroupElement.
  • state is either "active" or an uninteresting string
  • I set definitition and state elsewhere, we do not need to worry about this.
  • Use DEP_NR on the join table. If it's zero, use USR_DEP_NR. I did this with COALESCE(NULLIF()) successfully in native SQL and want to achieve the same in Hibernate with Pojos.

Okay, here we go with the code:

@Entity
@Table(name="CAR")
public class Car extends TableEntry implements Serializable {
    @Id
    @Column(name="DEP_NR")
    private int depnr;

    @Id
    @Column(name="USER_NAME")
    @Type(type="TrimmedString")
    private String username;

    @ManyToOne(fetch = FetchType.EAGER, targetEntity=CarGroup.class)
    @JoinColumns(value={ 
            @JoinColumn(name="GROUP_NAME"),
            @JoinColumn(name="DEP_NR"),
            @JoinColumn(name="state"),
    })
    private CarGroup group;

    @OneToMany(fetch=FetchType.EAGER, targetEntity=CarUserElement.class, mappedBy="car")
    private Set<CarUserElement> elements;
}

@Entity
@Table(name="CAR_GROUP")
public class CarGroup extends TableEntry implements Serializable {
    @Id
    @Column(name="DEP_NR")
    private int depnr;

    @Id
    @Column(name="GROUP_NAME")
    @Type(type="TrimmedString")
    private String group;

    @ManyToOne(fetch = FetchType.EAGER, targetEntity=Car.class)
    @JoinColumns(value={ 
            @JoinColumn(name="GROUP_NAME"),
            @JoinColumn(name="DEP_NR"),
            @JoinColumn(name="state"),
    })
    private Set<Car> cars;

    @OneToMany(fetch=FetchType.EAGER, targetEntity=CarGroupElement.class, mappedBy="car")
    private Set<CarGroupElement> elements;
}

@MappedSuperclass
public class CarElement extends TableEntry {
    @Id
    @ManyToOne(fetch = FetchType.EAGER, targetEntity=Element.class)
    @JoinColumns(value={ 
            @JoinColumn(name="ELEMENT_NAME"),
            @JoinColumn(name="state"),
    })
    private Element element;
}

@Entity
@Table(name="CAR_TO_ELEMENT")
public class CarUserElement extends CarElement {
    @Id
    @Column(name="DEFINITION")
    private char definition;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas(value = {
        @JoinColumnOrFormula(formula=@JoinFormula(value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
        @JoinColumnOrFormula(column=@JoinColumn(name="FORIGN_ELEMENT", referencedColumnName="USER_NAME")),
        @JoinColumnOrFormula(column=@JoinColumn(name="STATE", referencedColumnName="STATE"))
    })
    private Car car;

}

@Entity
@Table(name="CAR_TO_ELEMENT")
public class CarGroupElement extends CarElement {
    @Id
    @Column(name="DEFINITION")
    private char definition;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas(value = {
        @JoinColumnOrFormula(formula=@JoinFormula(value="COALESCE(NULLIF(DEP_NR, 0), USR_DEP_NR)", referencedColumnName="DEP_NR")),
        @JoinColumnOrFormula(column=@JoinColumn(name="FORIGN_ELEMENT", referencedColumnName="GROUP_NAME")),
        @JoinColumnOrFormula(column=@JoinColumn(name="STATE", referencedColumnName="STATE"))
    })
    private Car car;

}

I tried all available versions of hibernate (from 3.5.1 [first version with @JoinColumnsOrFormulas] up to 4.x.x), but I always get this error:

Exception in thread "main" java.lang.ClassCastException: org.hibernate.mapping.Formula cannot be cast to org.hibernate.mapping.Column
    at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:351)
    at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1338)
    at org.hibernate.cfg.annotations.CollectionBinder.bindOneToManySecondPass(CollectionBinder.java:791)
    at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:719)
    at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:668)
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:66)
    at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1597)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1355)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1737)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1788)

Other hibernate users seem to have the same problem: They can't get it working with any version, see this thread and other stackoverflow questions: https://forum.hibernate.org/viewtopic.php?f=1&t=1010559

To be more complete, here's my TrimmedString Class: https://forum.hibernate.org/viewtopic.php?p=2191674&sid=049b85950db50a8bd145f9dac49a5f6e#p2191674

Thanks in advance!

PS: It works with joining just these three colulmns with just one DEP-NR-Column (i.e. either DEP_NR OR USR_DEP_NR using just @JoinColumns). But I need this coalesce(nullif()).

解决方案

Join formulas are very fragile in Hibernate for the time being; I always had a difficult time to get them work properly.

The workaround that helped me often was to create database views which exposed the proper columns (including foreign keys that don't exist in the original tables). Then I mapped the entities to the views using classing Hibernate/JPA mappings.

Sometimes there are redundant joins in the generated SQL when using such entities, but the database optimizes such queries in most cases so that the execution plan is optimal anyway.

Another approach could be using @Subselects, which are some kind of Hibernate views, but I expect them to be less performant than the classic database views.

这篇关于Hibernate和@JoinFormula:org.hibernate.mapping.Formula不能转换为org.hibernate.mapping.Column的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆