[英]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.