当前位置: 首页 > 知识库问答 >
问题:

当DTO中存在相同类型的对象列表时,如何使用ModelMapper

太叔志尚
2023-03-14

我有以下型号。

组织模式

@Data
@Entity
@Table()
@JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id" )
public class Organization implements Serializable {
     @Id
     @GeneratedValue( strategy = GenerationType.IDENTITY )
     private Long id;

     private String name;
     .
     .
     .

     @OneToMany( mappedBy = "organization", cascade = CascadeType.MERGE, targetEntity = User.class )
     private Set< User > users;
}

用户模型

@Data
@Entity
@DynamicUpdate
@Table( name = RelationsConstant.TBL_USER_AUTH )
public class User implements Serializable {

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long id;

    private String name;
    .
    .
    .
    @ManyToOne( cascade = CascadeType.MERGE, targetEntity = Organization.class )
    @JoinColumn( nullable = false, foreignKey = @ForeignKey( name = org_usr_fk ) )
    private Organization organization;

    @ManyToMany( fetch = FetchType.EAGER, cascade = CascadeType.MERGE )
    @JoinTable( name = RelationsConstant.TBL_USER_AUTH_ROLE, //
        joinColumns = @JoinColumn( name = "base_user_id", referencedColumnName = "base_user_id", nullable = false ), //
        inverseJoinColumns = @JoinColumn( name = "role_id", referencedColumnName = "id", nullable = false ), //
        uniqueConstraints = { @UniqueConstraint( columnNames = { "base_user_id", "role_id" } ) } )
    private Set< Role > roles;

}

组织DTO

@Data
public class OrganizationDto implements Serializable {
     private Long id;
     private String name;
     private Set<UserDto> users;
}

用户DTO

@Data
public class UserDto implements Serializable {
     private Long id;
     private String name;
     private OrganizationDto organization;
     private Set<RoleDto> roles;
}

当我尝试将这些模型映射到DTO时,我得到以下错误。

处理请求时出错org.modelmapper.MappingException: ModelMapper映射错误:\r\n\r\n1)将组织映射到组织Dto时出错。

下面是我使用的转换器。

public class SetUserToSetUserDtoConverter implements Converter< Set< User >, Set< UserDto > > {

    @Override
    public Set< UserDto > convert( MappingContext< Set< User >, Set< UserDto > > context ) {
        ModelMapper mapper = new ModelMapper( );

        TypeMap< User, UserDto > propertyMapper = mapper.createTypeMap( User.class, UserDto.class );
        propertyMapper.addMappings( mpr -> {
            mpr.skip( User::getOrganization, UserDto::setOrganization );
            mpr.skip( User::getRoles, UserDto::setRoles );
            mpr.skip( User::getPrivileges, UserDto::setPrivileges );
            mpr.skip( User::getPassword, UserDto::setPassword );
        } );

        Set< User > source = context.getSource( );

        return source.stream( ).map( m -> mapper.map( m, UserDto.class ) ).collect( Collectors.toSet( ) );
    }

}

这就是映射器的配置方式。

public List< OrganizationDto > getAll() {
    ModelMapper mapper = new ModelMapper( );
    mapper.getConfiguration( ).setMatchingStrategy( MatchingStrategies.STRICT ).setFieldMatchingEnabled( true ).setFieldAccessLevel( Configuration.AccessLevel.PRIVATE );

    /** With Converter **/
    TypeMap< Organization, OrganizationDto > typeMap = mapper.createTypeMap( Organization.class, OrganizationDto.class );

    typeMap.addMappings( mpr -> mpr.using( new SetUserToSetUserDtoConverter( ) ).map( Organization::getUsers, OrganizationDto::setUsers ) );

    return orgRepo.findAll( ).stream( ).map( m -> mapper.map( m, OrganizationDto.class ) ).collect( Collectors.toList( ) );
}

我发现当我从UserDto类中删除组织字段并从Converter类中删除行mpr.skip(UserDto::setGroup);时,这个模型映射工作正常。

转换器被定义为将User Object Set转换为UserDto Object Set并跳过组织Dto字段的转换。用户对象和UserDto对象有设置

任何纠正这一点的线索都非常感谢。提前感谢。


共有1个答案

南门烈
2023-03-14

