Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用notnull foreignkey将父实体和子实体同时保存到父实体(Spring JPA/Hibernate)_Hibernate_Spring Data Jpa_One To Many_Many To One_Bidirectional Relation - Fatal编程技术网

使用notnull foreignkey将父实体和子实体同时保存到父实体(Spring JPA/Hibernate)

使用notnull foreignkey将父实体和子实体同时保存到父实体(Spring JPA/Hibernate),hibernate,spring-data-jpa,one-to-many,many-to-one,bidirectional-relation,Hibernate,Spring Data Jpa,One To Many,Many To One,Bidirectional Relation,我在MySQL数据库中有两个实体,我想实现一个双向映射,在保存新父级时自动保存新子级 MACCHINA(父)字段:id,marca 角色(子)字段:id、nome、macchina\u id(外键不为空) 当我保存一个新的MACCHINA时,我还想通过以下JSON保存一个新的角色: { "marca": "string", "personas": [ { "nome": "string" } ] } 麦加中国实体: @Entity @Table(name

我在MySQL数据库中有两个实体,我想实现一个双向映射,在保存新父级时自动保存新子级

MACCHINA(父)字段:id,marca

角色(子)字段:id、nome、macchina\u id(外键不为空)

当我保存一个新的MACCHINA时,我还想通过以下JSON保存一个新的角色:

{
  "marca": "string",
  "personas": [
    {
      "nome": "string"
    }
  ]
}
麦加中国实体:

@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 ...
}
@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 repository方法.save()时,我遇到了一个例外:

> Caused by:
> com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
> Column 'macchina_id' cannot be null
在同一个场景中,我试图在数据库中删除对Persona表中字段“macchina_id”的NotNull约束;在这种情况下,执行事务,但Persona表中的“macchina_id”字段为空

我找到了一种解决方法,通过删除数据库中“macchina_id”(以及实体中的注释)的NotNull约束,并通过以下方式修改从父对象到子对象的映射:

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "macchina_id")
private Set<Persona> personas = new HashSet<>();
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name=“macchina\u id”)
私有集personas=newhashset();
我删除了“mappedBy”并添加了@JoinColumn。 它是这样工作的:Hibernate执行对Macchina的插入,对Persona的插入,最后是对Persona的更新(我想写/更新Macchina_id字段)

我的目标是在数据库中维护字段“macchina_id”的NotNull属性;在映射字段
private Macchina Macchina上的子实体中保存一些属性值如@NotNull/nullable=false/@ManyToOne(可选=false),并使用Spring/Hibernate自动验证的“macchina\u id”字段同时保存这两个实体,而无需手动编写代码

因此,有一种自动方式(Spring/Hibernate)首先保存父级,然后保存具有指向父级的NotNull外键的子级

有什么建议吗


关于,Andrea,用于保存的代码非常简单:我从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);
}

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

为了完成这个示例,我使用了一个由项目生成器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_;
    }
}
/**
*通用dto到实体映射器的合同。
@param-DTO类型参数。
@param-实体类型参数。
*/
公共接口实体映射器{
公共电子实体(D dto);
公共托德机构(实体);
向实体公开名单(名单数据列表);
公共列表toDto(列表实体列表);
}
/**
*实体Macchina及其DTO MacchinaDTO的映射器。
*/
@映射器(componentModel=“spring”,使用={personemapper.class})
公共接口MacchinaMapper扩展了EntityMapper{
默认Macchina fromId(长id){
if(id==null){
返回null;
}
Macchina Macchina=新Macchina();
macchina.setId(id);
回归中国;
}
}
@产生(
value=“org.mapstruct.ap.MappingProcessor”,
日期=“2017-07-21T11:57:12+0200”,
comments=“version:1.1.0.Final,编译器:Eclipse JDT(IDE)3.12.3.v20170228-1205,环境:Java 1.8.0141(Oracle公司)”
)
@组成部分
公共类MacchinaMapperImpl实现MacchinaMapper{
@自动连线
私人人物映射器;
@凌驾
公用MacChinadTodto(Macchina arg0){
如果(arg0==null){
返回null;
}
MacchinaDTO MacchinaDTO=新MacchinaDTO();
macchinaDTO.setId(arg0.getId());
macchinaDTO.setMarca(arg0.getMarca());
Set=PersonasetTopPersonadToSet(arg0.getPersonas());
如果(设置!=null){
macchinaDTO.setPersonas(set);
}
返回macchinaDTO;
}
@凌驾
公共列表对象(列表arg0){
如果(arg0==null){
返回null;
}
列表=新的ArrayList();
用于(Macchina Macchina:arg0){
列表。添加(toDto(macchina));
}
退货清单;
}
@凌驾
Macchina公共实体(MacChinadToArg0){
如果(arg0==null){
返回null;
}
Macchina Macchina=新Macchina();
macchina.setId(arg0.getId());
macchina.setMarca(arg0.getMarca());
Set Set=personaDTOSetToPersonaSet(arg0.getPersonas());
如果(设置!=null){
macchina.setPersonas(set);
}
回归中国;
}
@凌驾
公共列表实体(列表arg0){
如果(arg0==null){
返回null;
}
列表=新的ArrayList();
for(MacchinaDTO MacchinaDTO:arg0){
列表。添加(实体(macchinaDTO));
}
退货清单;
}
受保护集PersonasetTopPersonadToSet(集){
if(set==null){
返回null;
}
Set Set=新HashSet();
for(Persona Persona:set){
set.add(personemapper.toDto(persona));
}
返回集;
}
受保护集合personaDTOSetToPersonaSet(集合集合){
if(set==null){
返回null;
}
Set Set=新HashSet();
for(personaldto personaldto:set){
set.add(personemapper.toEntity(personaldto));
}
返回集;
}
}

我遇到了同样的问题,经过多次搜索后找到了这条线索。我终于解决了。 基本上,JPA(或Hibernate-不确定)似乎无法单独在子对象中设置父引用(即使您设置了注释)。那么在
@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"
    }
}
@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;
    }
}