Однонаправленный запрос JPQL manyToMany

Я искал форумы и везде для однонаправленного запроса manyToMany. Я нахожу много примеров, но не могу настроить их под свои нужды :(

У меня есть 2 класса сущностей (аниме и пользователь)

Anime {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "anime_id")
    private Integer id;

    //Other fields etc.
}

User {
    @Id
    @ValidUsername
    @Column(name = "user_id")
    private String username;

    @ManyToMany()
    @JoinTable(name = "users_animes",
        joinColumns = @JoinColumn(name = "anime_id", referencedColumnName =     "anime_id"),
        inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "user_id"))
    private final List<Anime> animes = new ArrayList<>();
}

Аниме просто хранит данные из аниме. Пользователь содержит имя пользователя и т. д. пользователя и список аниме, на которые он подписан.

Теперь я пытаюсь найти запрос, который позволит мне получить все аниме в этом списке. Он отображается в таблице как «users_animes».

Было бы огромной помощью, так как я новичок в JPQL.

Спасибо!


person PieterJan    schedule 25.06.2015    source источник


Ответы (1)


Вот простой пример. Предположим, что у нас есть Country Entity, которая может иметь несколько граждан:

@Entity
@Table (name = "countries")
public class Country implements Serializable {

    @Id
    @Column (name = "coun_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column (name = "country_name")
    private String countryName;

    @ManyToMany (cascade = CascadeType.ALL)
    @JoinTable (
            name = "citizen_country",
            joinColumns = @JoinColumn (name = "country_id", referencedColumnName = "coun_id"),
            inverseJoinColumns = @JoinColumn (name = "citizen_id", referencedColumnName = "cit_id")
    )
    private List<Citizen> citizens;

    public Country() {}
    public Country(String countryName) {
        this.countryName = countryName;
    }
    //getters and setters
}

И гражданин, который может принадлежать нескольким странам:

@Entity
@Table (name = "citizens")
public class Citizen implements Serializable {

    @Id
    @Column (name = "cit_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column (name = "country_name")
    private String citizenName;

    public Citizen() {}

    public Citizen(String citizenName) {
        this.citizenName = citizenName;
    }

    public void setId(Long id) { this.id = id; }
    public Long getId() { return id; }

    public void setCitizenName(String citizenName) { this.citizenName = citizenName; }
    public String getCitizenName() { return citizenName; }

    //getters and setters
}

Он однонаправленный, как вы и хотели. Следовательно, Citizen Entity не знает о стране, поэтому вы не можете напрямую получить информацию о том, к какой стране принадлежит определенный гражданин. Однако вы можете получить информацию о том, какие граждане принадлежат к определенной стране.

Идя дальше, вы можете заполнить свои таблицы:

    Citizen citizen1 = new Citizen("Smith");
    Citizen citizen2 = new Citizen("Kowalski");
    Citizen citizen3 = new Citizen("Muller");
    dataAccess.saveCitizen(citizen1);
    dataAccess.saveCitizen(citizen2);
    dataAccess.saveCitizen(citizen3);

    // now let's fetch them from DB, along with their other properties (only id in this case)
    citizen1 = dataAccess.getCitizenByName("Smith");
    citizen2 = dataAccess.getCitizenByName("Kowalski");
    citizen3 = dataAccess.getCitizenByName("Muller");

    Country country1 = new Country("Foo");
    Country country2 = new Country("Bar");

    // create lists to hold citizens for each country
    List<Citizen> citizenList1 = new ArrayList();
    List<Citizen> citizenList2 = new ArrayList();

    // add elements to the lists
    citizenList1.add(citizen1);
    citizenList1.add(citizen2);        
    citizenList2.add(citizen2);
    citizenList2.add(citizen3);

    //assign lists of citizens to each country
    country1.setCitizens(citizenList1);
    country2.setCitizens(citizenList2);

    //save data in DB
    dataAccess.saveCountry(country1);
    dataAccess.saveCountry(country2);

    //fetch list of all persisted countries (associated Citizens will come along)
    countries = dataAccess.getAllCountries();

И наконец:

@Stateless
public class DataAccess {

    @PersistenceContext
    EntityManager em;

    public void saveCountry(Country country) {
        em.persist(country);
    }

    public void saveCitizen(Citizen citizen) {
        em.persist(citizen);
    }

    public Citizen getCitizenByName(String name) {
        Query query = em.createQuery("SELECT c FROM Citizen c WHERE c.citizenName = :name");
        query.setParameter("name", name);
        return (Citizen) query.getSingleResult();
    }

    public List<Country> getAllCountries() {
        Query query = em.createQuery("SELECT c FROM Country c");
        return (List<Country>) query.getResultList();
    }


}
person mmalik    schedule 25.06.2015
comment
Разве нельзя получить аниме, которые я хочу, от определенного пользователя с помощью запроса JOIN? Или это возможно только через получение пользователя и получение списка, когда у меня есть объект от пользователя. - person PieterJan; 25.06.2015
comment
Я не уверен, что понимаю ваш вопрос. Я старался максимально упростить JPQL, а все остальное сделал JPA Provider. Вы хотели получить все аниме, связанные с пользователем, верно? Просто замените Country в моем примере на своего пользователя, а Citizen на Anime, этого должно хватить. - person mmalik; 25.06.2015