2014-03-27 28 views
1

我正準備進行Oracle JPAD認證,所以我在Java SE環境中使用實體玩弄了一點點(至少,這是我的想法...)。我注意到了一些我希望有人能夠闡明的東西。Java SE環境中的JPA:在persistence.xml中加載的實體類沒有defenition

Pro JPA2是我正在閱讀的書。在第2章結尾的某處,有一個示例persistence.xml文件,其中定義了一個類。好吧,所以這是在Java SE環境中的方法,因爲你並不是真的在容器中放置整個shebang。但是這裏有一件奇怪的事情:我有兩個使用@Entity註解的Entity類,並沒有將這些添加到persistence.xml中。但仍然是被加載!我gobsmacked。我現在能想到的唯一的事情是,我不是在SE環境或者它是一個新的休眠功能...

的persistence.xml:

<?xml version="1.0" encoding="UTF-8" ?> 
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" 
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"> 
    <persistence-unit name="employees" transaction-type="RESOURCE_LOCAL"> 

    <properties> 
     <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" /> 
     <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:." /> 
     <property name="javax.persistence.jdbc.user" value="SA" /> 
     <property name="javax.persistence.jdbc.password" value="" /> 

     <property name="hibernate.show_sql" value="false" /> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> 
     <property name="hibernate.connection.shutdown" value="true" /> 
     <property name="hibernate.hbm2ddl.auto" value="create-drop" /> 
    </properties> 

    </persistence-unit> 
</persistence> 

實體:

@Entity 
    @Access(AccessType.FIELD) 
    public class Employee { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Long id; 
    private String name; 
    private Date startDate; 
    private Long salary; 

    public Employee() { 
    } 

    public Employee(String name) { 
     this.name = name; 
    } 

    public Employee(String name, Long salary) { 
     this.name = name; 
     this.salary = salary; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public Date getStartDate() { 
     return startDate; 
    } 

    public void setStartDate(Date startDate) { 
     this.startDate = startDate; 
    } 

    public Long getSalary() { 
     return salary; 
    } 

    public void setSalary(Long salary) { 
     this.salary = salary; 
    } 

    @Override 
    public String toString() { 
     return "Employee [name=" + name + ", salary=" + salary + ", startDate=" + startDate + "]"; 
    } 
} 

測試:

public class TestConnection { 

    private static EntityManagerFactory entityManagerFactory; 
    private static EntityManager entityManager; 
    private static final String PERSISTENCE_UNIT_NAME = "employees"; 

    @BeforeClass 
    public static void initEntityManager() throws Exception { 
     entityManagerFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); 
     entityManager = entityManagerFactory.createEntityManager(); 
     TableStructurePrinter.outputTableStructure(entityManager); 
    } 

    @AfterClass 
    public static void closeEntityManager() { 
     entityManager.close(); 
     entityManagerFactory.close(); 
    } 

    @BeforeMethod 
    public void setupDB() throws Exception { 
     entityManager.getTransaction().begin(); 
     LoadEmployees.load(entityManager, 4); 
    } 

    @AfterMethod 
    public void cleanDB() throws Exception { 
     entityManager.getTransaction().rollback(); 
    } 

    @Test 
    public void testCountEmployees() { 
     Query q = entityManager.createQuery("select e from Employee e"); 
     assertEquals(q.getResultList().size(), 4); 
    } 

} 

從我TableStructurePrinter輸出(這是從INFORMA一個簡單的SELECT語句TION_SCHEMA.SYSTEM_TABLES和INFORMATION_SCHEMA.SYSTEM_COLUMNS):

T.TABLE_TYPE   T.TABLE_NAME   C.ORDINAL_POSITION C.COLUMN_NAME     C.TYPE_NAME  C.COLUMN_SIZE 
=================== =================== =================== =================== =================== =================== 
TABLE    EMPLOYEE        1 ID         BIGINT     64 
TABLE    EMPLOYEE        2 NAME        VARCHAR     255 
TABLE    EMPLOYEE        3 SALARY        BIGINT     64 
TABLE    EMPLOYEE        4 STARTDATE      TIMESTAMP     26 

回答

1

