MappingException:使用Entity子类作为Command时的未知实体

时间:2012-12-12 15:15:43

标签: java spring hibernate spring-mvc spring-3

我有一个用hibernate注释映射的User对象工作正常。

例如

@Entity
public class User implements Serializable {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long userId;

   etc ..
}

然后我使用Spring 3 MVC创建了一个“添加用户”表单,我需要一个命令对象来支持这个表单,所以我在UserCommand中从上面创建了子类。 UserCommand上有一些与Web界面相关的额外内容,不需要保存为用户实体的一部分。

例如

public class UserCommand extends User {

    private String initialAddress;

    etc
}

所以我的视图/表示层基本上创建了一个UserCommand对象,填写了用户详细信息,然后控制器将其提交到service / dao层以保持不变。由于UserCommand扩展(“is-a”)用户dao接受UserCommand实例并且它传递dao验证检查(例如,确保填写了用户名和密码)。

然而,当hibernate实际上将对象持久化为db中的实体时,它似乎意识到实际对象是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的扩展名(即UserCommand)作为表单的后备命令对象。

或者我是否必须打破继承,在UserCommand中复制User的字段,并在表单提交期间将UserCommand中的所有值显式复制到User中?

3 个答案:

答案 0 :(得分:2)

我认为混合数据库和视图实体是一种不好的做法。这些是不同的层,它们应该在不同的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之间的转换需要一些复杂的逻辑,您可以将这些方法移动到转换服务。

拆分这些实体的一个好处是验证。您可以指定JSR-303注释来验证这些bean,在大多数情况下,它们对于UI和DB都是不同的。

答案 1 :(得分:0)

同意Hoaz。如果您想轻松地将对象的每个字段从DTO复制到DB,可以使用Dozer实用程序。

答案 2 :(得分:0)

我刚刚在Hibernate 3.6中遇到过这个问题,你可以明确定义一个子类。

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html

使用xml,您可以:

<subclass name="DomesticCat"
          discriminator-value="D">
   <property name="name" type="string"/>
</subclass>

或使用注释:

@Entity @DiscriminatorValue("D")
public class DomesticCat extends Cat {
   //class implementation here
}

修改
不要忘记描述者。

<discriminitor insert="false" formula="'C'" />

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(discriminatorType=DiscriminatorType.STRING, insert=false)
@DiscriminatorFormula("'C'")
@DiscriminatorValue("C")
public class Cat { ... }