Java JPA один ко многим

Недавно я опубликовал кого-то о заполнении JTable, который теперь полностью функционален. Однако сейчас я застрял на чем-то другом, я надеюсь достичь двух конкретных целей с помощью этой темы.

Один из них - решить мою проблему, а другой - подготовить ответ, когда другие наткнутся на ту же проблему, потому что я еще не нашел правильного ответа на этот вопрос.

у меня следующий сценарий

Две таблицы:

games
id pk int
жанр int
название varchar ....

жанр
id pk int
имя varchar ..

У одной игры может быть только один жанр, но в одном жанре может быть много игр.

Я использую Eclipse в качестве своей IDE и eclipselink в качестве поставщика JPA.

Я создал классы с помощью мастера сущностей, предоставленного eclipse, который также позволил мне определить отношения между двумя таблицами.

Отношения выглядят следующим образом:

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

@Id
@Column(name="Id", unique=true, nullable=false)
private int id;

@Temporal( TemporalType.DATE)
@Column(name="AddDate", nullable=false)
private Date addDate;

@Lob()
@Column(name="Description", nullable=false)
private String description;

@Temporal( TemporalType.DATE)
@Column(name="ModifiedDate", nullable=false)
private Date modifiedDate;

@Temporal( TemporalType.DATE)
@Column(name="ReleaseDate", nullable=false)
private Date releaseDate;

@Column(name="Title", nullable=false, length=255)
private String title;

//bi-directional many-to-one association to Genre
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="Genre", nullable=false)
private Genre genreBean;

//bi-directional many-to-one association to Publisher
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="Publisher", nullable=false)
private Publisher publisherBean;

и жанр

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

@Id
@Column(name="Id", unique=true, nullable=false)
private int id;

@Column(name="Genre", nullable=false, length=150)
private String genre;

//bi-directional many-to-one association to Game
@OneToMany(mappedBy="genreBean")
private List<Game> games;

Я использую следующее, чтобы выбрать все игры

        List<Game> games;

    try{
        TypedQuery<Game> selectGamesQuery = entityManager.createQuery("SELECT g FROM Game g", Game.class);
        games = selectGamesQuery.getResultList();
    } catch(Exception e) {
        games = null;
        System.out.println(e);

Проблема в том, что список игр не содержит названия жанра, на самом деле он пуст.

Как настроить список так, чтобы он содержал игру со следующими атрибутами: идентификатор, название, название жанра, имя издателя, дата выпуска

В моем JTable я пробовал следующее:

        switch(columnIndex){
        case 0:
            return game.getTitle();
        case 1:
            return game.getPublisherBean().getPublisher();
        case 2:
            return game.getGenreBean().getGenre();
        case 3:
            return game.getReleaseDate();
    }

При этом в моем JTable столбцы для случая 1 и 2 пусты, а остальные работают.

Итак, содержимое моей таблицы выглядит так

Battlefield 3 empty empty 3-3-2011

Я думаю, что с этим я должен был предоставить достаточно информации.

Пожалуйста, дайте мне знать, если есть какая-либо ошибка или ошибка в коде или, возможно, в запросе выбора, поскольку я даже не смог найти, ДОЛЖЕН ли я написать явный запрос JOIN и что он не делает этого из-за определенного отношения.

Я все еще новичок, так что будьте нежны ^^

Спасибо за уделенное время.


person Joey Roosing    schedule 03.03.2011    source источник
comment
После этого я должен быть в порядке, написав остальную часть своего приложения — замечательный оптимизм!   -  person Joel    schedule 03.03.2011
comment
Хех, пожалуй, слишком оптимистично. Но идея звучит красиво. А если серьезно, это последняя часть, которую мне нужно исправить для этого небольшого проекта самообучения. Без сомнения, я столкнусь с кучей других проблем в моем следующем проекте. Черт, возможно, в последних 5% этого проекта! Но это нормально. :) должен признать, что я ломаю себе голову над этим с моими ограниченными знаниями.. ха-ха.. Держу пари, это что-то глупо простое   -  person Joey Roosing    schedule 03.03.2011
comment
Чтобы уточнить: вы получаете ненулевые значения для game.getPublisherBean() и game.getGenreBean() и нулевые значения для их атрибутов издатель и жанр? Я делаю это предположение, поскольку вы не упомянули исключение NullPointerException в своем операторе switch.   -  person Kris Babic    schedule 03.03.2011
comment
Именно в этом была проблема. значение было нулевым. Я был очень небрежен. Спасибо за пробуждающую пощечину. Мне нужно лучше использовать обработку исключений и дважды проверять такие простые вещи. еще раз спасибо, теперь я могу закончить этот мини-проект и начать более крупный с моими знаниями, полученными ›:D   -  person Joey Roosing    schedule 03.03.2011