Hibernate可以自動檢測還實體,至少在Java EE環境,但我想說的也是這樣一個SE應用程序。 AFAIK它將掃描包含persistence.xml文件的jar以及其中列出的任何jar或類。

http://docs.oracle.com/cd/E16439_01/doc.1013/e13981/cfgdepds005.htm引述:

是否該持久性單元包括哪些持久託管類?
可以通過使用一個或多個以下的指定與一個持久性單元相關聯的持久性管理類:

  • <映射-file>元素:指定一個或多個對象關係映射的XML文件(ORM .xml文件)。

  • < jar-file>元素:指定一個或多個將被搜索類的JAR文件。

  • < class> element:指定一個顯式的類列表。

  • 包含在持久性單元的根中的帶註釋的託管持久性類。

    持久單元的根目錄是JAR文件或目錄,其META-INF目錄包含persistence.xml文件。要排除託管持久性類,請將一個< exclude-unlisted-classes>元素添加到持久性單元。

最後一部分是什麼,是你的情況,即管理類(實體)都包含在包含persistence.xml並因此被自動添加相同的罐子相關。

+0

我認爲你是對的,我甚至沒有意識到一個jar文件是在所有創建...但檢查jar,我看到實體不是直接在根,他們在自己的各自的包。所以現在我實際上有兩個問題:-) - 爲什麼創建了jar? - 爲什麼類加載,即使它們不直接在根中? (對不起,但我無法得到格式在這個答覆中工作...我正在研究它:-)) – Cesar

+1

@Cesar「根」不是根包,但jar文件本身(從上面引述:「持久化單元的根目錄是JAR文件...」),因此即使它們位於該jar中的它們各自的包中也會被發現。爲什麼創建jar取決於你的構建過程,所以你必須查看。 – Thomas

2

我注意到你在玩Java SE。基本上在Java SE環境中,您必須指定管理類和其他任何的行爲是不可移植的(檢查託管類下面的8.2.1.6.4列表)。作爲參數,我將添加來自JPA 2.0規範的摘錄,這實際上解釋了Hibernate(或我測試它的EclipseLink)是如何工作的(儘管不是便攜式的)以及您應該如何使用它:

託管的持久性類集由持久性單元,通過使用以下的一個或多個來定義:

8.2.1.6映射文件,JAR文件,類,排除-不公開的類

  • 帶註釋管理的持久性包含在持久性單元的根中的類(除非指定了排除-不公開的類元件 )
  • 一個或多個對象/關係映射的XML文件
  • 一個或多個jar文件將被搜索的類
  • 類的組的顯式列表由持久性單元管理的實體是這些源的聯合,與映射間位由XML映射

重寫由被管理的實體集對於任何給定類是 數據註釋(或註釋缺省值)持久性單元是的聯合個這些

中所含的持久性單元的根的持久性單元

所有類的根8.2.1.6.1註釋類被搜索 爲源[...]

註釋管理持久類的類與實體, 嵌入,或MappedSuperclass註解和任何映射元數據 註解這些類發現將被處理,否則將是 使用映射註釋默認映射。如果它不旨在 包含在 持久性單元的根註釋持久類被包括在持久性單元,所述 排除-不公開類元素必須被指定爲真。 的排除,非流通類的元素並不在Java SE環境中使用。託管類

8.2.1.6.4列表

[...]

所有命名管理的持久化類的列表必須 Java SE環境被指定爲保證便攜性。可移植的Java SE 應用程序不應該依賴於此處描述的其他機制來指定持久性單元的託管持久性類 。 持久性提供程序可能要求必須在Java SE環境中的每個 persistence.xml文件中完全枚舉要管理的實體類和 類的集合。

+0

感謝您的回答。我現在看到的方式是,我所有的類(實體,測試類和Main)都構成了一個不可移植的包,即找到了我的所有實體。 – Cesar

+1

沒錯。我知道這一點,因爲我也在Java SE環境中測試了一些東西。但是這不是可移植的,儘管這是Hibernate和EclipseLink(!!!參考實現!!!)的行爲(可能是出於向後兼容的原因)。但是你說你準備參加考試,所以你應該在那裏檢查正確的答案,而不是hibernate或eclipseLink的工作方式。 –

相關問題