简体   繁体   English

用hibernate和mysql检索多态实体

[英]retrieving polymorphic entities with hibernate and mysql

In a spring mvc application using hibernate over a MySQL database, I have an AccessLog entity that records the activities performed by various types of actors on various types of target resources. 在使用MySQL数据库休眠的spring mvc应用程序中,我有一个AccessLog实体,该实体记录各种类型的参与者在各种类型的目标资源上执行的活动。 For simplicity, I am using polymorphism to store all the actor ids in one column and all the target resource ids in another column, regardless of their type. 为简单起见,我使用多态性将所有actor ids存储在一个列中,并将所有target resource ids在另一列中,而不管它们的类型如何。 But how do I query the target entities and actor entities later? 但是,以后如何查询目标实体和参与者实体?

Here is the AccessLog entity. 这是AccessLog实体。 It currently uses an actor_type string property to indicate the type of the entity whose id is stored in actorentity_id , and another string property target_type to indicate the type of entity whose id is stored in targetentity_id . 当前,它使用actor_type字符串属性指示其id存储在actorentity_id中的实体的type ,并使用另一个字符串属性target_type指示其id存储在targetentity_id的实体的类型。 But this could get messy because it relies on logic in the application's business layer to manage all the string type values. 但这可能会变得混乱,因为它依赖于应用程序业务层中的逻辑来管理所有字符串类型值。 I could add a type property to BaseEntity , but that would still involve managing the type values in the business layer. 我可以将类型属性添加到BaseEntity ,但这仍将涉及在业务层中管理类型值。 How can I set things up so that this is designed most elegantly? 我该如何设置东西,使其设计得最优雅?

@Entity
@Table(name = "accesslogs")
public class AccessLog extends BaseEntity{

    @ManyToOne
    @JoinColumn(name = "actorentity_id")
    private BaseEntity actor_entity;

    @ManyToOne
    @JoinColumn(name = "targetentity_id")
    private BaseEntity target_entity;

    @Column(name="actorentity_type")//this could get messy
    private String actor_type;

    @Column(name="targetentity_type")//this could get messy
    private String target_type;

    @Column(name="action_code")
    private String action;

    @Column(name="access_date")
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime accessdate;

    //getters and setters
}

Here is the BaseEntity 这是BaseEntity

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    protected Integer id;

    public void setId(Integer id) {this.id = id;}
    public Integer getId() {return id;}
}

Here are a couple of examples of types of actor entities that extend BaseEntity, and which could be stored in the AccessLog.actor_entity property: 这是几个扩展BaseEntity的actor实体类型的示例,可以存储在AccessLog.actor_entity属性中:

@Entity
@Table(name="users")
public class User extends BaseEntity{
    //other stuff
}

@Entity
@Table(name="externalsystems")
public class ExternalSystem extends BaseEntity{
    //other stuff
}

Here is the DDL: 这是DDL:

CREATE TABLE IF NOT EXISTS accesslogs(
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  actorentity_id int(11) UNSIGNED NOT NULL,
  targetentity_id int(11) UNSIGNED NOT NULL,
  actorentity_type varchar(100), #This could get messy
  targetentity_type varchar(100), #This could get messy
  action_code varchar(100),
  access_date DATETIME
)engine=InnoDB;SHOW WARNINGS;

CREATE TABLE IF NOT EXISTS users(
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  #other stuff
)engine=InnoDB;SHOW WARNINGS;

CREATE TABLE IF NOT EXISTS externalsystems(
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  #other stuff
)engine=InnoDB;SHOW WARNINGS;

Based on the problem you propose, there are two possible solutions. 根据您提出的问题,有两种可能的解决方案。 If you want to code a custom solution for the problem you should do the following code. 如果要为该问题编写自定义解决方案,则应执行以下代码。

Here is how the BaseEntity will look like 这是BaseEntity的样子

@MappedSuperClass
public abstract class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Integer id;

    public Integer getId() {return id;}
}

An intermediate class would be needed (Let's call it AuditableEntity) 需要一个中间类(我们称它为AuditableEntity)

@Entity
@Inheritance(strategy=InheritanceType.Joined)    
public abstract class AuditableEntity extends BaseEntity {

    @OneToMany(mappedBy="actor")
    private List<AccessLog> actorLogs;

    @OneToMany(mappedBy="target")
    private List<AccessLog> targetLogs;
}

All your actors should extend from this class, so for example your User entity will look like this: 您的所有参与者都应从此类扩展,例如,您的User实体将如下所示:

@Entity
@PrimaryKeyJoinColumn
public class User extends AuditableEntity{
    //other stuff
}

At last your AccessLog will look like this: 最后,您的AccessLog将如下所示:

@Entity
@Table(name = "accesslogs")
public class AccessLog extends BaseEntity{

    @ManyToOne
    @JoinColumn
    private AuditableEntity actor;

    @ManyToOne
    @JoinColumn
    private AuditableEntity target;

    @Column(name="action_code")
    private String action;

    @Column(name="access_date")
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime accessdate;

    //getters and setters
}

But I will not implement this approach, a better solution is to use Hibernate Envers . 但是我不会实现这种方法,更好的解决方案是使用Hibernate Envers Check the link I posted here related to that project. 检查我在此处发布的与该项目相关的链接。 Your solution will require much code in all aspects each time you made changes to the data. 每次更改数据时,您的解决方案在各个方面都需要大量代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM