2009-05-27 14 views
6

में स्कीमा नाम के साथ @Table का उपयोग मैं कैसे हाइबरनेट 3.3.1ga और HSQLDB का उपयोग कर इकाई परीक्षण में यह काम कर सकते हैं । दूसरी समस्या यह है कि हाइबरनेट CREATE TABLE TEST.CATEGORY को मेरे किसी भी कोड चलाने से पहले जारी करता है (यह स्प्रिंग के परीक्षण सेटअप के अंदर गहरा होता है), इसलिए मुझे हाइबरनेट से पहले डीबी से कनेक्शन नहीं मिल सकता है और स्कीमा मैन्युअल रूप से बना सकता है।हाइबरनेट 3.3.1ga और HSQLDB

लेकिन मुझे स्कीमा की आवश्यकता है क्योंकि मुझे वास्तविक कोड में विभिन्न डेटाबेस तक पहुंचना है। मुझे क्या करना चाहिए?

हाइबरनेट 3.3.1ga, HSQLDB, स्प्रिंग 2.5

उत्तर

1

मेरे वर्तमान समाधान इस तरह दिखता है:

@Override 
protected String[] getConfigLocations() { 
    createHSQLDBSchemas(); 

    return new String[]{ 
      "test-spring-config.xml" 
    }; 
} 

private static boolean hsqldbSchemasCreated = false; 

public static void createHSQLDBSchemas() 
{ 
    if (hsqldbSchemasCreated) 
     return; 

    try 
    { 
     log.info ("createHSQLDBSchemas"); 

     Class.forName("org.hsqldb.jdbcDriver").newInstance(); 
     Connection c = DriverManager.getConnection("jdbc:hsqldb:mem:test", "sa", ""); 
     Statement stmt = c.createStatement(); 

     String sql; 
     sql = "CREATE SCHEMA xxx AUTHORIZATION DBA"; 
     log.info (sql); 
     stmt.execute (sql); 

     stmt.close(); 
     c.close(); 
    } 
    catch (Exception e) 
    { 
     throw new ShouldNotHappenException (e); 
    } 

    hsqldbSchemasCreated = true; 
} 

लेकिन यह है कि एक बहुत बदसूरत हैक की तरह लगता है। क्या कोई बेहतर समाधान नहीं है?

0

ऐसा लगता है कि आपके पास हाइबरनेट डीडीएल निर्माण कोड में एक पुनरुत्पादित बग है। आपको report a bug होना चाहिए - यह एक दीर्घकालिक समाधान है, लेकिन ओपन सोर्स में चीजें पूरी तरह से की जाती हैं। बेशक आप एक पैच बनाना चाहते हैं, लेकिन मुझे कभी भी हाइबरनेट कोड बेस हैक करने में आसान नहीं मिला।

+0

वहां पहले से ही इस बात के लिए खुला कीड़े हैं: http: // ओपनसोर्स। atlassian.com/projects/hibernate/browse/HHH-1853 लेकिन जाहिर है, डेवलपर्स पैच पसंद नहीं करते हैं (यह * तीन साल * के लिए खुला है, अब)। यह मुझे बताता है: कभी भी ठीक नहीं होगा। वे सिर्फ परवाह नहीं करते हैं। तो मुझे एक कामकाज की जरूरत है। –

+0

यह शर्म की बात है, लेकिन ऐसा होता है: | । आप किस तरह का समाधान ढूंढ रहे हैं? आपके भीतर उप-इष्टतम क्या है - तथ्य यह है कि आपको स्कीमा या तथ्य यह है कि इसे आपके परीक्षण कोड में रखा गया है (मुझे कोड से लगता है) बनाना है? –

+0

मुझे नाखुश है कि मुझे इसे प्राप्त करने में करना है कॉन्फिग लोकेशन() - यह विधि पूरी तरह से कुछ और करती है और यदि कोई इस कोड की तलाश में था, तो यह देखने के लिए आखिरी जगह होगी। –

5

आप एक वर्ग को लागू करने वाली InitializingBean लिख सकते हैं:

public class SchemaCreator implements InitializingBean { 

    private String schema; 
    private DataSource dataSource; 

    public String getSchema() { 
     return schema; 
    } 

    public void setSchema(String schema) { 
     this.schema = schema; 
    } 

    public DataSource getDataSource() { 
     return dataSource; 
    } 

    public void setDataSource(DataSource dataSource) { 
     this.dataSource = dataSource; 
    } 

    @Override 
    public void afterPropertiesSet() throws Exception { 
     JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 
     jdbcTemplate.execute("CREATE SCHEMA " + schema + " AUTHORIZATION DBA"); 
    } 

} 

