将父项和子项实体与notnull外键保存在父项中(Spring JPA / Hibernate)

时间:2017-07-21 10:19:06

标签: hibernate spring-data-jpa one-to-many many-to-one bidirectional-relation

我在MySQL数据库中有两个实体,我希望实现双向映射,并在保存新父项时自动保存新子项。

MACCHINA(父级)字段:id,marca

PERSONA(子)字段:id,nome,macchina_id(外键NOT NULL)

当我保存新的MACCHINA时,我还要通过此JSON保存新的PERSONA:

{
  "marca": "string",
  "personas": [
    {
      "nome": "string"
    }
  ]
}

MACCHINA实体:

@Entity
@Table(name = "macchina")
public class Macchina implements Serializable {

    private static final long serialVersionUID = 1L;

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

    @NotNull
    @Column(name = "marca", nullable = false)
    private String marca;

    @OneToMany(mappedBy = "macchina", cascade = CascadeType.ALL)
    private Set<Persona> personas = new HashSet<>();

    // getters and setters ...
}

PERSONA实体:

@Entity
@Table(name = "persona")
public class Persona implements Serializable {

    private static final long serialVersionUID = 1L;

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

    @NotNull
    @Column(name = "nome", nullable = false)
    private String nome;

    @ManyToOne(optional = false)
    @JoinColumn(name="macchina_id", referencedColumnName = "id", nullable = false)
    private Macchina macchina;

        // getters and setters ...
    }

在这种情况下,当我在Macchina实体上调用JPA存储库方法.save()时,我就是例外:

> Caused by:
> com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
> Column 'macchina_id' cannot be null

在同一场景中,我试图在数据库中删除NotNull约束到字段&#34; macchina_id&#34;在Persona表中;在这种情况下,交易被执行,但是&#34; macchina_id&#34; Persona表中的字段为NULL。

我找到了解决方法,将NotNull约束移除到&#34; macchina_id&#34;在数据库中(以及实体中的注释)并通过以这种方式修改从父项到子项的映射:

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "macchina_id")
private Set<Persona> personas = new HashSet<>();

我删除了&#34; mappedBy&#34;并添加了@JoinColumn。 这样就可以了:Hibernate执行插入Macchina,插入Persona,最后更新到Persona(我想编写/更新macchina_id字段)。

我的目标是为字段保留NotNull属性&#34; macchina_id&#34;在数据库中;在映射字段private Macchina macchina;上的子实体中保留一些属性值,如@NotNull / nullable = false / @ManyToOne(optional = false),并使用&#34; macchina_id&#34同时保存这两个实体; Spring / Hibernate自动验证字段,无需手动编写代码。

那么,有一种自动方式(Spring / Hibernate)首先保存父级,然后保存对父级具有NotNull外键的子级吗?

有什么建议吗?

此致,Andrea

3 个答案:

答案 0 :(得分:1)

我遇到了完全相同的问题,经过大量搜索后发现了该线程。我终于解决了。 基本上,JPA(或Hibernate-不确定)似乎无法单独在子级中设置父级引用(即使您设置了注释)。因此,在 ParentEntity 中,您应该执行以下操作:

@Entity
public class ParentEntity {

    @OneToMany(mappedBy = "parentReference", cascade = CascadeType.ALL) // parentReference, the property in ChildEntity class
    private final List<ChildEntity> childEntities = new ArrayList<>();

    public ParentEntity(ParentDTO parentDTO) {
        ...
        this.childEntities.add(new ChildEntity(parentDTO.getChildDTO(), this)); // NOTE second param "this"
    }
}

并在 ChildEntity 中设置父级引用

@Entity
public class ChildEntity {

    @ManyToOne
    @JoinColumn(name = "child_foreign_key_column_name", nullable = false)
    private final ParentEntity parentReference;

    public ChildEntity(ChildDTO child, ParentEntity parentReference) {
        ...
        this.parentReference = parentReference;
    }
}

答案 1 :(得分:0)

用于执行保存的代码非常简单:我从REST接收JSON到DTO,然后我将DTO映射到域对象,最后我调用JpaRepository的方法.save()。

