0

I'm learning Spring Framework, i followed some tutorials of relationship 1-1, so i defined my models: One Library have one Address. I send in my body request the library data and the id from the address, the spring create the record, but he can't do the relationship, returning address null and when i make a select in database, the address_id is not saving in the table library

This is what i tried:

My model Library:

@Entity
@Table(name = "Bibliotecas")
public class Library implements Serializable {
  private static final long serialVersionUID = 1L;

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

  private String name;

  @OneToOne
  @JoinColumn(name = "address_id", referencedColumnName = "id")
  private Address address;

  public Library() {
  }

  public long getId() {
    return this.id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Address getAddress() {
    return this.address;
  }

  public void setAddress(Address address) {
    this.address = address;
  }

}

My model Address:

@Entity
public class Address {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;

  @Column(nullable = false)
  private String location;

  public long getId() {
    return this.id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getLocation() {
    return this.location;
  }

  public void setLocation(String location) {
    this.location = location;
  }

  @OneToOne(mappedBy = "address", fetch = FetchType.LAZY, optional = false)
  private Library library;

}

My repositories:

public interface LibraryRepository extends JpaRepository<Library, Long> {}
public interface AddressRepository extends JpaRepository<Address, Long> {}

My library resource:

@RestController
@RequestMapping(value = "/api")
public class LibraryResource {

  @Autowired
  LibraryRepository libraryRepository;

  @GetMapping("/libraries")
  public List<Library> listaBibliotecas() {
    return libraryRepository.findAll();
  }

  @PostMapping("/library")
  public Library salvaBiblioteca(@RequestBody Library library) {
    return libraryRepository.save(library);
  }
}

I do this request in Postman:

{
    "name": "library test",
    "address_id": 1
}

Obs: i have one address with id 1 in database, but i receive:

{
    "id": 5,
    "name": "Biblioteca test",
    "address": null
}

Why i'm receiving null in my return? And why my register is not saving the address_id?

veroneseComS
  • 653
  • 2
  • 14
  • 40
  • 1
    Better never to use one-to-one relations it has the worst performance.. we found using 40 columns in single table better than splitting them because on @one-to-one relation with each call hibernate create another call to fetch the other table irrespective if you annotate with FetchType.LAZY/FetchType.EAGER it act the same. anw provied you with solution for you issue hope it helps! – Hussein Akar May 19 '20 at 00:17

1 Answers1

1

Please consider the following:

  • You switched the mapping between address & library
  • Better to user Hibernate annotations on public fields
  • Address -> Library getter & setter not implemented
  • Address entity missing the @table annotation

This must work for you:

Library:

@Entity
@Table(name = "library")
public class Library implements Serializable {

    private static final long serialVersionUID = 1L;

    private long id;
    private String name;
    private Address address;

    public Library() {
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToOne(mappedBy = "library", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
    public Address getAddress() {
        return this.address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

Address:

@Entity
@Table(name = "address")
public class Address {

    private long id;
    private String location;
    private Library library;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @Column(nullable = false)
    public String getLocation() {
        return this.location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id")
    public Library getLibrary() {
        return library;
    }

    public void setLibrary(Library library) {
        this.library = library;
    }
}
  • Better never expose your repositories to controller, you should instead reference a service that has access to repositoryDao.

  • Use same entity name as table name is better approach.

Hussein Akar
  • 425
  • 3
  • 12
  • 1
    Hi thanks for the observations, i fixed this using: @RequestMapping(value = "/library/{address_id}", method = RequestMethod.POST) public Library salvaBiblioteca(@PathVariable("address_id") long address_id, @RequestBody Library library) { Address address = addressRepository.findById(address_id); library.setAddress(address); return libraryRepository.save(library); } I can't put the address_id directly, i need to first search my Address and after set the address from my library. If i put the fetchType as lazy, when i save i receive a gigant json error – veroneseComS May 19 '20 at 00:48
  • "Better never expose your repositories to controller, you should instead reference a service that has access to repositoryDao." I'm using @Autowired to make a injection dependency, you have a example of how i can make this repository in my controller? – veroneseComS May 19 '20 at 00:49
  • 1
    Sure, Using `@Autowired` to inject is 100% right. What I meant is you must create LibraryService .. inject that service in controller ... and inside this service you call `@Autowired` LibraryRepository that how MVC meant to be (Model, View, Controller) for now it is simple but later when you have more logic pushing all business logic to services will be much better. – Hussein Akar May 19 '20 at 00:53