3

我尝试使用 Dozer 将我的域实体转换为 DTO 对象。所以,我想在我的 DTO 对象中将 PersistentList, PersistentBag, ... 从我的域实体转换为 ArrayList, ... 以避免惰性问题。

这是我的两个域实体的示例:

public class User {
      private Collection<Role> roles;
      ...
}

public class Role {
      private Collection<User> users;
      ...
}

我的 DTO 对象是相同的,只是该类是 DTO 类型。因此,要将域转换为 DTO 对象,我使用以下推土机映射:

 <configuration>
  <custom-converters>
   <converter type=com.app.mapper.converter.BagConverter">
    <class-a>org.hibernate.collection.PersistentBag</class-a>
    <class-b>java.util.List</class-b>
   </converter>
  </custom-converters>
 </configuration>

 <mapping>
  <class-a>com.app.domain.User</class-a>
  <class-b>com.app.dto.UserDTO</class-b>
 </mapping>

 <mapping>
  <class-a>com.app.domain.Role</class-a>
  <class-b>com.app.dto.RoleDTO</class-b>
 </mapping>

BagConverter 是一个推土机自定义转换器,这是它的代码:

  public class BagConverter<T> extends DozerConverter<PersistentBag, List>{

 public BagConverter() {
  super(PersistentBag.class, List.class);
 }

 public PersistentBag convertFrom(List source, PersistentBag destination) {
  PersistentBag listDest = null;

  if (source != null) {

   if (destination == null) {
    listDest = new PersistentBag();
   } else {
    listDest = destination;
   }

   listDest.addAll(source);
  }

  return listDest;
 }

 public List convertTo(PersistentBag source, List destination) {
  List listDest = null;

  if (source != null) {

   if (destination == null) {
    listDest = new ArrayList<T>();
   } else {
    listDest = destination;
   }

   if (source.wasInitialized()) {
    listDest.addAll(source);
   }
  }

  return listDest;
 }}

所以,我得到一个包含角色的 PersistentBag 的用户对象。我在该对象上应用推土机映射器地图以获取 UserDTO 对象。我得到的结果是一个 UserDTO 对象,它有一个 Role 的 ArrayList,没有我希望的 RoleDTO 的 ArrayList。

我以为即使我使用自定义转换器,推土机也会转换我列表的内容。这不是正确的方法吗?如果不是,如何通过将持久性集合替换为经典 java 集合来将我的域实体转换为 dto 对象?

谢谢你的帮助。

西尔万。

4

4 回答 4

1

我尝试使用 Dozer 将我的域实体转换为 DTO 对象。所以,我想在我的 DTO 对象中将 PersistentList, PersistentBag, ... 从我的域实体转换为 ArrayList, ... 以避免惰性问题。

我得到最后一句话,但我不明白为什么你需要处理o.h.c.PersistentBag(等等),因为这个类一个List. 只需使用这样的东西:

<mapping>
  <class-a>com.myapp.domain.User</class-a>
  <class-b>com.myapp.dto.UserDTO</class-b>
  <field>
    <a>roles</a>
    <b>roles</b>
    <a-hint>com.myapp.domain.Role</a-hint>
    <b-hint>com.myapp.dto.RoleDTO</b-hint>
  </field>
</mapping>

并在分离实体之前执行转换(这是您问题的关键)。

于 2010-05-13T21:34:59.430 回答
1

不幸的是,当您注册时,CustomConverter您将承担映射对象(在您的情况下为集合)的全部责任,包括其所有内容、属性、元素等。

正如我现在所看到的(我以前没有看到它,它必须是某种新功能)。可以使用Dozer 文档中自定义类型转换器章节MapperAware末尾所述的界面。我想这正是您需要的。

于 2010-05-13T16:43:40.423 回答
0

我还测试了一个没有自定义转换器的其他解决方案:

<mapping>
    <class-a>com.myapp.domain.User</class-a>
    <class-b>com.myapp.dto.UserDTO</class-b>
    <field>
        <a>roles</a>
        <b>roles</b>
        <a-hint>com.myapp.domain.Role</a-hint>
        <b-hint>com.myapp.dto.RoleDTO</b-hint>
    </field>
</mapping>

还有一个问题。当 Dozer 尝试将角色从 User 转换为 UserDTO 中 RoleDTO 的角色时,我从 Hibernate 收到一个延迟初始化异常,因为 User 中的角色处于 EAGER 模式。

所以,我不知道如何进行映射。我继续寻找解决这些问题的方法

于 2010-05-14T09:33:43.423 回答
0

正如 Pascal 所说,我不明白直接使用 PersistentBags 的意义。如果在您的@Entity POJO 中您将角色列表声明为经典,java.util.List那么 Hibernate 将自动使用其内部表示。这也是您不能在序列化过程中使用 POJO 的原因。澄清:

@Entity
public class User {
  private java.util.List<Role> roles = new java.util.Arraylist<Role>(); //Hibernate doesn't really care about this new Arraylist stuff, it will use its org.hibernate.collection.PersistentList
  ... //other fields and methods
}

现在,当您想将 Entity POJO 转换为 DTO 对象时,您只需使用 Pascal 建议的映射,也就是

<mapping>
  <class-a>com.myapp.domain.User</class-a>
  <class-b>com.myapp.dto.UserDTO</class-b>
  <field>
    <a>roles</a>
    <b>roles</b>
    <a-hint>com.myapp.domain.Role</a-hint>
    <b-hint>com.myapp.dto.RoleDTO</b-hint>
  </field>
</mapping>

在关闭事务之前进行转换以避免延迟初始化异常,例如:

@Transactional
public UserDTO getUser(...) {
  User user = dao.getUser(...);
  UserDTO dto = //Place your Dozer conversion here
  return dto;
}

正如我的小笔记,我出于同样的原因使用推土机,这就像魅力一样。

于 2013-01-03T09:12:22.487 回答