HIbernate的实体自关联如何写配置文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HIbernate的实体自关联如何写配置文件相关的知识,希望对你有一定的参考价值。

例如,我们写一个类来描述生活中的接口,架设写的是RJ45接口,因为RJ45接口只能与RJ45接口连接,所以在RJ45接口类里面有一个linker是RJ45类型的,那么在这种情况下怎么写关联呢?已知写成<one-to-one name="linker" />的话是不行的。求大牛指导、、、

单项的配置many-to-one吧,如果是一对一,还要在里面写unique="true",本来是多对一,但是加上unique="true",就表示唯一,那就是一对一了。
如果是双向关联,则要在另外一边配置one-to-one,property_ref="linker",property_ref=""相当于mappedBy,就是指定由哪一方来维护双方的关系。
写配置文件累死了,而且时不时有一些错误,直接用Annotation方便得多,其实hibernate帮助文档上提供了很多例子,要学会穿一手鞋,主动学习放弃被动灌输。

以下是1对1的关系配置
一对一:(少用,可以合成一张表,数据库表一般设计成单向外键关联或主键关联)
外键关联:
单向:@OneToOne @JoinColumn指定外键列名 <many-to-one unique="true"/>
双向:@OneToOne(MappedBy,意思是由哪边维护关联关系,相当与xml中的inverse)
<many-to-one unique="true"/> <one-to-one property_ref=""/>(property_ref相当于MappedBy) 两个都用<many-to-one/>也会生成两个外键

注意:
1、对于双向关联除了双向主键关联,annotation必须加MappedBy(否则会产生冗余外键)
2、设置MappedBy还可以在添加的时候由对方设置关联不再需要两边都设置追问

这些对自关联都是不起作用的,因为自关联它关联的本来就是自身的实体,在写关联关系时,它只能写一个而已。

追答

那你把一张表看做两张表,一个对象看做两个对象不就行了么
比如Oracle数据库中的scott用户下有一张emp表,其中有两个列:empno和mgr是一模一样的,empno是员工编号,mgr是上司的员工编号,而上司也属于一个员工,所以mgr这个列中的数据都是引用empno这个列的。
写java实体类的时候,你只要在该类中加入一个自己的引用,用来表示上司,不就行了?如果还要找出你的下属,那就加一个Set集合,集合中的对象就是自己。
@Entity
public class Emp
@Id
private int empno;

private String ename;

//下属和上司存在1对多的关系,也就是1个上司有多个下属,所以是ManyToOne

@ManyToOne

private Emp mgr; //这就是引用自己

//双向关联时,只要加上OneToMany就行了,关系肯定是由多的一方维护,所以加mappedBy

@OneToMany(mappedBy="mgr")

private Set xiashu; //这就是你的下属



这样就是自联1对多,自联1对1还不就是一样的。

参考技术A <one-to-many unique="true"> 参考技术B 当一般的单向 one-to-one 写。

如何使用 JPA 和 Hibernate 为关联的只读实体获取单个实例?

【中文标题】如何使用 JPA 和 Hibernate 为关联的只读实体获取单个实例?【英文标题】:How to get a single instance for an associated read-only entity with JPA and Hibernate? 【发布时间】:2019-07-18 08:10:49 【问题描述】:

我有这两个实体:

@Entity
@Immutable
@Cacheable
@Cache(region = "dosefrequency", usage = CacheConcurrencyStrategy.READ_ONLY)
public class DoseFrequency
   .....
 

@Entity
public class PrescriptionDrug 

     .....
    @ManyToOne(optional=false)
    @JoinColumn(name="doseFrequency")   
    public DoseFrequency getDoseFrequency() 
        return doseFrequency;
     


DoseFrequency 是一个只读实体,PrescriptionDrug 关联了一个 DoseFreqyency。我希望每次加载一个或多个 PrescriptionDrug 时都不会重复 DoseFrequency 的实例。

我知道 DoseFrequency 实例将被缓存在 hibernate 的一级缓存中,但加载是在几个会话中完成的(它是一个 web 应用程序)。我用的是二级缓存,但是那个缓存不存储实例只序列化实体。

我在 DoseFrequency 中使用 Tuplizer 得到了这种行为,但我不知道是否有任何其他方法可以实现这一点。

@Entity
@Immutable
@Cacheable
@Cache(region = "dosefrequency", usage = CacheConcurrencyStrategy.READ_ONLY)
@Tuplizer(impl=DoseFrequencyTuplizer.class)
public class DoseFrequency 
   ....



public class DoseFrequencyTuplizer extends PojoEntityTuplizer 

    public DoseFrequencyTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) 
        super(entityMetamodel, mappedEntity);
    

    @Override
    protected Instantiator buildInstantiator(EntityMetamodel entityMetamodel, PersistentClass persistentClass) 
        return new DoseFrequencyInstantiator(DoseFrequency.class.getName(),entityMetamodel,persistentClass,null);
    

    


public class DoseFrequencyInstantiator implements Instantiator 

    private final Class targetClass;
    protected PojoEntityInstantiator pojoEntityInstantiator;

    public DoseFrequencyInstantiator(String targetClassName, EntityMetamodel entityMetamodel,
            PersistentClass persistentClass, ReflectionOptimizer.InstantiationOptimizer optimizer) 
        try 
            this.targetClass = Class.forName(targetClassName);
         catch (ClassNotFoundException e) 
            throw new HibernateException(e);
        

        pojoEntityInstantiator = new PojoEntityInstantiator(entityMetamodel, persistentClass, optimizer);

    

    @Override
    public Object instantiate(Serializable id) 
        DoseFrequency df = MedereEMRCache.instance.findDoseFrequencyByID(Long.valueOf(id.toString()));
        if (df == null) 
            return pojoEntityInstantiator.instantiate(id);
        
        return df;
    

    @Override
    public Object instantiate() 
        return instantiate(null);
    

    @Override
    public boolean isInstance(Object object) 
        try 
            return targetClass.isInstance(object);
         catch (Throwable t) 
            throw new HibernateException("could not get handle to entity as interface : " + t);
        
    


我知道实例将在应用程序的所有线程之间共享,但它们被视为只读,因此不应修改。

这种方法对吗?

谢谢

【问题讨论】:

【参考方案1】:

您也可以使用LoadEventListener 来始终为同一个实例提供服务。尽管如此,由于实体是不可变的,因此不需要此功能,因此,即使您有多个副本,它仍然是不可变的。

此外,即使你实现了单例模式,它也只会在每个 JVM 中强制执行,所以我不明白你为什么要实现这个请求。

实体仅被视为每个EntityManager 的单例。

【讨论】:

感谢弗拉德的回答。在 VisualVM 的采样器中,不可变对象的实例总是在我每次加载它们时上升(当然 GC 会清理它们)。我想避免像单例一样为这些实体实现。我将尝试使用 LoadEventListener,再次感谢您

以上是关于HIbernate的实体自关联如何写配置文件的主要内容,如果未能解决你的问题,请参考以下文章

hibernate 的 关联关系之多对多 和 延迟加载

hibernate多对一关联映射两种形式的理解

hibernate中多表映射关系配置

hibernate中多表映射关系配置

hibernate之一

hibernate映射postgreSQL数据库中的表时,表名是大写的时候为啥hibernate不能映射实体