2013-06-04 129 views
0

我有一個JPA繼承的問題。見下面我的實體。我有一個Person,可以在HouseCar,當然從不在同一時間。接口CarHouse實現PersonHoldable接口。我知道我無法將一個實體直接映射到一個接口。JPA繼承映射多個實現

這是我的模型:

@Entity 
public class Person{ 
    private PersonHoldable personHoldable; // either a Car or a House 

    // This does not work of course because it's an interface 
    // This would be the way to link objects without taking JPA into consideration. 
    @OneToOne 
    public PersonHoldable getPersonHoldable() { 
    return this.personHoldable; 
    } 

    public void setPersonHoldable(PersonHoldable personHoldable) { 
    this.personHoldable = personHoldable; 
    } 
} 

@Entity 
public class Car implements PersonHoldable{} 

@Entity 
public class House implements PersonHoldable{} 

public interface PersonHoldable{} 

我怎樣才能在JPA正確映射該採取以下考慮?

  1. 我試過@MappedSuperclassPersonHoldable的抽象實現。雖然它可以用於這個特定的設置,但問題在於CarHouse實際上實現了更多的接口。它們也映射到其他實體。
  2. Person可能有一個屬性爲每個可能PersonHoldable,因此在這種情況下它可能有一個getCar()getHouse()屬性。這對我來說似乎並不靈活。如果我要添加一個BikePersonHoldable的實現,我將不得不更改我的Person類。
  3. 我可以映射另一種方式,所以在PersonHoldable實現端只有OneToOne關係。這意味着將getPerson()屬性添加到PersonHoldable。但是,從Person的角度來看,它並不是很容易看到它與什麼PersonHoldable相關聯。
  4. 我使用默認的JPA,所以如果可能的話,沒有Hibernate特定的標籤。

如果這對於默認JPA是不可能的,那麼在這種情況下最好的做法是什麼?

+1

這不支持標準的JPA。它需要一個'@ Any'休眠映射來映射這種關聯。 –

+0

謝謝,似乎Hibernate'@ Any'不過是兩列,一列包含'type',另一列包含'id'。可以手動實施。這是常見的做法嗎? –

+1

除了生成適合您的所有查詢之外,它只是「沒有更多」,例如「從Person p左連接獲取p.personH​​oldable」中選擇p,並且它允許導航到personH​​oldable而不必關心它是什麼類型。使用這種映射常見的做法是什麼?我從來沒有必要自己使用它。我寧願定義一個所有PersonH​​oldable實體都會擴展的抽象實體。這將是標準的JPA。 –

回答

1

第二點的一個細微變化是讓Person有一個繼承類型並實現一個CarPerson和HousePerson(後來是一個BikePerson),它的全部目的是爲特定的PersonH​​older實現定義特定的連接關係。這樣可以保持完整的關係,並且更容易從Person端進行查詢。

@Inheritance(strategy = JOINED) 
@DiscriminatorColumn(name="holdableType", discriminatorType=CHAR, length=1) 
@Entity 
public class Person { 
    // common fields 
} 

@Entity 
@DiscriminatorValue("C") 
public class CarPerson extends Person { 
    @OneToOne 
    private Car car; 
} 

@Entity 
@DiscriminatorValue("H") 
public class HousePerson extends Person { 
    @OneToOne 
    private House house; 
} 
+0

這使得它不可能改變它所居住的地方。一旦它是CarPerson,它就是CarPerson,不能成爲HousePerson。我寧願在PersonH​​oldable方面使用繼承。 –

+0

一旦它是一個CarPerson,它就會在與汽車有關的表格中關聯數據。無法快速轉移到HousePerson是一個因素,而不是對象的層次結構。如果業務需要在CarPerson和HousePerson之間切換,那麼可以通過適當處理持久層的工廠方法輕鬆完成。我認爲有人可能同時是汽車和房子的人,但寫下的問題清楚地表明瞭1-1的關係。 – Jeff

+0

該問題與它們存儲在不同表中的事實無關。即使使用單表繼承,您也會遇到這個問題,這是由於給定類型的對象不能成爲Java中另一種類型的對象。因此,更改類型的唯一方法是刪除該人員並將其重新創建爲另一種類型(如果該人員有外鍵則不起作用),或者使用JDBC將該行從一個表格移動到另一個表格,或者在單表繼承的情況下更改行中的鑑別器值。 –