Adib Saikali opened SPR-10296 and commented
When writing integration tests involving JPA JdbcTestUtils
is quite useful, however it would be better if there was a JpaTestUtils
which did everything that JdbcTestUtils
does without requiring that we pass in table names. Rather the table names should be extracted from the JPA entity mappings. For example.
@Entity
@Table(schema="foo",name="bar")
public class Bar{
}
// this call should extract the name of the table that the Bar is mapped
// to and then call JdbcTestUtils.countRowsInTable
int rows = JpaTestUtils.countRows(jdbcTemplate,Bar.class);
I am doing something like this in my base test classes, but it would be great if it was part of the official spring distribution.
The primary advantages for this approach are: * Tests don't break when table names are changed which happens during development, especially if you use a tool like flywaydb that makes it easy to build migration scripts * Eliminates strings and typos and leverages the power of the IDE
Affects: 3.2 GA
Comment From: spring-projects-issues
Sam Brannen commented
Adib Saikali, would you be willing to share the code that you're using to extract the entity's table name from the JPA metadata?
Furthermore, is it a robust, general solution that you're currently using?
Comment From: spring-projects-issues
Adib Saikali commented
My code handles the most common case when @Table
and @Entity
is present, which is the way I use JPA across my applications. I think many others might do the same thing. Here are some of the methods from my base class. I have omitted a few useful methods that I have which assume my standard way of using JPA. I think it is still worth including methods like this in the standard distribution because they are really useful and many spring users would not want to recreate their own or may not know how to recreate their own. Also I am sure other users will contribute more sophisticated ways of getting the table names and that will be implementation specific and over time the code to get the table names could become pretty complete.
Here is a useful link from SO http://stackoverflow.com/questions/2342075/how-to-retrieve-mapping-table-name-for-an-entity-in-jpa-in-runtime
// The code below uses a bunch of useful static methods from google guava.
/**
* Determine the fully qualified name of a table that a JPA entity is mapped to. which is schemaName.tableName
*
* @param entity
* the entity class that should have {@code @Table} and {@code @Entity} annotations.
* @return The table that the entity is mapped to
*/
public String entityTableName(Class<?> entity)
{
// check that the class is an entity
checkArgument(entity.isAnnotationPresent(Entity.class));
checkArgument(entity.isAnnotationPresent(Table.class));
// extract table name
Table table = entity.getAnnotation(Table.class);
if (isNullOrEmpty(table.schema()))
{
return checkNotNull(table.name());
} else
{
return table.schema() + "." + checkNotNull(table.name());
}
}
/**
* Delete all rows from the tables the passed in entities are mapped to.
*
* @param entityClasses
* @return
*/
public int deleteAllRows(Class<?>... entityClasses)
{
String[] tableNames = new String[entityClasses.length];
for (int i = 0; i < entityClasses.length; i++)
{
tableNames[i] = entityTableName(entityClasses[i]);
}
return JdbcTestUtils.deleteFromTables(jdbcTemplate, tableNames);
}
/**
* Count the number of rows in the table that the specified entity is mapped to using raw jdbc.
*
* @param entityClass
* the entity class that we will extract a table name from
*
* @param whereClause
* the where clause for the search
*
* @return the number of rows
*/
public int countRows(Class<?> entityClass, String whereClause)
{
return JdbcTestUtils.countRowsInTableWhere(this.jdbcTemplate, entityTableName(entityClass), whereClause);
}
/**
* Count all the rows of the table that the entity is mapped to.
*
* @param entityClass
* @return
*/
public int countRows(Class<?> entityClass)
{
return JdbcTestUtils.countRowsInTable(this.jdbcTemplate, entityTableName(entityClass));
}