Parobay
Parobay

Reputation: 2619

One-To-Many Association without a third table

OK, so today I tried a basic Hibernate tutorial and I'm struggling to make it behave how I want.

This is a simple snippet, assume all other fields/methods are defined (e.g. id etc.)

@Entity
@Table(name = "CITIES")
public static class City {

    @ManyToOne
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Country country;


}


@Entity
@Table(name = "COUNTRIES")
public static class Country {

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<City> cities;
}

The above solution utilizes an (automatically created) association table - COUNTRY_CITIES, but this does work only in one way - i.e. I see country's cities (when I select one), but I don't see a city's country (when I select a city).

So what should I do to make cities see their country?

I can add a @JoinColumn(name = "COUNTRY_ID") to the Country.cities field and it works in two ways.

But I don't like to add columns to city's table from country's code.

So I added the @JoinColumn to the City.country field and it didn't work.

So - how to make the association work in 2 ways w/o an association table??


OK, to be precise: I used the above code add feed the DB with this objects:

    Country germany = new Country("Germany", new HashSet<>(asList(
            new City("Berlin"),
            new City("Hamburg")
    )));

.. and viewed the DB. It looked like this:

table COUNTRIES_CITIES (note, I didn't declare it; Hibernate does automatically)

COUNTRIES_ID   CITIES_ID  
1              1
1              2

table COUNTRIES

ID      NAME  
1       Germany

table CITIES (note I didn't declare the COUNTRY_ID column! Hibernate again..)

ID   NAME      COUNTRY_ID  
1    Berlin    null
2    Hamburg   null

And that's it. Fetching the country gives me the cities, fetching the city gives me null country.


If I add a @JoinColumn to the Country class, then the a column is appended to the CITIES table and fetching works two ways.

Upvotes: 2

Views: 3319

Answers (3)

Dilli Babu Kadati
Dilli Babu Kadati

Reputation: 169

step 1: Add mappedBy at OneToMany side.

 @OnetoMany(mappedBy="users")
   private List<Address> address;

step 2: Add JoinColumn at ManyToOne Side.

 @ManytoOne
 @JoinColumn("userId")
 private User user;

Upvotes: 0

SpartanElite
SpartanElite

Reputation: 624

After reading your edit problem is clear.

The way you are adding cities and associating with Country...

Country germany = new Country("Germany", new HashSet<>(asList(
        new City("Berlin"),
        new City("Hamburg")
)));

If you do this then City does not have a country. No where you setting City's country property. ie. city.country = germany;
In a bidirectional relationship you cannot rely on JPA or your provider to entirely manage object persistence for you.

So This is what you need to do..

Country germany = new Country("Germany");
City berlin = new City("Berlin");
City Hamburg = new City("Hamburg");
berlin.country = germany;
hamburg.country = germany;
germany.cities = new HashSet<>(asList(berlin, hamburg));
germany.saveOrUpdate(); // or whichever definition you use

Now in the db you Cities Table will have correct country ids. Also it is recommended, since this is a bidirectional relationship, that you use the mappedBy attribute in your @OneToMany relationship. Using it you are telling JPA that cities is the inverse side of the Country 1-n City relationship.

Upvotes: 3

Ben
Ben

Reputation: 1177

Have you tried using the mappedBy property?

@OneToMany(mappedBy="country", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<City> cities;

For an explanation, look here: Can someone please explain mappedBy in hibernate?

Upvotes: 2

Related Questions