0

I want to create a REST application with two entities: Bord and BordRows, as you can guess a Bord has many BordRows. Now I want a request to just get all the bords with every attribute except the rows relationship and a different request to get a single Bord with the relationship Rows included. I am still new to Java spring and as far as my understanding it's faster to use less database queries to retrieve results, e.g., don't retrieve the Rows if I don't need them to save time for faster results. I have it set up with a @JsonIgnore annotation to ignore the relationship and thus not retrieving them from the database. I have a resource with a findAll, getById and getBordRows to retrieve the rows in a specific request. I want another request to get a Bord by id with the relationship rows

Bord entity:

import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;

@Table(name = "bords")
@Entity
public class Bord
{
    @Id
    @GeneratedValue
    private int id;

    @NotNull
    private String name;

    @Column
    private String icon;

    @Column
    private String background;

    @OneToMany(mappedBy = "bord")
    @JsonIgnore
    private List<BordRow> rows;

    public Bord()
    {
        rows = new ArrayList<>();
    }

    public int getId()
    {
        return id;
    }

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

    public String getName()
    {
        return name;
    }

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

    public String getIcon()
    {
        return icon;
    }

    public void setIcon(String icon)
    {
        this.icon = icon;
    }

    public String getBackground()
    {
        return background;
    }

    public void setBackground(String background)
    {
        this.background = background;
    }

    public void addRow(BordRow bordRow)
    {
        this.rows.add(bordRow);
    }

    public List<BordRow> getRows()
    {
        return rows;
    }

    public void setRows(List<BordRow> bordRows)
    {
        this.rows = bordRows;
    }
}

BordRow entity:

import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import javax.validation.constraints.NotNull;

@Entity
@Table(name = "bord_rows")
public class BordRow
{
    @Id
    @GeneratedValue
    private int id;

    @NotNull
    private String title;

    @ManyToOne
    @JoinColumn(name = "bord_id")
    @JsonIgnore
    private Bord bord;

    public int getId()
    {
        return id;
    }

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

    public String getTitle()
    {
        return title;
    }

    public void setTitle(String title)
    {
        this.title = title;
    }

    public Bord getBord()
    {
        return bord;
    }

    public void setBord(Bord bord)
    {
        this.bord = bord;
    }
}

BordResource:

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping(path = "/bords")
public class BordResource
{
    private final BordController bordController;

    public BordResource(BordController bordController)
    {
        this.bordController = bordController;
    }

    @GetMapping
    public List<Bord> getAll()
    {
        return bordController.findAll();
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Optional<Bord> getById(@PathVariable("id") int id)
    {
        return Optional.ofNullable(bordController.getById(id));
    }

    @RequestMapping(value = "/rows/{id}", method = RequestMethod.GET)
    public List<BordRow> getBordRows(@PathVariable final int id)
    {
        Bord bord = bordController.getById(id);
        return bordController.getBordRowsByBord(bord);
    }
}

2 Answers 2

1

For such a scenario two steps have to be taken care of :

  1. Associated objects should be loaded lazily.
  2. There can be some DTO objects in API layer for transferring data returned from business layer to the client.

now, the Bord and BordRow entities should change.

in Bord:

@OneToMany(mappedBy = "bord", fetch = FetchType.LAZY)
    @JsonIgnore
    private List<BordRow> rows;

in BordRows:

@ManyToOne
@JoinColumn(name = "bord_id", , fetch = FetchType.LAZY))
@JsonIgnore
private Bord bord;

By applying these changes, whenever you query your database, associated objects are not loaded until an explicit call is made to them. For understanding lazy loading better take a look at this_SO_thread.

For the second step (which is optional), you can declare some DTO classes and map the objects returned form business layer to them and pass them to the client. These DTO classes can own properties which you (as the developer) believe that should be transfered to client.

for example:

class BordDto{
    private String name;
    private String icon;
    private String background;
    //getters and setters
}

class BordRowDto {
    private String title;
    //getters abs setters
}

and in your controller:

@GetMapping(value = "/bords")
public List<BordDto> handle() {

    return bordService.findAll().stream
            .map(SomeUtilToMapModelToDto::mapBordToBordDto)
            .collect(Collectors.toList());

}
Sign up to request clarification or add additional context in comments.

Comments

0

I guess you are using Spring JPA, so you can always write your custom queries using,

org.springframework.data.jpa.repository.Query

Therefore, in your case, you would add something like that in your BordRepository class,

@Query(value = "SELECT * FROM Bord b INNER JOIN BordRow br WHERE b.id = br.bordId AND b.id = :id)
List<Bord> getBordsAndRowsById(@Param("id") Long id);

That (or some slight modification) will probably solve the case.

1 Comment

@Gimby you are totally right, didn't notice..! Thanks..! :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.