而不是我的自定义转换器类(SetUserToSetUserDtoConverter类)中的以下代码,

    TypeMap< UserAuth, UserAuthDto > propertyMapper = mapper.createTypeMap( UserAuth.class, UserAuthDto.class );
    propertyMapper.addMappings( mpr -> {
        mpr.skip( UserAuthDto::setOrganization );
        mpr.skip( UserAuth::getRoles, UserAuthDto::setRoles );
        mpr.skip( UserAuth::getPrivileges, UserAuthDto::setPrivileges );
        mpr.skip( UserAuth::getPassword, UserAuthDto::setPassword );
    } );

我使用下面的代码跳过了组织和不必要的字段以及其他字段。

PropertyMap< UserAuth, UserAuthDto > skipped = new PropertyMap< UserAuth, UserAuthDto >( ) {

                @Override
                protected void configure() {
                    skip( ).setOrganization( null );
                    skip( ).setRoles( null );
                    skip( ).setPrivileges( null );
                    skip( ).setPassword( null );
                }

            };

首先,我怀疑userdt中的组织字段是否会创建循环引用循环之类的东西。但我的跳场逻辑似乎不正确。

问题现已解决。

完全正确的转换器实现如下。

公共类SetUserToSetUserDtoConverter实现转换器

@Override
public Set< UserDto > convert( MappingContext< Set< User >, Set< UserDto > > context ) {
    ModelMapper mapper = new ModelMapper( );
    mapper.getConfiguration( ).setMatchingStrategy( MatchingStrategies.STRICT ).setFieldMatchingEnabled( true );

    PropertyMap< User, UserDto > skipped = new PropertyMap< User, UserDto >( ) {

        @Override
        protected void configure() {
            skip( ).setOrganization( null );
            skip( ).setRoles( null );
            skip( ).setPrivileges( null );
            skip( ).setPassword( null );
        }

    };

    mapper.addMappings( skipped );

    Set< User > source = context.getSource( );

    return source.stream( ).map( m -> mapper.map( m, UserDto.class ) ).collect( Collectors.toSet( ) );
}

}

从艾米·德雷戈里奥(Amy DeGregorio)2018年发布的以下nice博客中获得了想法和参考。https://amydegregorio.com/2018/05/23/skipping-fields-with-modelmapper/

 类似资料:
  • 假设我有两个列表,现在listOld包含旧员工信息,listNew包含新员工信息 我如何比较这两个列表并返回新列表,其中包含,添加的新员工列表,包含,删除的员工列表,包含上次更新已更改的员工的新列表? 我只能想到迭代列表和比较,可能最终几乎是O(n2)时间,这可以由任何util类更有效地完成吗?

  • 问题内容: 我对此进行了扩展,应该可以帮助我在上下文之间传输对象: 现在它返回的对象,我应该将其强制转换为我想要的类,如下所示: 有没有办法避免这种无用的转换,如果我从类的对象调用使其返回类型? 问题答案: 更新: 有关更好的解决方案 与如何在NSManagedObjectSwift扩展中如何创建托管对象子类的实例中类似,这可以使用通用的辅助方法来完成: 请注意,我已将返回类型更改为。 并 没有

  • 每个类都有一些独特的字段。所有最大的功能是:添加,更新,删除,查找,显示列表,保存,加载文件 -所以,首先我将创建一个名为Product的类,它有4个公共字段。以上课程将从产品延伸。 -然后,我想我可能会创建一个ComputerStore类,它有一个字段是items类型ArrayList。items存储所有的对象,这些对象是上述4个类的实例,但我不确定。

  • 当我保存以下实体时,它在另一个对象中复制相同的值: 例如,在我的struts项目(屏幕)中,如果我更改shipmentShipper字段的值,那么Shipment收货人也将使用相同的值进行更新。 实体: 仓库类: JSP中的字段映射(工作正常): 请检查屏幕截图,我将发货人更改为C4并保存。收货人也被选为C4。请注意,两个选择都使用相同的数据列表填充。(客户名单)

  • 我在http://neo4j.com/docs/ogm/java/stable/遵循Neo4j OGM指南 对于关系实体,我们需要有一个开始节点和一个结束节点。我对这个例子做了一点修改(使它像这样更简单)- 现在,当我尝试保存这个在Neo4j,它工作正常。但是在我的场景中,StartNode和EndNode对象的类型是相同的- 当我尝试使用- 学生、课程和注册对象被保存,但两个MyObject和M

  • 我是java新手,正在努力克服它。我有类似(< code>String URL,int Score)的数据,我想在数组列表中实现它。我研究了如何在< code>ArrayList或< code>LinkedList中实现多种类型的变量,发现解决方案是从超类创建子类,我创建了这个子类: 我的超级班是: 当我尝试使用添加对象时,我遇到了错误?该错误说: 类型ArrayList中的add(int,MyS