फिर आप इस वर्ग के अपने सेम परिभाषा फ़ाइल में एक सेम को परिभाषित करने के लिए है (मैं के रूप में अंधेरे में एक शॉट ले रहा हूँ क्या अपने मौजूदा बीन परिभाषाएं दिखती हैं)।

<bean id="dataSource" class="..."> 
    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> 
    <property name="url" value="jdbc:hsqldb:mem:test"/> 
    <property name="username" value="sa"/> 
    <property name="password" value=""/> 
</bean> 

<bean id="sessionFactory" depends-on="schemaCreator" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource"/> 
    ... 
</bean> 

<bean id="schemaCreator" class="SchemaCreator"> 
    <property name="dataSource" ref="dataSource"/> 
    <property name="schema" value="TEST"/> 
</bean> 

हाइबरनेट की फलियों की depends-on विशेषता का उपयोग करके, वसंत यह सुनिश्चित करेंगे कि schemaCreator सेम पहले प्रारंभ किया जाएगा, स्कीमा बस समय में मौजूद हैं के कारण। इससे आपके इरादे स्पष्ट हो सकते हैं।

0

मैं उसी समस्या में भाग गया जहां एमएस एसक्यूएल सर्वर सूची और स्कीमा परिभाषित करना चाहता है, लेकिन एचएसक्यूएलडीबी नहीं करता है। मेरा समाधान कस्टम orm.xml फ़ाइल (persistence.xml के माध्यम से) को विशेष रूप से एमएस एसक्यूएल सर्वर के लिए लोड करना था जो कैटलॉग और स्कीमा सेट करता है। अपने META-INF/persistence.xml फ़ाइल

में

@Entity 
@Table(name="CATEGORY") 
public static class Category { ... } 

2.Specify दो हठ इकाई नोड्स:

1.Only अपनी इकाई के लिए @Table नाम (किसी भी सूची या स्कीमा जानकारी को छोड़ देते हैं) निर्दिष्ट

<persistence version="2.0" 
    xmlns="http://java.sun.com/xml/ns/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"> 

    <!-- 
    | For production and integration testing we use MS SQL Server, which needs 
    | the catalog and schema set (see orm-mssql.xml). 
    |--> 
    <persistence-unit name="com.mycompany.prod"> 
     <mapping-file>META-INF/orm-mssql.xml</mapping-file> 
    </persistence-unit> 

    <!-- 
    | For unit testing we use HSQLDB, which does not need the catalog or schema. 
    |--> 
    <persistence-unit name="com.mycompany.test" /> 

</persistence> 

3.Specify डिफ़ॉल्ट सूची और ORM-mssql.xml फ़ाइल में स्कीमा:

<entity-mappings version="2.0" 
    xmlns="http://java.sun.com/xml/ns/persistence/orm" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"> 

    <persistence-unit-metadata> 

     <!-- 
     | Set the catalog and schema for MS SQL Server 
     |--> 
     <persistence-unit-defaults> 
      <schema>MYSCHEMA</schema> 
      <catalog>MYCATALOG</catalog> 
     </persistence-unit-defaults> 

    </persistence-unit-metadata> 

</entity-mappings> 

4.I'm SPRI का उपयोग कर एनजी जेपीए कॉन्फ़िगर करने के लिए, तो मैं persistenceUnitName के मूल्य के लिए एक संपत्ति-प्लेसहोल्डर का उपयोग करें:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dataSource" /> 
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> 
    <property name="persistenceUnitName" value="${entityManagerFactory.persistenceUnitName}" /> 
</bean> 

इकाई परीक्षण के लिए, 'com.mycompany.test' का उपयोग करें और के लिए एकीकरण-परीक्षण/उत्पादन की तैनाती, उपयोग 'कॉम .mycompany.prod '।

1

नीचे एक उदाहरण है कि आप कैसे परीक्षण hslqdb के साथ वसंत कॉन्फ़िगरेशन बना सकते हैं यह स्वचालित रूप से @Table (schema = ...) से आपके सभी स्कीमा का पता लगाता है और उन्हें आपके लिए बनाता है।

यदि यह सिर्फ इस परीक्षण आप के लिए काम करना चाहिए के लिए है:

import org.reflections.Reflections; //maven artifact: 'org.reflections:reflections:0.9.9-RC1' 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.Lazy; 
import org.springframework.core.io.ClassPathResource; 
import org.springframework.jdbc.core.JdbcTemplate; 
import org.springframework.jdbc.datasource.DriverManagerDataSource; 
import org.springframework.orm.hibernate4.LocalSessionFactoryBean; 

