简体   繁体   中英

Spring JPA/Hibernate - OneToMany bi-directional problem

I've encountered this problem that won't let me sleep

I have 2 entities Property and Tenant

each property can have 0..1 tenant, each tenant can have 1..N properties

// some annotations
public class Tenant {

  // more fields

  @OneToMany(mappedBy = "tenant", cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
  private Set<Property> properties = new HashSet<>();

}

// some annotations
public class Property {

  // more fields

  @ManyToOne(fetch = FetchType.LAZY)
  private Tenant tenant;

}

what am I trying to accomplish is when I create a new tenant, using cascading I want to attach it to an existing property

saving is done via JpaRepository.save(Tenant)

for example first I create new Property

{
  // more fields
  "tenant": null
}

then sometime later I decide I want to create a tenant for this property

{
  // more fields
  "properties": [
    {
      "id": 1, // property id I want to create this tenant for
      "tenant": null
    }  
  ]
}

I believe I've tried every cascade type (except ALL and PERSIST, these 2 can't be used with detached entities)

How would it be possible to synchronize a newly created tenant with an already existing property?

I read about this that CascadeType.MERGE should do the trick but it does not for me

Any help is appreciated Thanks in advance

edit: all getters and setters are generated by lombok

rest resource for saving

  @PostMapping
  public ResponseEntity<Void> saveTenant(
      @Valid @RequestBody TenantDto tenantDto, UriComponentsBuilder uriComponentsBuilder) {
    log.info(tenantDto.toString());
    Long id = tenantService.saveTenant(tenantDto);
    URI location = uriComponentsBuilder.path("/api/tenants/{id}").buildAndExpand(id).toUri();
    return ResponseEntity.created(location).build();
  }

service

  @Override
  public Long saveTenant(TenantDto tenantDto) {
    // mapstruct mapping
    return tenantRepository.save(tenantMapper.toEntity(tenantDto)).getId();
  }

repo

@Repository
public interface TenantRepository extends JpaRepository<Tenant, Long> {}

Cascading is when you have 2 entities, and you want both of them to be UPDATE ed / INSERT ed / whatever even though you did something only to one of them explicitly. Your question doesn't really relate to cascading - because you want to INSERT one entity, but UPDATE another one.

Now, you put a mappedBy on the Tenant.properties . This means that Property will be the owning entity - it's responsible for saving the connection between these 2 entities.

It means that you need to retrieve Property from DB and set Tenant to it. Then when saving Property you'll get your Foreign Key filled.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM