我有一个与休眠注释映射的User对象,效果很好。
例如
@Entity
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
etc ..
}
然后,我使用Spring 3 MVC创建了一个“添加用户”表单,并且我需要一个命令对象来支持该表单,因此我在UserCommand中从上面将User子类化。 UserCommand上有一些与Web界面等相关的额外内容,不需要另存为User实体的一部分。
例如
public class UserCommand extends User {
private String initialAddress;
etc
}
因此,我的视图/表示层基本上创建了一个UserCommand对象,填写了用户详细信息,然后控制器将其提交到服务/ dao层以持久化。由于UserCommand扩展了用户(“ is-a”),因此dao接受UserCommand实例,并通过dao验证检查(例如,确保已填写用户名和密码)。
但是,当休眠实际上将对象作为数据库中的一个实体持久化时,似乎意识到实际的对象是一个UserCommand,它不是一个映射的实体,即使它是超类型的。
产生的错误是;
org.hibernate.MappingException: Unknown entity: com.example.UserCommand
org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:691)
org.hibernate.impl.SessionImpl.getEntityPersister(SessionImpl.java:1494)
org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:202)
org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:531)
org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:102)
org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
有没有办法解决这个问题?我似乎很容易做,表单正在填写一个User,因此只需使用User的扩展名(即UserCommand)作为表单的后备命令对象。
还是我将不得不中断继承,在UserCommand中复制User的字段,并在提交表单期间将UserCommand中的所有值显式复制到User中?
最佳答案
我认为混合数据库和视图实体是一种不好的做法。这些是不同的层,它们应在不同的DTO上运行。通常,我使用以下模式在两层之间进行转换:
public class UserCommand {
public static UserCommand fromUser(User user) {
UserCommand command = new UserCommand();
// fill UserCommand fields
return command;
}
public void toUser(User user) {
// fill User fields
}
}
如果视图DTO和数据库DTO之间的转换需要一些复杂的逻辑,则可以将这些方法移至转换服务。
拆分这些实体的一个好处是验证。您可以指定JSR-303批注来验证这些bean,并且在大多数情况下,它们对于UI和DB而言将有所不同。