繁体   English   中英

用hibernate和mysql检索多态实体

[英]retrieving polymorphic entities with hibernate and mysql

在使用MySQL数据库休眠的spring mvc应用程序中,我有一个AccessLog实体,该实体记录各种类型的参与者在各种类型的目标资源上执行的活动。 为简单起见,我使用多态性将所有actor ids存储在一个列中,并将所有target resource ids在另一列中,而不管它们的类型如何。 但是,以后如何查询目标实体和参与者实体?

这是AccessLog实体。 当前,它使用actor_type字符串属性指示其id存储在actorentity_id中的实体的type ,并使用另一个字符串属性target_type指示其id存储在targetentity_id的实体的类型。 但这可能会变得混乱,因为它依赖于应用程序业务层中的逻辑来管理所有字符串类型值。 我可以将类型属性添加到BaseEntity ,但这仍将涉及在业务层中管理类型值。 我该如何设置东西,使其设计得最优雅?

@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
}

这是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;}
}

这是几个扩展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
}

这是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;

根据您提出的问题,有两种可能的解决方案。 如果要为该问题编写自定义解决方案,则应执行以下代码。

这是BaseEntity的样子

@MappedSuperClass
public abstract class BaseEntity {

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

    public Integer getId() {return id;}
}

需要一个中间类(我们称它为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;
}

您的所有参与者都应从此类扩展,例如,您的User实体将如下所示:

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

最后,您的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
}

但是我不会实现这种方法,更好的解决方案是使用Hibernate Envers 检查我在此处发布的与该项目相关的链接。 每次更改数据时,您的解决方案在各个方面都需要大量代码。

暂无
暂无

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

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