import javax.persistence.Table; 
import java.util.HashSet; 
import java.util.Properties; 
import java.util.Set; 

@Configuration 
@ComponentScan("com.test.collection") 
public class CollectionConfig { 

private static final String[] ENTITY_PACKAGES = { "com.test.collection.domain.dao" }; 
private static final String CONFIGURATION_LOCATION = "/movie-collection-hibernate.cfg.xml"; 

@Bean(name = "testSessionFactory") 
@Lazy 
public LocalSessionFactoryBean getTestSessionFactory() { 
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); 
    sessionFactory.setPackagesToScan(ENTITY_PACKAGES); 

    Properties hibernateProperties = getHibernateHsqlTestDbProperties(); 
    sessionFactory.setHibernateProperties(hibernateProperties); 

    createNonStandardSchemas(hibernateProperties); 

    return sessionFactory; 
} 

private void createNonStandardSchemas(Properties properties) { 
    final String DEFAULT_SCHEMA = ""; 

    Set<String> schemas = new HashSet<>(); 
    Reflections reflections = new Reflections(ENTITY_PACKAGES); 
    Set<Class<?>> annotatedClasses = 
      reflections.getTypesAnnotatedWith(Table.class); 

    for (Class<?> clazz : annotatedClasses) { 
     Table table = clazz.getAnnotation(Table.class); 
     if (!DEFAULT_SCHEMA.equals(table.schema())) { 
      schemas.add(table.schema()); 
     } 
    } 

    if (!schemas.isEmpty()) { 
     DriverManagerDataSource driverManager = new DriverManagerDataSource(); 
     driverManager.setDriverClassName(properties.getProperty("hibernate.connection.driver_class")); 
     driverManager.setUrl(properties.getProperty("hibernate.connection.url")); 
     driverManager.setUsername(properties.getProperty("hibernate.connection.username")); 
     driverManager.setPassword(properties.getProperty("hibernate.connection.password")); 

     JdbcTemplate jdbcTemplate = new JdbcTemplate(driverManager); 

     for (String schemaName : schemas) { 
      jdbcTemplate.execute(
        String.format("DROP SCHEMA IF EXISTS %s", schemaName) 
      ); 
      jdbcTemplate.execute(
        String.format("CREATE SCHEMA %s AUTHORIZATION DBA", schemaName) 
      ); 
     } 
    } 
} 


private Properties getHibernateHsqlTestDbProperties() { 
    Properties prop = new Properties(); 
    prop.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver"); 
    prop.setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:test"); 
    prop.setProperty("hibernate.connection.username", "sa"); 
    prop.setProperty("hibernate.connection.password", "test"); 
    prop.setProperty("hibernate.connection.pool_size", "5"); 
    prop.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); 
    prop.setProperty("hibernate.current_session_context_class", "thread"); 
    prop.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.internal.NoCachingRegionFactory"); 
    prop.setProperty("hibernate.show_sql", "false"); 
    prop.setProperty("hibernate.format_sql", "false"); 
    prop.setProperty("hibernate.use_sql_comments", "false"); 
    prop.setProperty("hibernate.hbm2ddl.auto", "create-drop"); 
    return prop; 
} 


} 

और यहाँ एक परीक्षण नमूना है:

@ContextConfiguration(classes = CollectionConfig.class) 
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) 
public class DaoMappingTest extends AbstractTestNGSpringContextTests { 

@Autowired 
private SessionFactory testSessionFactory; 

@Test 
public void thatMovieIsSaved() { 
    Movie killBill = getKillBillMovie0(); 

    saveToDb(Arrays.asList(killBill)); 

    Session querySession = testSessionFactory.openSession(); 
    List<Movie> movies = querySession.createQuery("from Movie").list(); 
    querySession.close(); 

    assertThat(movies).containsExactly(killBill); 
} 

@Test 
public void that2MoviesIsSaved() { 
    Movie killBill = getKillBillMovie0(); 
    Movie terminator = getTerminatorMovie1(); 

    saveToDb(Arrays.asList(killBill, terminator)); 

    Session querySession = testSessionFactory.openSession(); 
    List<Movie> movies = querySession.createQuery("from Movie").list(); 
    querySession.close(); 

    assertThat(movies).containsOnly(killBill, terminator); 
} 

private void saveToDb(List<?> objects) { 
    Session session = testSessionFactory.openSession(); 
    session.beginTransaction(); 

    for(Object obj : objects) { 
     session.save(obj); 
    } 

    session.getTransaction().commit(); 
    session.close(); 
} 

@AfterSuite 
public void tearDown() { 
    testSessionFactory.close(); 
} 
} 
संबंधित मुद्दे