@Override
@Transactional
public MacchinaDTO save(MacchinaDTO macchinaDTO) {
    log.debug("Request to save Macchina : {}", macchinaDTO);
    Macchina macchina = macchinaMapper.toEntity(macchinaDTO);
    macchina = macchinaRepository.save(macchina);
    return macchinaMapper.toDto(macchina);
}

答案 2 :(得分:0)

我想尽量避免手动将Macchina添加到每个Persona。我试图通过Spring / Hibernate来管理它(因为如果我从外键中删除not null约束,它可以工作)。

为了做这个例子,我使用的是用项目生成器JHipster生成的项目(如果你知道的话),它使用MapStruct来映射DTO和域:

/**
 * Contract for a generic dto to entity mapper.
 @param <D> - DTO type parameter.
 @param <E> - Entity type parameter.
 */

public interface EntityMapper <D, E> {
    public E toEntity(D dto);
    public D toDto(E entity);
    public List <E> toEntity(List<D> dtoList);
    public List <D> toDto(List<E> entityList);
}

/**
 * Mapper for the entity Macchina and its DTO MacchinaDTO.
 */
@Mapper(componentModel = "spring", uses = {PersonaMapper.class})
public interface MacchinaMapper extends EntityMapper <MacchinaDTO, Macchina> {

    default Macchina fromId(Long id) {
        if (id == null) {
            return null;
        }
        Macchina macchina = new Macchina();
        macchina.setId(id);
        return macchina;
    }
}

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2017-07-21T11:57:12+0200",
    comments = "version: 1.1.0.Final, compiler: Eclipse JDT (IDE) 3.12.3.v20170228-1205, environment: Java 1.8.0_141 (Oracle Corporation)"
)
@Component
public class MacchinaMapperImpl implements MacchinaMapper {

    @Autowired
    private PersonaMapper personaMapper;

    @Override
    public MacchinaDTO toDto(Macchina arg0) {
        if ( arg0 == null ) {
            return null;
        }

        MacchinaDTO macchinaDTO = new MacchinaDTO();

        macchinaDTO.setId( arg0.getId() );
        macchinaDTO.setMarca( arg0.getMarca() );
        Set<PersonaDTO> set = personaSetToPersonaDTOSet( arg0.getPersonas() );
        if ( set != null ) {
            macchinaDTO.setPersonas( set );
        }

        return macchinaDTO;
    }

    @Override
    public List<MacchinaDTO> toDto(List<Macchina> arg0) {
        if ( arg0 == null ) {
            return null;
        }

        List<MacchinaDTO> list = new ArrayList<MacchinaDTO>();
        for ( Macchina macchina : arg0 ) {
            list.add( toDto( macchina ) );
        }

        return list;
    }

    @Override
    public Macchina toEntity(MacchinaDTO arg0) {
        if ( arg0 == null ) {
            return null;
        }

        Macchina macchina = new Macchina();

        macchina.setId( arg0.getId() );
        macchina.setMarca( arg0.getMarca() );
        Set<Persona> set = personaDTOSetToPersonaSet( arg0.getPersonas() );
        if ( set != null ) {
            macchina.setPersonas( set );
        }

        return macchina;
    }

    @Override
    public List<Macchina> toEntity(List<MacchinaDTO> arg0) {
        if ( arg0 == null ) {
            return null;
        }

        List<Macchina> list = new ArrayList<Macchina>();
        for ( MacchinaDTO macchinaDTO : arg0 ) {
            list.add( toEntity( macchinaDTO ) );
        }

        return list;
    }

    protected Set<PersonaDTO> personaSetToPersonaDTOSet(Set<Persona> set) {
        if ( set == null ) {
            return null;
        }

        Set<PersonaDTO> set_ = new HashSet<PersonaDTO>();
        for ( Persona persona : set ) {
            set_.add( personaMapper.toDto( persona ) );
        }

        return set_;
    }

    protected Set<Persona> personaDTOSetToPersonaSet(Set<PersonaDTO> set) {
        if ( set == null ) {
            return null;
        }

        Set<Persona> set_ = new HashSet<Persona>();
        for ( PersonaDTO personaDTO : set ) {
            set_.add( personaMapper.toEntity( personaDTO ) );
        }

        return set_;
    }
}