在使用hibernate通过MySQL数据库的spring mvc应用程序中,我有一个AccessLog
实体,它记录各种类型的actor在各种类型的目标资源上执行的活动。为简单起见,我使用多态来将所有actor ids
存储在一列中,将所有target resource ids
存储在另一列中,而不管其类型如何。 但是我如何在以后查询目标实体和参与者实体?
这是AccessLog
实体。它当前使用actor_type
字符串属性来指示type
存储在id
中的实体的actorentity_id
,以及另一个字符串属性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;
答案 0 :(得分:1)
根据您提出的问题,有两种可能的解决方案。如果要为问题编写自定义解决方案,则应执行以下代码。
以下是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。检查我在此处发布的与该项目相关的链接。每次更改数据时,您的解决方案都需要很多代码。