I am implementing a unit test using the H2 embedded database. When I insert an entry in a table, I am able to retrieve the entry using a native SQL query, but not with an HQL query. A find by the primary key also works through the JPA EntityManager interface. I am using Hibernate as the persistence provider.
Configuration:
<bean id="hibernateJpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:showSql="true" p:generateDdl="false" p:databasePlatform="org.hibernate.dialect.H2Dialect" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="hibernateJpaVendorAdapter"
p:persistenceUnitName="AMgSAdapter" p:packagesToScan="com.hcsc.amgs.adapter.domaindto">
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.ejb.interceptor" value="com.hcsc.amgs.adapter.dao.hibernate.interceptor.AuditableFieldInterceptor" />
</map>
</property>
</bean>
Test Case:
#Test
#Transactional(value="transactionManager",propagation = Propagation.REQUIRED)
public void getVasPolicyMatchesTest() {
Application application = TestDataCreationUtil.createApplication();
entityManager.persist(application.getX834EnrollmentApplicationTransaction());
entityManager.persist(application);
List<Application> matches = new ArrayList<Application>();
Query q = simpleQueryHQL();
matches= q.getResultList();
Application findApp = entityManager.find(Application.class, application.getId()); // this works
Assert.assertTrue(matches.size() > 0);
}
private Query simpleQueryHQL() {
return entityManager.createQuery("Select app From Application app", Application.class);
}
private Query simpleQuerySQL() {
return entityManager.createNativeQuery("Select * from Application", Application.class);
}
No exceptions are thrown, the test case fails for simpleQueryHQL() and passes for simpleQuerySQL()
Related
I am performing retrieval operation to get list of students from database. But I am getting 'empty' data from database. Used HibernateTemplate in
Spring with Hibernate integration,
domain class:-
#Entity
#Table(name="student")
public class StdBO {
#Id
private int sno;
private String sname,sadd;
//setters and getters
}
How can I use HibernateCallBack() interface for search operation? This is my first time that integrating spring with hibernate, is the below way correct? I tried many ways to perform search operations using HibernateTemplate but failing to get the details
DAO
#Repository
public class StdDAO {
private HibernateTemplate ht;
public void setHt(HibernateTemplate ht) {
this.ht = ht;
}
public List<StdBO> select(){
List<StdBO> list = ht.executeFind(new HibernateCallback() {
public Object doInHibernate(Session ses)
throws HibernateException, SQLException {
Criteria criteria=ses.createCriteria(StdBO.class);
System.out.println("before printing sutdents");
List<StdBO> bos = criteria.list();
System.out.println("students are"+bos);//here getting empty list
return bos;
}
});
return list;
}
xml
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="annotatedClasses">
<list>
<value>com.nt.dao.StdDAO</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
</bean>
<bean id="template" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="dao" class="com.nt.dao.StdDAO">
<property name="ht" ref="template" />
</bean>
You need begin (and commit) a transaction to query data. You can do it manually by session.beginTransaction() or using #Transactional annotation. For using #Transactional annotation you will need to do some additional spring configuration:
Hibernate Transaction Annotation Configuration.
I have a spring project with the dao and integration tests for it. For integration tests I am using hsqldb.
Everything was ok, untill I had to add "USE INDEX" command to my query. The application works fine and fetches records as expected.
But tests started to faile with SQL exception "Unexpeced token USE in command".
So I am wondering, is there any way to configure htsqldb to recognize "USE INDEX" statement? Thanks
My Dao looks like the following:
public interface SomeDao extends CrudRepository<Mapping, Integer> {
#Query(value = "SELECT mm.record_id" +
" FROM mappings mm" +
" USE INDEX (mapping_indx)" +
" JOIN records ss ON mm.record_id = ss.id "
" WHERE mm.name= :name", nativeQuery = true)
public List<Integer> getRecordsIds(#Param("name") String name);
}
My test example:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath*:testContext.xml")
public class SimpleTEst{
#Autowired
private SomeDao someDao;
//...other daos
#Test
public void testDao() {
//...test background creation
List<Integer> actualList = someDao.getRecordsIds("testing");
assertEquals(expectedList, actualList);
}
}
testContext.xml contains the following settings
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:myTest"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaDialect" ref="jpaDialect"/>
<property name="persistenceXmlLocation" value="classpath*:/META-INF/persistence.xml"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource"/>
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="namingStrategy" class="org.hibernate.cfg.ImprovedNamingStrategy"/>
different dbs are not compatible so, in general, you can't run same sql on both of them. you have a few quick potential workarounds:
teach your test database new constructs/functions. in some in-memory dbs you can register new functions. not sure if it's your case
skip some tests when running on different-vendor-db. if you don't test also on same-vendor-db then this actually mean: remove the test :(
create/choose query dynamically base on your runtime-detected vendor. this way you can limit tested part of query
to summarize: there is probably absolutely no way to test use index on hsqldb. you should test it on real db. if you really want to stick to hsqldb, what you can do is to try to test as similar query as possible... but not the same, sorry
We have a scenario where in the catalog/schema combination is different for the entity classes inside certain package from the default one used by all others. I am trying to set Catalog and Schema on #Table annotation using PersistenceUnitPostProcessors callback at runtime using javaassist as below.
The issue: The added member values on javaassist annotation are NOT getting reflected on to the actual class associated with it. Please help me in finding the wrong lines of code; OR if there are other ways to achieve this, more than happy to know.
Note: I do not want to create a separate EntityManagerFactory for each catalog/schema combination - it is not really required in our case as the datasource is same.
related content in spring context :
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
<bean name="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="mainUnit" />
<property name="packagesToScan" value="com.mycompany.lob.domain" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceUnitPostProcessors">
<list>
<bean class="com.mycompany.lob.jpa.CustomPersistenceUnitPostProcessor"/>
</list>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SqlmxDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">100</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.connection.autocommit">true</prop>
<prop key="hibernate.default_schema">DEFAULT_SCHEMA</prop>
<prop key="hibernate.default_catalog">DEFAULT_CATALOG</prop>
</props>
</property>
</bean>
PersistenceUnitPostProcessors callback :
public class CustomPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
#Value("${user.schema}")
private String userSchema;
#Value("${user.catalog}")
private String userCatalog;
private static final Logger LOGGER = LoggerFactory.getLogger(CustomPersistenceUnitPostProcessor.class);
#SuppressWarnings("unchecked")
#Override
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
LOGGER.info("MutablePersistenceUnitInfo : {} ",pui);
List<String> jpadomains = pui.getManagedClassNames();
for (Iterator<?> iterator = jpadomains.iterator(); iterator.hasNext();) {
String clazzName = (String) iterator.next();
if(clazzName.startsWith("com.mycompany.lob.domain.user")){
try {
//modify annotation attributes using JavaAssist
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get(clazzName);
ClassFile classFile = ctClass.getClassFile();
ConstPool constPool = classFile.getConstPool();
AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute)classFile.getAttribute(AnnotationsAttribute.visibleTag);
if(annotationsAttribute!=null){
//Get hold of #Table annotation
Annotation tableAnnotation = annotationsAttribute.getAnnotation("javax.persistence.Table");
if(tableAnnotation!=null){
tableAnnotation.addMemberValue("catalog", new StringMemberValue(userCatalog, constPool));
tableAnnotation.addMemberValue("schema", new StringMemberValue(userSchema, constPool));
annotationsAttribute.addAnnotation(tableAnnotation);
LOGGER.debug("Schema-Table : {} - {} ", ((StringMemberValue)tableAnnotation.getMemberValue("schema")).getValue(),
((StringMemberValue)tableAnnotation.getMemberValue("name")).getValue() );
//write the file back
ctClass.writeFile();
}
}
} catch (Exception e) {
LOGGER.error("Schema/Catalog could not be altered for {} ",clazzName);
}
}
}
}
}
Simple answer:
19. Multitenancy
Complex catalog mapping:
interface PhysicalNamingStrategy in Hibernate v5 is helpful.
public interface PhysicalNamingStrategy {
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment);
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment);
....
}
Check the Example 2. Example PhysicalNamingStrategy implementation in Hibernate 5 User Guide and how to config it
for some reason the database (ugly!) that I should use contains all the tables twice; every table are duplicated into these modes: DB1_<table> and DB2_<table>.
The structures of these databases are the same!
The application that I am realizing uses Spring + Hibernate and should permit to the users to change the database on runtime; this mean that a user can start the application using database DB1 and after some minutes change to DB2, return to DB1 and so on.
I have tried to extend DefaultNamingStrategy for every databases:
// I have create also DB2
public class DB1 extends DefaultNamingStrategy {
private static final long serialVersionUID = 676544180324515651L;
#Override
public String tableName(String tableName) {
return "DB1_" + tableName;
}
}
and set the naming strategy through the property hibernate.ejb.naming_strategy of jpa dinamically but for a reason that I can't understand I can change the naming strategy only once, and all next callings trown an Exception.
Someone know why?
Configuration of entityManagerFactory:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="it.perfectquiz.entity" />
<property name="persistenceProviderClass" value="org.hibernate.jpa.HibernatePersistenceProvider" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
How I try to change naming strategy:
XmlWebApplicationContext context = (XmlWebApplicationContext) ContextLoader.getCurrentWebApplicationContext();
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
GenericBeanDefinition entityManager = (GenericBeanDefinition) beanFactory.getBeanDefinition("entityManagerFactory");
ManagedProperties jpaProperties = (ManagedProperties) entityManager.getPropertyValues().get("jpaProperties");
TypedStringValue namingStrategy = (TypedStringValue) jpaProperties.get(new TypedStringValue("hibernate.ejb.naming_strategy"));
// only for test!
String newNaming;
if (namingStrategy.getValue().equals(DB1.class.getCanonicalName()))
newNaming = DB2.class.getCanonicalName();
else
newNaming = DB1.class.getCanonicalName();
// only for test!
namingStrategy.setValue(newNaming);
beanFactory.registerBeanDefinition("entityManagerFactory", entityManager);
Thanks,
Regards
I am trying to implement a simple DAO using hibernate 4 and Spring 3.
When I try to save or delete a row in the db the transaction is not persisted. I have included some code to show how the saving in the db doesnt work:
I have a junit test which simply tries to save a StockEntityDTO in the db.
#RunWith(SpringJUnit4ClassRunner.class)
public class StocksDAOImplTest extends
AbstractTransactionalJUnit4SpringContextTests {
#Autowired
protected StocksDAO stockDao;
#Test
public void shouldInsertIntoDatabase() {
BigDecimal price = new BigDecimal(653.50);
StockEntityDTO savedStock = new StockEntityDTO("GOOG", price, "google");
stockDao.create(savedStock);
StockEntityDTO retrievedStock = stockDao.getById(savedStock.getId());
assertEquals(savedStock, retrievedStock);
}
The test passes but the expected row (1, "GOOG", 653.50, "google") is not persisted in the db.
The DAO looks like this:
#Transactional
public abstract class AbstractHibernateDAO<T extends Serializable> {
private Class<T> clazz;
#Resource(name = "sessionFactory")
private SessionFactory sessionFactory;
public void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public void create(final T entity) {
Session session = this.getCurrentSession();
session.save(entity);
}
Application Context:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:orcl" />
<property name="username" value="gtp" />
<property name="password" value="gtp" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ubs.gtp.data.domain" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext
</prop>
</props>
</property>
</bean>
Hope someone can help. As is probably evident from my code, I am very new to spring.
AbstractTransactionalJUnit4SpringContextTests rolls back after the test. Try setting a breakpoint at the last line and then inspecting the database. You can use the Rollback annotation if you don't want this default behaviour.