早上好, 我正在开发一个跟踪业务指标的应用程序。数据库不常见,导致复杂的查询(在我的级别)和复杂的映射。能否请你帮我看看下面的堆栈跟踪:
Caused by: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to fr.alteca.outilindicateurs.entityRedmine.Issues
at fr.alteca.outilindicateurs.controller.IssuesRESTController.init(IssuesRESTController.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:365)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:310)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
... 44 more
数据库查询(MySQL),按预期工作:
SELECT issues.id,
max(CASE WHEN custom_fields.name='Date de résolution'
THEN custom_values.value
ELSE '-'
END) AS date_resolution ,
max(CASE WHEN custom_fields.name='Date d\'ouverture'
THEN custom_values.value
ELSE '-'
END ) AS date_ouverture
FROM redmine_tma_ibp.issues
join custom_values
on issues.id = custom_values.customized_id
join custom_fields
on custom_values.custom_field_id = custom_fields.id
join enumerations
on enumerations.id=issues.priority_id
where (enumerations.type="IssuePriority" and (enumerations.position=1 or enumerations.position=2))
and (status_id=3 or status_id=5)
and (custom_fields.name = "Date d'ouverture" or custom_fields.name="Date de résolution")
and str_to_date(custom_values.value, '%d/%m/%Y %H:%i') > date('2016-01-01')
group by issues.id
此请求的HQL转换(待检出):
public static String GET_RECORDS_FOR_M1 =
"Select i, max(case when cf.name=:date_denom then cv.value else null end) as date_ouverture FROM Issues i, CustomValues cv, CustomFields cf, Enumerations e "
+ "join fetch i.values "
+ "where i.id=cv.issue "
+ "and cv.customFields=cf.id "
+ "and e.id=i.priority "
+ "and (e.type=:priority and (e.position=:position1 or e.position=:position2)) "
+ "and (i.issueStatus.id=:status1 or i.issueStatus.id=:status2) "
+ "and cf.name = :date_denom "
+ "and str_to_date(cv.value, :date_format) > date(:date_ouverture)"
+ "and i.projects.name=:pole "
//+ "and :value member of i.values "
+ "group by i.id";
我的RESTConstroller:
@RestController
@RequestMapping("/issues")
public class IssuesRESTController extends GenericRestController<Issues> {
private List<Issues> listeM1;
private List<Issues> trashBin;
@Autowired
IssuesRepository issuesRepository;
@Autowired
DataM1Repository dataM1Repository;
@Autowired
AuteurRepository auteurRepository;
@Autowired
PoleRepository poleRepository;
@Autowired
public IssuesRESTController(IssuesRepository repository, DataM1Repository dataM1Repository, AuteurRepository auteurRepository, PoleRepository poleRepository) {
super(repository);
}
@PostConstruct
public void init() {
Param.poles=new HashMap<>();
int i=0;
for(String s : issuesRepository.getPolesNames()) {
Param.poles.put(i, s);
i++;
}
listeM1= new ArrayList<>();
trashBin = new ArrayList<>();
listeM1 = issuesRepository.getM1Issues();
System.out.println(listeM1.size()+" Enregistrements récupérés dans la variable listeM1");
/**
* On regarde si les tuples remontés sont déjà présent dans la base,
* si oui, on les enlève de la liste à traiter.
*/
System.out.println(listeM1.get(0).toString());
for(Issues issue : listeM1) {
for(DataM1 d : dataM1Repository.list()) {
if(issue.getId()==d.getId_ticket()) {
System.out.println("Ticket trouvé correspondant au tuple"+issue + "\n suppression du tuple de la liste à traiter");
trashBin.add(issue);
};
}
}
for (Issues issue : trashBin) { // on évite java-util concurrentmodificationexception
listeM1.remove(issue);
}
trashBin.clear();
/**
* On crée les tickets manquants, les poles et les auteurs suivant le besoin
*/
for(Issues issue : listeM1) {
System.out.println("Création dans la table outil des tickets manquants");
DataM1 ticket = new DataM1();
ticket.setId(Integer.SIZE);
ticket.setId_ticket(issue.getId());
System.out.println("*********\n Ticket : "+issue.getId()+"\n**********");
System.out.println("Recherche l'auteur "+ issue.getAuthor().getLastname()+" "+issue.getAuthor().getFirstname()+" dans la base ...");
System.out.println(issue.getValues());
try {
Auteur a = auteurRepository.findbyName(issue.getAuthor().getLastname(), issue.getAuthor().getFirstname());
System.out.println("Auteur trouvé :"+a.getNom() + " "+a.getPrenom());
ticket.setAuteur(a);
}catch(NullPointerException e){
System.out.println("Cet auteur n'est pas en base .. création ...");
ticket.setAuteur(new Auteur(issue.getAuthor().getLastname(), issue.getAuthor().getFirstname()));
}
System.out.println("Recherche du pole "+issue.getProjects().getName()+" dans la base ...");
try {
Pole p = poleRepository.findbyName(issue.getProjects().getName());
System.out.println("Pole trouvé : "+p.getNom_pole());
ticket.setPole(p);
}catch(NullPointerException e) {
System.out.println("Ce pole n'est pas en base... création...");
ticket.setPole(new Pole(issue.getProjects().getName()));
}
System.out.println("Création du ticket...");
dataM1Repository.create(ticket);
System.out.println("Ticket crée");
}
}
@Override
@RequestMapping("/all")
public ResponseEntity<List<Issues>> list(){
List<Issues> list = issuesRepository.getAll();
return new ResponseEntity<List<Issues>> (list, HttpStatus.OK);
}
@RequestMapping("/M1/list")
public ResponseEntity<List<Issues>> listM1(){
List<Issues> list = issuesRepository.getM1Issues();
return new ResponseEntity<List<Issues>> (list, HttpStatus.OK);
}
@RequestMapping("/M1/count")
public ResponseEntity<Long> countM1(){
Long nbIssues = issuesRepository.countM1Issues();
return new ResponseEntity<Long>(nbIssues, HttpStatus.OK);
}
@RequestMapping("/M1/poles") // recherche la liste des poles dans la base
public ResponseEntity<List<String>> getPolesNames(){
List<String> poles = issuesRepository.getPolesNames();
return new ResponseEntity<List<String>>(poles, HttpStatus.OK);
}
@RequestMapping("/M1/pole")
public ResponseEntity<List<Issues>> getPoleByName(@RequestParam(value="pole") int polekey){
List<Issues> poles = issuesRepository.getPoleByName(polekey);
return new ResponseEntity<List<Issues>>(poles, HttpStatus.OK);
}
@RequestMapping("/M1/pole/count")
public ResponseEntity<Long> countPoleByName(@RequestParam(value="pole") int polekey){
Long poles = issuesRepository.CountPoleByName(polekey);
return new ResponseEntity<Long>(poles, HttpStatus.OK);
}
@RequestMapping("/M1/pole/count/all")
public ResponseEntity<HashMap<String, Long>> getAllInformationOnPoles(){
HashMap<String, Long> tabl = new HashMap<>();
int i=0;
for(String s :issuesRepository.getPolesNames()) {
tabl.put(Param.poles.get(i), issuesRepository.CountPoleByName(i));
i++;
}
return new ResponseEntity<HashMap<String, Long>>(tabl, HttpStatus.OK);
}
@RequestMapping("/M1/pole/count/red")
public ResponseEntity<HashMap<String, Long>> getAllRedInformationOnPoles(){
HashMap<String, Long> tabl = new HashMap<>();
int i=0;
for(String s :issuesRepository.getPolesNames()) {
tabl.put(Param.poles.get(i), issuesRepository.CountRedPoleByName(i));
i++;
}
return new ResponseEntity<HashMap<String, Long>>(tabl, HttpStatus.OK);
}
@RequestMapping("/test/issue")
public ResponseEntity<Issues> listIssueFields(@RequestParam(value="issue") int id_issue){
Issues list = issuesRepository.getIssueById(id_issue);
return new ResponseEntity<Issues>(list, HttpStatus.OK);
}
}
我的实体类:
@Entity
@Table(name = "issues")
public class Issues {
public Issues() {}
/*
* Primary key
*/
@Id
@Column(name = "id", unique = true, nullable = false)
private int id;
/*
* Foreign keys
*/
@JoinColumn(name = "project_id")
@ManyToOne(targetEntity = Projects.class)
private Projects projects;
@JoinColumn(name = "status_id")
@ManyToOne(targetEntity = IssueStatuses.class)
private IssueStatuses issueStatus;
@JoinColumn(name = "author_id", referencedColumnName = "id")
@ManyToOne(targetEntity = Users.class)
private Users author;
@JoinColumn(name = "priority_id")
@ManyToOne(targetEntity = Enumerations.class)
private Enumerations priority;
/*
* Fields
*/
@Column(name = "subject", nullable = false)
private String subject;
@Column(name = "description", nullable = true)
private String description;
@OneToMany(mappedBy = "issue", targetEntity = CustomValues.class, fetch = FetchType.LAZY)
private List<CustomValues> values;
@Transient
private Map<CustomFields, String> mapValeurs;
@Transient
private IssueStatuses status;
//getters & setters
我的存储库:
@Repository
public class IssuesRepository extends GenericCRUDImplRedmine<Issues>{
public IssuesRepository() {
super();
System.out.println(Repositories.BUILD+this.getClass().getSimpleName());
}
@SuppressWarnings("unchecked")
public List<Issues> getAll() {
String sql = Database.GET_ALL_ISSUES;
return super.getCurrentSession().createQuery(sql).getResultList();
}
@SuppressWarnings("unchecked")
public List<Issues> getM1Issues(){
String sql = Database.GET_RECORDS_FOR_M1;
System.out.println("requete : "+sql);
List<Issues> M1Issues =(List<Issues>) super.getCurrentSession().createQuery(sql)
.setParameter("priority", Param.priority)
.setParameter("position1", Param.position[0])
.setParameter("position2", Param.position[1])
.setParameter("status1", Param.status[0])
.setParameter("status2", Param.status[1])
.setParameter("date_ouverture", Date.date_ouverture)
.setParameter("date_resolution", Date.date_resolution)
.setParameter("date_format", Date.FORMAT_DATE_M1)
.setParameter("date_denom", Date.date_denom)
.setParameter("pole", Param.poles.get(0)) // define the key
//.setParameter("value", 1)
.getResultList();
return M1Issues;
}
我的通用CRUD实施:
@Transactional("hibernateTransactionManagerRedmine")
公共类GenericCRUDImplRedmine实现了GenericCRUD {
private final Class<T> persistentClass;
@Autowired
@Qualifier("sessionFactoryRedmine")
private SessionFactory sessionFactory;
protected Session getCurrentSession() {
boolean testSessionFactory = sessionFactory!=null;
System.out.println("Avons nous une sessionFactory? "+testSessionFactory);
Session session = sessionFactory.getCurrentSession();
boolean testSession = session!=null;
System.out.println("Avons nous une session? "+testSession);
return session;
}
@SuppressWarnings("unchecked")
public GenericCRUDImplRedmine() {
this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
@Override
public void create(final T entity) {
this.getCurrentSession().save(entity);
}
@Override
public void update(T t) {
this.getCurrentSession().update(t);
}
@Override
public void refresh(T t) {
// TODO Auto-generated method stub
}
@Override
public void delete(Integer id) {
this.getCurrentSession().delete(this.find(id));
}
@Override
public T find(Integer id) {
// TODO Auto-generated method stub
return (T) this.getCurrentSession().get(persistentClass, id);
}
@SuppressWarnings("unchecked")
@Override
public List<T> list() {
// TODO Auto-generated method stub
return this.getCurrentSession().createQuery("from "+persistentClass).getResultList();
}
DB配置:
@Configuration
@EnableTransactionManagement
public class DBConfig {
/**
* Créer la fabrique de session à la base de données et associe les entités
* utilisables dans la session.
*
* @return SessionFactory
*/
@Bean(name="sessionFactoryOutil")
public SessionFactory sessionFactoryOutil() {
System.out.println("Construction de l'objet SessionFactory pour l'outil...");
return new LocalSessionFactoryBuilder(getDataSourceOutil())
.scanPackages("fr.alteca.outilindicateurs.entityOutil")
.buildSessionFactory();
}
@Bean(name="sessionFactoryRedmine")
public SessionFactory sessionFactoryRedmine() {
System.out.println("Construction de l'objet SessionFactory pour Redmine...");
return new LocalSessionFactoryBuilder(getDataSourceRedmine())
.scanPackages("fr.alteca.outilindicateurs.entityRedmine")
.buildSessionFactory();
}
/**
* Configure l'accès à la base de données.
* La configuration à la base de données se trouve dans le fichier de contexte (WebContent / META-INF / context.xml)
*
* @return DataSource
*/
@Bean(name="dataSourceOutil")
public DataSource getDataSourceOutil() {
try {
InitialContext initialContext = new InitialContext();
DataSource datasource = (DataSource) initialContext.lookup( "java:/comp/env/jdbc/postgres" );
System.out.println("Base de donnée outil Localisée");
return datasource;
} catch (NamingException e) {
e.printStackTrace();
return null;
}
}
@Bean(name="dataSourceRedmine")
public DataSource getDataSourceRedmine() {
try {
InitialContext initialContext = new InitialContext();
DataSource datasource = (DataSource) initialContext.lookup( "java:/comp/env/jdbc/redmine" );
System.out.println("Base de donnée Redmine Localisée");
return datasource;
} catch (NamingException e) {
e.printStackTrace();
return null;
}
}
/**
* Défini Hibernate pour la transaction à la base de données.
*
* @return
*/
@Bean(name="hibernateTransactionManagerOutil")
public HibernateTransactionManager hibernateTransactionManagerOutil() {
System.out.println("initialisation du transaction manager pour l'outil !");
return new HibernateTransactionManager(this.sessionFactoryOutil());
}
@Bean(name="hibernateTransactionManagerRedmine")
public HibernateTransactionManager hibernateTransactionManagerRedmine() {
System.out.println("initialisation du transaction manager pour Redmine !");
return new HibernateTransactionManager(this.sessionFactoryRedmine());
}
答案 0 :(得分:0)
好的,我看到,我无法在同一个查询中返回多个对象,实际上并不像你说的那样是JPA问题。我设法通过它将查询划分为3个查询(我认为是肮脏的方式),它可以工作,但我仍然会寻找一种更清晰的方式来实现这一目标