0

I have an entity called itineraryTraveller, and every itineraryTraveller can have many flightEntity. When I try to delete an itineraryTraveller (parent), from the database, I get this error message:

a foreign key constraint fails (`pquino01db`.`ITINERARYTRAVELLER_FLIGHTENTITY`, CONSTRAINT `FK_ITINERARYTRAVELLER_FLIGHTENTITY_flights_ID` FOREIGN KEY (`flights_ID`) REFERENCES `FLIGHTENTITY` (`ID`))"

Here is my itineraryTraveller entity:

@Entity
public class itineraryTraveller implements Serializable {

    private static final long serialVersionUID = 1L;

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

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<flightEntity> flights;

    @Temporal(javax.persistence.TemporalType.DATE)
    private Date departureDate;

    private String departureLocation;
    private String arrivalLocation;
    private double cost;
    private char status;
    private ArrayList<String> stops;
    private String stopPrint;
    private String userName;
    private int iden;

    // ...
}

And the flightEntity looks like this:

@Entity
public class flightEntity implements Serializable {

    private static final long serialVersionUID = 1L;

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

    @Temporal(javax.persistence.TemporalType.DATE)
    private Date departureDate;

    private String airlineCode;
    private String flightNumber;
    private String departureLocation;
    private String arrivalLocation;
    private double businessCost;
    private double economyCost;
    private int numBusinessSeats;
    private int numEconomySeats;

    // ...
}

Can someone see the problem? I think my @OneToMany annotation might be missing something, but I'm not sure what. I want to delete both the parent and child at the same time.

blacktide
  • 10,654
  • 8
  • 33
  • 53
pquin92
  • 21
  • 2
  • 8
  • Are you using Hibernate to do the work? – PeterS May 08 '16 at 16:12
  • JPA Ecliplse Link with glassfish – pquin92 May 08 '16 at 16:14
  • Ok thanks, my suggestion is probably irrelevant, however you should check which type of CascadeType you use, I know with Hibernate you should use Hibernate's perhaps glassfish has a similar issue? Check here: http://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/ – PeterS May 08 '16 at 16:16
  • Possible duplicate of [JPA OneToMany not deleting child](http://stackoverflow.com/questions/2011519/jpa-onetomany-not-deleting-child) – RubioRic May 08 '16 at 16:17
  • In the above mentioned link appears an specific answer for Eclipse Link: @PrivateOwned annotation. http://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/a_privateowned.htm – RubioRic May 08 '16 at 16:26
  • I've read those links thanks, but it does not find the @CascadeOnDelete. it says "cannot find symbol". HELP – pquin92 May 08 '16 at 17:20
  • @JaqenH'ghar how can I fix that then? – pquin92 May 08 '16 at 18:00

2 Answers2

1

Your relationship between the two entities is unidirectional as there is no mapping from flightEntity back to itineraryTraveller entity as you do not have a @JoinColumn on your flightEntity. There can be one of the following solutions for your problem:

  1. Add a @ManyToOne annotation on the flightEntity as follows:

    @Entity
    public class flightEntity implements Serializable {
       // ....
    
       @ManyToOne
       @JoinColumn(name="<name_of_foreignkey_column>")
       private itineraryTraveller traveller;
    
       // ...
    }
    

    And you have to add a mappedBy attribute to your @OneToMany annotation:

    @OneToMany(mappedBy="traveller", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    

    Thereby making the relationship between the entities bidirectional.

This one can solve the problem if you already have tables in the database with a foreign key relationship.

  1. Use @JoinTable annotation on the @OneToMany annotation:

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinTable(name="<join_table_name>", joinColumns=@JoinColumn("TRAVELLER_ID"), inverseJoinColumns=@JoinColumn("FLIGHT_ID"))
    private List<flightEntity> flights;
    

(The names of the columns are considered to be examples, and can be changed.)

This last mapping is useful if you don't have tables in the database with foreign key column defined, and it will create a new table as an association between the tables; which is normally the case in a many-to-many relationships.

If it is possible use @ManyToOne annotation on the flights entity. This is normal way of mapping a one-to-many relationships.

Lastly, there are conventions in Java that state class names should begin with a capital letter. So I would rename the entity names to Flight and ItineraryTraveller.

ujulu
  • 3,289
  • 2
  • 11
  • 14
  • thanks!! I am using the 2 solution. But it does not find "TRAVELLER_ID", neither "FLIGHT_ID". Where should I set these columns names? – pquin92 May 08 '16 at 19:48
  • `TRAVELLER_ID` and `FLIGH_ID` are the names I chose. But in your case you have to look for the correct column names in your database. Do you have an association table containing the primary keys of both tables? – ujulu May 08 '16 at 19:56
  • the thing is that I want my application to automatically create all tables in the database. So I rather not manipulate from database. As when first deployed the application, those tables would not already exist – pquin92 May 08 '16 at 20:03
  • and btw my objective is to delete a FlightEntity from db, then automatically delete all ItineraryTravellers that contain that flight inside their property list of flights – pquin92 May 08 '16 at 20:04
  • I thought you have already tables in the database. If you want to create all the tables automatically, it doesn't matter which way you choose. You have only to tell your JPA provider to generate the tables, and indeed only the first time you deploy your application. – ujulu May 08 '16 at 20:27
  • and then what TRAVELLED_ID and FLIGHT_ID names should I write? – pquin92 May 08 '16 at 20:38
  • I am not sure that I understood you; if not leave me a comment. (Then tomorrow). If you choose to use these names `TRAVELLED_ID` should match the `ID` column of the `itineraryTraveller` table and `FLIGHT_ID` matches the `ID` column of the `flightEntity` in the join table. – ujulu May 08 '16 at 20:48
0

Note that in some cases the @JoinColumn on the child object must have insertable = false and updatable = false like this: @JoinColumn(name = "user_id", insertable = false, updatable = false)

public class User {
   private List<UserRole>   roles;

   @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
   public List<UserRole> getRoles() {
      return this.roles;
   }
   public void setRoles(List<UserRole> roles) {
       this.roles = roles;
   }

}

public class UserRole {
    @ManyToOne
    @JoinColumn(name = "user_id", insertable = false, updatable = false)
    private User user;
}
Maayan Hope
  • 1,482
  • 17
  • 32