Ответы (3)


чтобы немного приблизиться к проблеме, вы можете включить мелкозернистое ведение журнала JPA, добавив следующее в файл persistence.xml (внутри элемента persistence-unit):

<properties>
      <property name="eclipselink.logging.level" value="FINEST"/>
</properties>

Затем посмотрите свой файл журнала и посмотрите, как jpql-запрос транслируется в sql.

Еще одна идея (может показаться глупой!): Вы устанавливали ограничения внешнего ключа и в базе данных, или только в Persistence Unit?

Надеюсь это поможет

person Matt Handy    schedule 03.03.2011
comment
Не глупый вопрос. И спасибо. Я не устанавливал его в своей базе данных. Нужно ли мне? Я думал, что JPA со всем этим разберется. ^^;; Кстати, это свойство потрясающее! спасибо! Я еще не знал, что один ^^ - person Joey Roosing; 03.03.2011
comment
На самом деле я не знаю, действительно ли это необходимо. Я всегда так делал. Таким образом, полученный SQL-запрос будет полезен. Затем вы можете отправить этот запрос напрямую в свою базу данных. - person Matt Handy; 03.03.2011
comment
Когда я запускаю его, я получаю 2 запроса. : ReadAllQuery(referenceClass=Game sql=SELECT Id, AddDate, Description, ModifiedDate, ReleaseDate, Title, Genre, Publisher FROM games) [EL Finest]: 2011-03-03 15:45:49.381--ServerSession(2920707)-- Connection(4047165)--Thread(Thread[AWT-EventQueue-0,6,main]) и SELECT Id, Genre FROM жанры WHERE (Id = ?) не уверен, что это значит :( - person Joey Roosing; 03.03.2011

вы уверены в том, как вы делаете вставки ?? потому что могло случиться так, что при вставке игры нужно вставить жанр в список и обновить игру примерно так

/**** the var em is the entity manager ****/

Game game = new Game();

game.setId(1);
game.setDesription("This is a example");
game.setTitle("try");
em.persist(game);

Genre genre = new Genre();

genre.setName("blah");
genre.setId(1);

em.persist(genre);

тогда вам нужно взять сущность уже сохраняющуюся и установить для каждого объекта, потому что отношение является двунаправленным, что-то вроде этого

genre.getGenreBean().add(game);
em.persist(genre);

я надеюсь, что этот пример поможет вам с проблемой

РЕДАКТИРОВАТЬ:

Если вам нужен запрос, это что-то вроде этого

select G, Game from Genre, IN(g.getGenreBean()) Game

Этот запрос возвращает коллекцию Object[] в позиции 0 с жанром и в позиции 1 с игрой.

person Jorge    schedule 03.03.2011
comment
Привет, Джоген, спасибо за ответ. Однако моя проблема заключается в выборе. Я пока ничего не вставляю. Мне нужно выбрать игру по жанру. В моей таблице игр у меня есть поле с именами жанров, которое является INT и содержит идентификатор жанра в таблице жанров, мне нужно соответствующее название этого жанра. Поэтому я просто хочу выбрать, а не вставить, удалить или что-то еще. Этот ответ, однако, довольно хорош для будущего. Спасибо. - person Joey Roosing; 03.03.2011
comment
Я не могу понять запрос из вашего редактирования. :( Однако я ценю помощь. Сейчас я чувствую себя таким новичком. ›‹ - person Joey Roosing; 03.03.2011

Ответ решен.

Проблема, с которой я столкнулся, и причина, по которой я ничего не получил, заключалась в том, что значение было нулевым. Это была моя очень небрежная ошибка в базе данных. По какой-то причине я добавил запись с идентификатором жанра 2, а не с идентификатором 1, в то время как в игре был идентификатор жанра 1, который был пуст.

(спасибо, Крис Бабич) :)

Итак, мой ценный урок дня: проверьте результаты дублирования в базе данных, посмотрите, есть ли у вас совпадающие записи. Использовать

    <properties>
      <property name="eclipselink.logging.level" value="FINEST"/>
   </properties>

При отладке

И я добавил функциональность вставки. Так что спасибо за это, Хорхе.

Спасибо, что нашли время ответить и прочитать.

Таким образом, отношения очень хорошо работают с использованием JPA. На мой взгляд, НАМНОГО лучше, чем linq to sql.

Теперь я могу назвать следующее:

game.getPublisherBean().getPublisher();

И получаю желаемый результат. Так что "РПГ" вместо ""

person Joey Roosing    schedule 03.03.2011