Неверные операторы SQL, сгенерированные JPA - PullRequest
1 голос
/ 11 ноября 2010

Я столкнулся со странной ошибкой в ​​JPA, которая не зависит от поставщика сохраняемости. Я использую JPA 2.0 и использую сгенерированную схему.

Вкратце: сгенерированная схема включает таблицу соединения с тремя столбцами, но сгенерированные операторы вставки обрабатывают эту таблицу так, как если бы она имела только два столбца.

Вот сопоставления:

@Entity
@Table( name = "Game" )
public class MatchEntity implements Match, Serializable {

    @Id
    @GeneratedValue( strategy = GenerationType.AUTO )
    private Long id;

    @ManyToOne( targetEntity = ClubEntity.class )
    private Club homeTeam;

    @ManyToOne( targetEntity = ClubEntity.class )
    private Club awayTeam;

    @ManyToMany( targetEntity = PlayerEntity.class )  
    private Collection<Player> homeTeamPlayers;

    @ManyToMany( targetEntity = PlayerEntity.class )
    private Collection<Player> awayTeamPlayers;

    private String location;

    @Temporal( value = TemporalType.DATE )
    @Column( name = "Match_Date" )
    private Date date;

    /* constructor, getters and setters follow */
 }


@Entity
@Table( name = "Club" )
public class ClubEntity implements Club, Serializable {

    @Id
    @GeneratedValue( strategy = GenerationType.AUTO )
    private Long id;

    private String name;

    @OneToMany( fetch = FetchType.EAGER, targetEntity = PlayerEntity.class,
    mappedBy = "club" )
    private Collection<Player> players = new ArrayList<Player>();

    private String fieldName;

    private Boolean archived;

    /* constructor, getters and setters follow */
}

@Entity
@Table( name = "PLAYER" )
public class PlayerEntity implements Player, Serializable {

    @Id
    @GeneratedValue( strategy = GenerationType.AUTO )
    private Long id;

    private String firstName;

    private String surname;

    @Temporal( value = TemporalType.DATE )
    private Date birthDate;

    @Column( name = "pos" )    
    @Enumerated( EnumType.ORDINAL )
    private Position position;

    private Integer number;

    private Boolean archived;

    @ManyToOne( targetEntity = ClubEntity.class, fetch = FetchType.EAGER )
    private Club club;


    /* constructor, getters and setters follow */
}

Из этих сопоставлений создается следующая схема:

create table Club (id bigint generated by default as identity (start with 1), archived bit, fieldName varchar(255) not null, name varchar(255) not null, primary key (id))
create table Game (id bigint generated by default as identity (start with 1), Match_Date date, location varchar(255), awayTeam_id bigint, homeTeam_id bigint, primary key (id))
create table Game_PLAYER (Game_id bigint not null, homeTeamPlayers_id bigint not null, awayTeamPlayers_id bigint not null)
create table PLAYER (id bigint generated by default as identity (start with 1), archived bit, birthDate date, firstName varchar(255) not null, number integer, pos integer, surname varchar(255) not null, club_id bigint, primary key (id))
alter table Game add constraint FK21C0123B2A3B9E foreign key (homeTeam_id) references Club
alter table Game add constraint FK21C012F5972EAF foreign key (awayTeam_id) references Club
alter table Game_PLAYER add constraint FK267CF3AE6AE1D889 foreign key (Game_id) references Game
alter table Game_PLAYER add constraint FK267CF3AED51EDECF foreign key (homeTeamPlayers_id) references PLAYER
alter table Game_PLAYER add constraint FK267CF3AE6CBE869E foreign key (awayTeamPlayers_id) references PLAYER
alter table PLAYER add constraint FK8CD18EE13F2C6C64 foreign key (club_id) references Club

Эта строка важна - это таблица соединения.

create table Game_PLAYER (Game_id bigint not null, homeTeamPlayers_id bigint not null, awayTeamPlayers_id bigint not null)

Когда я пытаюсь сохранить сущность Game (MatchEntity.java), это происходит:

insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)
Hibernate: insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)
binding '2' to parameter: 1
binding '1' to parameter: 2
reusing prepared statement
insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)
Hibernate: insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)
binding '2' to parameter: 1
binding '2' to parameter: 2
done inserting collection: 2 rows inserted
Inserting collection: [football.model.entities.MatchEntity.homeTeamPlayers#2]
Executing batch size: 2
about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
Could not execute JDBC batch update [insert into Game_PLAYER (Game_id, awayTeamPlayers_id) values (?, ?)]

JPA пытается вставить две строки в таблицу соединения, каждая из которых затрагивает только два столбца из трех.

Что я пробовал:

  • В целом избавление от интерфейсов в отображениях
  • Определение явной таблицы соединений
  • Использование OpenJPA вместо Hibernate

Ни одна из них не решила проблему.

edit: код для активной загрузки:

    @Transactional(readOnly = true)
    public Collection<Match> findAll() {        
        em.createQuery("SELECT m FROM MatchEntity m "
            + "JOIN FETCH m.homeTeamPlayers", MatchEntity.class).getResultList();
        List<MatchEntity> rList = em.createQuery("SELECT m FROM MatchEntity m "
            + "JOIN FETCH m.awayTeamPlayers", MatchEntity.class).getResultList();
        Collection<Match> result = new ArrayList<Match>( rList );
        return result;
    }

1 Ответ

1 голос
/ 11 ноября 2010

Возможно, вам нужны разные таблицы соединений для homeTeamPlayers и awayTeamPlayers:

@ManyToMany( targetEntity = PlayerEntity.class )   
@JoinTable(name = "Game_HomeTeamPlayers")
private Collection<Player> homeTeamPlayers; 

@ManyToMany( targetEntity = PlayerEntity.class ) 
@JoinTable(name = "Game_AwayTeamPlayers")
private Collection<Player> awayTeamPlayers; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...