SpringData architektura i powiązania

Odpowiedz Nowy wątek
2018-11-23 17:59
0

Cześć.
Mam trzy encje:

public class Game {

    @Id
    private int matchID;
    @JoinColumn(name = "Competition")
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    private Competition competition;
    private String dateMatch;
    private String startTime;
    private String statusMatch;
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    private Team homeTeam;
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
    private Team awayTeam;
    private String winner;
    @OneToMany(mappedBy = "matchID")
    private Set<UserBets> listBets;
    @Column(nullable = false, columnDefinition = "TINYINT(1)")
    private boolean verifiedStatus;
}
public class Competition {

    @Id
    private int competitionID;
    private String competitionName;
    @OneToMany(mappedBy = "competition", fetch = FetchType.LAZY)
    private Set<Game> games = new HashSet<>();
}
public class Team {

    @Id
    private int teamId;
    private String teamName;
}

W swoim DTO chciałem aby gameDto posiadało dokładną nazwę zespołu, niestety powoduje to u mnie, że na 4 rezultaty mam 1 zapytanie do game, 1 do competition, 8 do Team.

Jak to rozwiązać ?
Ustawić w w GameDto ID drużyny zamiast nazwy ? Ustawić nazwę zamiast ID w encji ? Które rozwiązanie jest lepsze ? A może popełniam jakiś błąd już na wstępie.

Pozostało 580 znaków

2018-11-23 18:31
1

Pobierając listę czterech obiektów Game, masz:
jedno zapytanie do Game,
4 do Competition
8 do Team
Jest to spowodowane tym, że mapując do DTO dociągasz obiekty powiązane, ale działa to tylko wtedy jeśli encja nie jest jeszcze "odłączona", czyli jest cały czas zarządzana przez entity managera. Wtedy dla każdego obiektu Game tworzy zapytanie o Team, czyli dla 1. obiektu Game -> zapytanie o homeTeam, następnie zapytanie o awayTeam i tak 4*2 = 8 dodatkowych zapytań

Możesz to poprawić robiąc: SELECT *JOIN FETCH

A znalazłam jeszcze fajne wyjaśnienie dotyczące tego, że FETCH działa różnie czasami powodójąc n+1 zapytań, na stronce https://docs.jboss.org/hibern[...]apters/fetching/Fetching.html:

Example 2. Direct fetching example
Employee employee = entityManager.find( Employee.class, 1L );
select
    e.id as id1_1_0_,
    e.department_id as departme3_1_0_,
    e.username as username2_1_0_,
    d.id as id1_0_1_
from
    Employee e
left outer join
    Department d
        on e.department_id=d.id
where
    e.id = 1
The LEFT JOIN clause is added to the generated SQL query because this association is required to be fetched eagerly.

On the other hand, if you are using an entity query that does not contain a JOIN FETCH directive to the Department association:

Example 3. Entity query fetching example
Employee employee = entityManager.createQuery(
        "select e " +
        "from Employee e " +
        "where e.id = :id", Employee.class)
.setParameter( "id", 1L )
.getSingleResult();
select
    e.id as id1_1_,
    e.department_id as departme3_1_,
    e.username as username2_1_
from
    Employee e
where
    e.id = 1

select
    d.id as id1_0_0_
from
    Department d
where
    d.id = 1
Hibernate uses a secondary select instead. This is because the entity query fetch policy cannot be overridden, so Hibernate requires a secondary select to ensure that the EAGER association is fetched prior to returning the result to the user.
edytowany 3x, ostatnio: szarotka, 2018-11-23 19:37

Pozostało 580 znaków

2018-11-23 18:49
0

Obecnie:
screenshot-20181123184720.png

Po zmianie na eager
screenshot-20181123184828.png

W DTO odwołuje się do teamName dlatego tyle tych zapytań.

Po eager nadal tak? Bez sensu. - jarekr000000 2018-11-23 20:33
Właśnie nie. Ja na początku właśnie zasugerowałam żeby zmienić LAZY na EAGER, no bo zdrowy rozsądek mówi, że LAZY dociąga potem pojedynczo, a EAGER od razu zrobi JOIN FETCH, ale właśnie okazuje się, że nie. Dołączyłam linka do stronki gdzie jest rozpisany ten przykład. - szarotka 2018-11-23 20:53

Pozostało 580 znaków

2018-11-23 22:50
0

zmiana w repository z

 List<Game> findByCompetitionCompetitionID(int competitionId);

na

    @Query("Select g from Game g " +
                    "join fetch g.awayTeam " +
                    "join fetch g.homeTeam " +
                    "where competition=:competition")
    List<Game> findByCompetitionCompetitionID(@Param("competition") int competition);

Rozwiązała problemy, pytanie czy można to zrobić bez pisanie każdego query ręcznie ?

Oraz: w competition mam Set<game>.
Team odnosi się natomiast do dwóch właściwości w Game, jak to zaimplementować żeby w Team był set<game> z listą obojętnie czy away czy home_team?

edytowany 1x, ostatnio: cayman25, 2018-11-23 23:16

Pozostało 580 znaków

2018-11-23 23:36
0

Możesz zapoznać się z poniższymi adnotacjami:

@Fetch(FetchMode.JOIN)
@Fetch(FetchMode.SUBSELECT)

A jak nie chcesz zmieniać fetch mode to zostaje jeszcze poznanie tego:

@BatchSize(size = 50)
edytowany 1x, ostatnio: Seti87, 2018-11-23 23:37

Pozostało 580 znaków

2018-11-25 13:44
0

A jakaś podpowiedź z tym:

Team odnosi się natomiast do dwóch właściwości w Game, jak to zaimplementować żeby w Team był set<game> z listą obojętnie czy away czy home_team?

edytowany 1x, ostatnio: cayman25, 2018-11-25 13:45

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0