Question

I hope I can explain this clearly the first attempt. So I have two entities: Person and Address. One person can have many addresses, so my Person entity is composed of a list of addresses. Note that addresses can be shared among different people, however my Address entity does not need a reference to a Person entity. Also, each Address entity will have a rank attribute.

My table structure is as follows:

PERSON (
  person_id,
  etc,
  primary key (person_id)
)

ADDRESS (
  address_id,
  etc,
  primary key (address_id)
)

PERSON_ADDRESS_MAP (
  person_id,
  address_id,
  rank,
  foreign key (person_id) references person (person_id),
  foreign key (address_id) references address (address_id),
  primary key (person_id, address_id, rank)
)

Given the above, I'm not sure how to annotate my List of addresses in Person, or the rank attribute in Address. I suspect the Person will look as follows:

@Entity
public class Person {
  @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinTable(name="person_address_map", joinColumns=@JoinColumn(name="person_id"), inverseJoinColumns=@JoinColumn(name="address_id") )
  private List<Address> addresses;
  ...
}

I'm clueless on how to annotate rank in the Address entity.

Thanks in advance

Was it helpful?

Solution

First of all, the logical association between Person and Address is a many-to-many, since a person has many addresses, and an address is shared by many persons.

The rank, you say, is a property of Address. But for a given address, the rank can be 1 (for Bob) or 2 (for Mary). This simply shows (and the table model shows it clearly) that rank is not a property of Address.

So, the solution to your problem is simple: you have to map the PERSON_ADDRESS_MAP table to an entity:

public class Person {
    @OneToMany(mappedBy = "person")
    private Set<RankedAddress> rankedAddresses;
}

public class RankedAddress {
    @ManyToOne
    private Person person;

    @ManyToOne
    private Address address;
}

public class Address {
    @OneToMany(mappedBy = "adress")
    private Set<RankedAddress> rankedAddresses;
}

I also advise you, as for all the entities, to add a single-column, auto-generated ID (and the corresponding column) to the RankedAddress entity.

If rank is the only additional of the join table, and if it's used to contain the index of each address in a person's address list (i.e. it goes from 0 to N - 1, N being the number of addresses of a user), then there is an alternative, which doesn't force you to map the join table to an entity:

public class Person {
    @ManyToMany
    @OrderColumn(name = "rank")
    private List<Address> addresses;
}

Note that the value of the column will completely be handled by JPA, and it will only be used to store every address at a given index in the list. It won't be available for queries, and you won't be able to know the rank of a person's address, other than by getting its index in the list.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top