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