Spring Data JPA。在实体之间的关系中使用复合自然键

时间:2015-03-16 11:37:09

标签: java spring hibernate java-ee jpa

我使用Spring Data JPA(版本为1.7.2.RELEASE)和MySQL 5.5。

以下是我的表格的简化版本:

CREATE TABLE `station` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$

CREATE TABLE `ticket` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `trip_id` bigint(20) unsigned NOT NULL,
  `wagon_number` tinyint(4) unsigned NOT NULL,
  `place_number` tinyint(4) unsigned NOT NULL,
  `departure_station_id` bigint(20) unsigned NOT NULL,
  `arrival_station_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `departure_trip_station_fk_idx` (`trip_id`,`departure_station_id`),
  KEY `arrival_trip_station_fk_idx` (`trip_id`,`arrival_station_id`),
  CONSTRAINT `arrival_trip_station_fk` FOREIGN KEY (`trip_id`, `arrival_station_id`) REFERENCES `trip_station` (`trip_id`, `station_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `departure_trip_station_fk` FOREIGN KEY (`trip_id`, `departure_station_id`) REFERENCES `trip_station` (`trip_id`, `station_id`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$

CREATE TABLE `train` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `number` int(11) unsigned NOT NULL,
  `name` varchar(64) NOT NULL,
  `enabled` bit(1) NOT NULL DEFAULT b'1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1$$

CREATE TABLE `train_station` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `train_id` bigint(20) unsigned NOT NULL,
  `station_id` bigint(20) unsigned NOT NULL,
  `departure_time` mediumint(8) unsigned NOT NULL,
  `arrival_time` mediumint(8) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `train_station_uq` (`train_id`,`station_id`),
  KEY `train_id_idx` (`train_id`),
  KEY `id_idx` (`station_id`),
  KEY `station_fk_idx` (`station_id`),
  CONSTRAINT `station_fk` FOREIGN KEY (`station_id`) REFERENCES `station` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `train_fk` FOREIGN KEY (`train_id`) REFERENCES `train` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$

CREATE TABLE `trip` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `train_id` bigint(20) unsigned NOT NULL,
  `departure_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `train_id` (`train_id`),
  CONSTRAINT `timetable_fk` FOREIGN KEY (`train_id`) REFERENCES `train` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=246 DEFAULT CHARSET=latin1$$

CREATE TABLE `trip_station` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `train_id` bigint(20) unsigned NOT NULL,
  `station_id` bigint(20) unsigned NOT NULL,
  `trip_id` bigint(20) unsigned NOT NULL,
  `arrival_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `departure_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  UNIQUE KEY `trip_station_uq` (`trip_id`,`station_id`),
  KEY `trip_fk_idx` (`trip_id`),
  KEY `train_station_fk_idx` (`train_id`,`station_id`),
  CONSTRAINT `train_station_fk` FOREIGN KEY (`train_id`, `station_id`) REFERENCES `train_station` (`train_id`, `station_id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `trip_fk` FOREIGN KEY (`trip_id`) REFERENCES `trip` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$

以下是我的实体:

@Entity
@Getter
@Setter
public class Station {
    @Id
    private long id;

    @Basic
    private String name;

    @OneToMany(mappedBy = "station", fetch = FetchType.LAZY)
    private Collection<TrainStation> stationTrains;
}


@Entity
@Getter
@Setter
public class Ticket {
    @Id
    private long id;

    @Basic
    @Column(name = "place_number")
    private byte placeNumber;

    @Basic
    @Column(name = "wagon_number")
    private byte wagonNumber;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
            @JoinColumn(name = "trip_id", referencedColumnName = "trip_id", nullable = false),
            @JoinColumn(name = "departure_station_id", referencedColumnName = "station_id", nullable = false)
    })
    private TripStation departureTripStation;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
            @JoinColumn(name = "trip_id", referencedColumnName = "trip_id", nullable = false),
            @JoinColumn(name = "arrival_station_id", referencedColumnName = "station_id", nullable = false)
    })
    private TripStation arrivalTripStation;
}


@Entity
@Getter
@Setter
public class Train {
    @Id
    private long id;

    @Basic
    private int number;

    @Basic
    private String name;

    @Basic
    @Column(name = "enabled", columnDefinition = "BIT", length = 1)
    private boolean enabled;

    @OneToMany(mappedBy = "train", fetch = FetchType.LAZY)
    private List<TrainStation> trainStations;

    @OneToMany(mappedBy = "train", fetch = FetchType.LAZY)
    private List<Trip> trips;
}

@Entity
@Table(name = "train_station", schema = "", catalog = "rail_db",
        uniqueConstraints = @UniqueConstraint(columnNames = { "train_id", "station_id" })
)
@Getter
@Setter
public class TrainStation {
    @Id
    private long id;

    @Basic
    @Column(name = "departure_time")
    private int departureTime;

    @Basic
    @Column(name = "arrival_time")
    private int arrivalTime;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "train_id", referencedColumnName = "id", nullable = false)
    private Train train;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "station_id", referencedColumnName = "id", nullable = false)
    private Station station;

    @OneToMany(mappedBy = "trainStation", fetch = FetchType.LAZY)
    private Collection<TripStation> tripStations;
}


@Entity
@Getter
@Setter
public class Trip {
    @Id
    private long id;

    @Basic
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    @Column(name = "departure_date")
    private DateTime departureDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "train_id", referencedColumnName = "id", nullable = false)
    private Train train;

    @OneToMany(mappedBy = "trip", fetch = FetchType.LAZY)
    private Collection<TripStation> tripStations;
}

@Entity
@Table(name = "trip_station", schema = "", catalog = "rail_db",
        uniqueConstraints = @UniqueConstraint(columnNames = { "trip_id", "station_id" })
)
@Getter
@Setter
public class TripStation {
    @Id
    private long id;

    @Basic
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    @Column(name = "arrival_date")
    private DateTime arrivalDate;

    @Basic
    @Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    @Column(name = "departure_date")
    private DateTime departureDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "trip_id", referencedColumnName = "id", nullable = false)
    private Trip trip;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
            @JoinColumn(name = "train_id", referencedColumnName = "train_id", nullable = false),
            @JoinColumn(name = "station_id", referencedColumnName = "station_id", nullable = false)
    })
    private TrainStation trainStation;

    @OneToMany(mappedBy = "departureTripStation", fetch = FetchType.LAZY)
    private Collection<Ticket> departureTickets;

    @OneToMany(mappedBy = "arrivalTripStation", fetch = FetchType.LAZY)
    private Collection<Ticket> arrivalTickets;
}

如您所见,我的表包含代理主键和复合自然键(例如trip_station具有UNIQUE KEY trip_station_uqtrip_idstation_id))。 对于实体之间的关系,我使用复合自然键,因为它们反映了域的逻辑。

但后来我得到了这个运行时异常:

ERROR o.s.web.context.ContextLoader - Context initialization failed 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/xxx/rail/config/JpaConfig.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build EntityManagerFactory
    ...
Caused by: org.hibernate.AnnotationException: referencedColumnNames(trip_id, station_id) of com.xxx.rail.domain.entity.Ticket.arrivalTripStation referencing com.xxx.rail.domain.entity.TripStation not mapped to a single property
    ...
  • 我想了解什么是错的?
  • 当存在代理主键时,是否可以使用自然复合键(不是主键)进行关系?

0 个答案:

没有答案