Search code examples
spring-boothibernatejpaspring-data-jpahibernate-mapping

Unknown Column Error while attempting a many-to-one entity mapping


I followed this example, renaming Student to Journey, and renaming Library to Station. My interpretation of the error is, the table schema does not have a field called 'departure' while the java class representation does. I didn't expect this to be a problem because I followed the JPA naming convention mentioned in this answer. In the example's case, lib + b_id == LIB_B_ID . In my case, departure + station_id == departure_station_id (my database naming scheme uses lowercase).

Other notable differences to the example, I don't have a persistence.xml, for id I use GenerationType.IDENTITY not GenerationType.AUTO .

Error

java.sql.SQLException: Unknown column 'departure' in 'field list'

Schema script

CREATE TABLE `station` (
  `station_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `locker_id` bigint(20) DEFAULT NULL,
  `station_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`station_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2579 DEFAULT CHARSET=utf8

CREATE TABLE `journey` (
  `journey_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `departure_station_id` bigint(20) DEFAULT NULL,
  `destination_station_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`journey_id`),
  KEY `station_id_departure` (`departure_station_id`),
  KEY `station_id_destination` (`destination_station_id`),
  CONSTRAINT `journey_ibfk_1` FOREIGN KEY (`destination_station_id`) REFERENCES `station` (`station_id`),
  CONSTRAINT `journey_ibfk_2` FOREIGN KEY (`departure_station_id`) REFERENCES `station` (`station_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Journey

@Entity
public class Journey implements Serializable{//Serializable required by @JoinColumn

//Station
public Journey(Station departure, Station destination){
this.departure = departure;
this.destination = destination;
}

//List<Station>
public Journey(List<Station> journeyStationList){
departure = journeyStationList.get(0);//0 is first index
destination = journeyStationList.get(journeyStationList.size() - 1);//-1 because first index of List is 0
}

private Long journeyId;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getJourneyId(){
return journeyId;
}
public void setJourneyId(Long journeyId){
this.journeyId = journeyId;
}

@ManyToOne
private Station departure;

public Station getDeparture(){
return departure;
}

public void setDeparture(Station departure){
this.departure = departure;
}

@ManyToOne
private Station destination;

public Station getDestination(){
return destination;
}

public void setDestination(Station destination){
this.destination = destination;
}

}

Station

@Entity
public class Station implements Serializable{//Serializable required by @JoinColumn

public Station(){//default constructor needed for JPA query

}

public Station(String stationName){
setStationName(stationName);
}

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long stationId;

public Long getStationId(){
return stationId;
}

public void setStationId(Long stationId){
this.stationId = stationId;
}

private String stationName;

public String getStationName(){
return stationName;
}

public void setStationName(String stationName){
this.stationName = stationName;
}

}

Solution

  • In contrast to the two examples I cross referenced A and B, I noticed in this question the @ManyToOne annotation was above the getter not the field's declaration. Because my currently working annotations (@id and @GeneratedValue) was also above a getter it seemed like a plausible solution. After moving the annotation to the getter, the error went away.

    The examples were not wrong, they were just using a different access strategy than what I had inadvertently implicitly set by placing the @id annotation above the getter. By placing my @id annotation above the getter I implicitly specified property-based access resulting in hibernate calling the getter and setter methods to access my attributes, hence why my @ManyToOne annotation had to be above the getter. The examples I was referencing placed the @id annotation above the class variable itself, implicitly specifying field-based access in which case you should placing the @ManyToOne annotation above the class variables work. Source