2014-02-12 36 views
4

在我的項目中,我有一個JPA層次結構Location -> Site。現在從層次結構中檢索的實體類

@Entity 
@Table(name = "LOCATION") 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="LOC_TYPE",discriminatorType=DiscriminatorType.STRING) 
public class Location { 
    ... 
} 

@Entity 
@DiscriminatorValue("SI") 
public class Site extends Location { 
    ... 
} 

,每Employee具有分配的Location列表(就算了,據我所知,所有這些地方實際上是Site)。在某些部分,我需要列出Site s和Employee已經分配給(注意,我定義的關係是Location s)。

使用Hibernate 3.2,我可以只寫Location的查詢並通過判別式過濾;返回的類是更具體的子類的實例,v.g:

Query query = em.createQuery("SELECT loc FROM Location loc WHERE loc.type=\"SI\""); 
List<Location> locations = (List<Location>) query.getResultList(); 
for (Location location : locations) { 
    Site mySite = (Site) location; 
    ... 
} 

但是,我無法找到,如果這種行爲是由JPA規範保證或告訴是從休眠只是一個實現決策的任何文件。在最後一種情況下,我不應該使用這種方法,因爲如果我切換提供者,它可能會改變)。

你能告訴我,如果我的方法是由標準支持?

順便說一句,我使用JPA 1基於Hibernate 3.2

UPDATE:

在奧登澄清我想要的東西,這就是「安全警報」,我已經實現。請記住,disc屬性是鑑別器列,所以我確定返回的對象保持爲Site實例。

Query query = em.createQuery("SELECT lo FROM Employee em JOIN em.location lo WHERE lo.disc = 'SI'"); 
List<Location> locations = (List<Location>) query.getResultList(); 
List<Site> site = new ArrayList<Site>(); 
for (Location location : locations) { 
    if (location instanceof Site) { 
    sites.add((Site) location); 
    } else { 
    log.warn("Found a Location that is not instance of Site"); 
    } 
} 

JPA規範規定,我log.warn聲明絕不會叫什麼名字? AFAIK,也許一個實現可以返回一堆Location不是Site的實例。當然,在這種情況下只有Location屬性可用;該行爲有點像在C++中切片。

+0

我想你還是沒有解釋你的問題。你有一個Java字段'disc',它被映射到'LOC_TYPE'數據庫列嗎?如果沒有,比你可以簡單地嘗試。另外在你的例子中:爲什麼不直接尋找Site實體:'SELECT s FROM Site s WHERE ...'? –

+0

我的JPQL有點過分簡化了,現在它更具代表性。我不能只選擇「Site」實體,因爲我通過導航到「Location」超類。作爲最後一個解決方案,我可以用一個從'Location'返回ID來選擇'Site'的子選擇來解決這個問題,但這個問題讓我想到了這個問題(另外,我試圖避免' IN'子選擇表現問題)。 – SJuan76

+0

1.子選擇比「IN」更差。 2.只要你沒有1000個值,'IN'從來就不是問題。 3.你對我的第一個想法(也許你已經使用過)沒有提出任何意見:只需添加一個映射到你的LOC_TYPE數據庫鑑別器列的JAVA字段eType,並在你的查詢中使用它。 –

回答

5

在版本2.0開始的JPA中,您有TYPE(e)函數。從規範例如:

SELECT e FROM Employee e WHERE TYPE(e) IN (Exempt, Contractor) 

摘自JPA 2.0規範(4.6.17.4實體類型表達式):

一個實體型表達可用於限制查詢多態性。 TYPE運算符返回參數的確切類型。


注意JPA。另一方面,您的示例對基本的JPA機制產生懷疑,我想再次強調這一點:當您從數據庫中獲取一行(使用JPA查詢),其實例鑑別值爲Site實體時,您可以確定Java對象將是該類的一個實例(即Site類)。現在我相信該規範不會強制其級別爲Site(即fetchedEntity.getClass()==Site.class)的提供商,但您可以100%確定fetchedEntity instanceof Site返回true。


注意Hibernate。從我的Hibernate體驗中我只能補充一點,fetchedEntity.getClass() == Site.class在Hibernate中返回true(當然旁邊的事實是fetchedEntity instanceof Site)。

+0

感謝您的提示,很高興知道這個選項。無論如何,'WHERE'部分已經被覆蓋了,因爲我通過鑑別器進行過濾,我想要的是確保檢索到的'e'實際上已經被創建爲'Exempt'或'Contractor'實例(而不僅僅是一個純文本'員工') – SJuan76

+0

你是什麼意思的「部分已被覆蓋」?據我所知,這正是你所需要的(如果JPA 1.0支持的話):這些員工將完全是Java類型:'免責'或'承包商',而不是普通的'員工'。 –

+0

JPA 1不支持'TYPE'(我剛剛檢查過它)。我通過鑑別器進行篩選(如我的'JPQL')來解決它。無論如何,我想要的是規範的一部分(或缺少它),以確保您最後的肯定;我可能有點太擔心,但我有這樣的感覺,如果文檔沒有指定,一些實現可能會返回一個普通的'Employee'實體而不是原始的子類(因爲這是'JPQL'請求的「) – SJuan76