通过在适当的地方添加括号来帮助您进行逻辑和调试,例如,尝试清楚查询操作数的分组。下面
flights = (List<Flight>) entityManager
.createQuery("SELECT f FROM Flight f WHERE f.departureTerminal = :destination AND f.arrivalTerminal = :arrival AND (f.departureTime <= :departureDate) AND (f.numberOfSeatsAvailable <= :numberOfPassengers)")
.setParameter("destination", destination)
.setParameter("arrival", arrival)
.setParameter("departureDate", newDate)
.setParameter("numberOfPassengers", numberOfPassengers).getResultList();
再想一想,尝试传递 1 个参数,然后调整您的请求以提供 1 个参数,然后继续执行第 2 个参数,等等。这将准确指出哪个参数有问题。
一旦你发现了那个罪魁祸首,现在通过作为唯一的请求参数传递来将你的问题简化为那个参数来修复它。
更新(我的解决方案):
我对您的代码进行了另一次破解,并且查询很好。我怀疑这是您的输入,就像您报告的异常一样。如果这对您的测试有帮助,我会执行以下操作来测试与您的查询类似的内容。
FlightTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestH2DatabaseConfiguration.class }, loader = AnnotationConfigContextLoader.class)
public class FlightTest extends AbstractTransactionalJUnit4SpringContextTests {
final static Logger log = LoggerFactory.getLogger(FlightTest.class);
@Autowired
@Qualifier("entityManagerFactory")
EntityManagerFactory entityManagerFactory;
@Test
@SuppressWarnings("unchecked")
public void test() throws ParseException {
assertNotNull(entityManagerFactory);
EntityManager entityManager = entityManagerFactory.createEntityManager();
assertNotNull(entityManager);
List<Flight> flights = (List<Flight>) entityManager.createQuery("FROM Flight").getResultList();
assertEquals(2, flights.size());
String departureTimeRequestInput = "2016-05-16T21:00:00.000Z";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Date departureDate = sdf.parse(departureTimeRequestInput);
Timestamp departureTimestamp = new Timestamp(departureDate.getTime());
flights = (List<Flight>) entityManager.createQuery(
"SELECT f FROM Flight f "
+ "WHERE "
+ "f.destinationId = :destinationId "
+ "and "
+ "f.arrivalId = :arrivalId "
+ "and "
+ "f.departureTime <= :departureDate "
+ "and "
+ "f.numberOfPassengers <= :numberOfPassengers")
.setParameter("destinationId", 1L)
.setParameter("arrivalId", 3L)
.setParameter("departureDate", departureTimestamp)
.setParameter("numberOfPassengers", 400L)
.getResultList();
assertEquals(1, flights.size());
log.debug("**H2**SIZE: " + flights.size());
}
}
TestH2DatabaseConfiguration.java
@Configuration
@EnableJpaRepositories("com.mycompany.h2.jpa")
@EnableTransactionManagement
public class TestH2DatabaseConfiguration {
final static Logger log = LoggerFactory.getLogger(TestH2DatabaseConfiguration.class);
@Bean
@Qualifier("dataSource")
public DataSource h2DataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:flight.sql").build();
}
@Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(h2DataSource());
factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
factoryBean.setPackagesToScan("com.mycompany.h2.jpa");
factoryBean.setPersistenceUnitName("flight_table");
Properties ps = new Properties();
ps.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
ps.put("hibernate.show_sql", "true");
ps.put("hibernate.hbm2ddl.auto", "none");
factoryBean.setJpaProperties(ps);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
}
Flight.java
public class Flight implements Serializable {
private static final long serialVersionUID = 2608721697556397731L;
@Id
private Long destinationId;
private Long arrivalId;
private Timestamp departureTime;
private Timestamp arrivalTime;
private Long numberOfPassengers;
...
}
flight.sql
CREATE TABLE flight (
destinationId INTEGER PRIMARY KEY,
arrivalId INTEGER,
departureTime TIMESTAMP,
arrivalTime TIMESTAMP,
numberOfPassengers INTEGER
);
INSERT INTO flight VALUES (1, 3, '2016-05-16 17:30:00.0', '2016-05-18 17:30:00.0', 400);
INSERT INTO flight VALUES (2, 2, '2016-05-17 17:30:00.0', '2016-05-19 17:30:00.0', 200);
关键点:
这里的关键点是将您的用户输入时间传递到 java.sql.Timestamp 对象中,如 FlightTest.java 中所示,例如
String departureTimeRequestInput = "2016-05-16T21:00:00.000Z";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Date departureDate = sdf.parse(departureTimeRequestInput);
Timestamp departureTimestamp = new Timestamp(departureDate.getTime());
和
...
.setParameter("departureDate", departureTimestamp)
...
更新 2: 在下面的事务中插入示例 Flight 对象
EntityManager entityManager = null;
try {
entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(flightObject);
entityManager.flush();
transaction.commit();
return flightObject;
}
finally {
entityManager.close();
}