简体   繁体   中英

spring boot jpa: return custom object from jpa query not related to table schema

Here is my configuration: Java: 1.8 Spring Boot :: v2.3.1.RELEASE

I have following models/classes:

Books: The Book class is as below. Please note this is not an entity related to table in DB, or can treat it as a data fetched from multiple tables with only required attributes. In short I won't have a table schema for following object.

package com.myservice.model;

public class Book {
    private long bookId;
    private String bookName;
    private String bookType;
    private String author;


    public Book(long bookId, String bookName, String bookType, String author) {
        this.bookId = bookId;
        this.bookName = bookName;
        this.bookType = bookType;
        this.author = author;
    }

    public long getBookId() {
        return bookId;
    }

    public void setBookId(long bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookType() {
        return bookType;
    }

    public void setBookType(String bookType) {
        this.bookType = bookType;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

}

Similar to the above, I have another class,

package com.myservice.model;

public class Business {

    private String businessName;
    private String businessType;
    private String owner;


    public Book(String businessName, String businessType, String owner) {
        this.businessName = businessName;
        this.bookType = bookType;
        this.owner = owner;
    }


    public String getBusinessName() {
        return businessName;
    }

    public void setBusinessName(String businessName) {
        this.businessName = businessName;
    }

    public String getBusinessType() {
        return businessType;
    }

    public void setBusinessType(String businessType) {
        this.businessType = businessType;
    }

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        this.owner = owner;
    }

}

I need the output as following object

import java.util.List;

public class Configuration {

    private List<Book> books;
    private List<Business> businesses;
    private List<String> authors;
    private List<String> owners;

    // Constructor and getters/setters omitted for brevity

}

So, I tried to have a repository

import com.myservice.model.Configuration;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ConfigurationRepository extends JpaRepository<Configuration, Long>, ConfigurationRepositoryCustom {

}

Custom interface

import com.myservice.model.Configuration;

public interface ConfigurationRepositoryCustom {

    Configuration getConfigData();
}

Implementation:

@Repository
@Transactional(readOnly = true)
public class ConfigurationRepositoryImpl implements ConfigurationRepositoryCustom {

    @PersistenceContext
    EntityManager entityManager;

    private List<Book> getBooks() {
        Query query = entityManager.createNativeQuery(
                "SELECT book_id, book, bookType, author FROM TABLE1 JOIN TABLE2 <Other criterias>"
                , Book.class
        );
        return query.getResultList();
    }

    private List<Business> getBusinesses() {
        List<Business> businesses = new ArrayList<>();
        businesses.add(new Business("ABC", "Constructions", "ABC PQR" ));
        businesses.add(new Business("XYZ", "Constructions", "PQR CCC" ));
        businesses.add(new Business("PQR", "Education", "ABC PQR" ));
        return businesses;
    }


    @Override
    public Configuration getConfigData() {
        List<Book> books = getBooks();
        List<Business> businesses = getBusinesses();
        
        List<String> authors = books.stream().map(Book::getAuthor).collect(Collectors.toList());
        List<String> owners = businesses.stream().map(Book::getOwner).collect(Collectors.toList());
        
        Configuration config = new Configuration(
                books,
                businesses,
                authors,
                owners
        );

        return config;
    }
}

Basically, if you see Configuration object is not in DB.

When I start the app, it first threw this error:

Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.myservice.model.Configuration
    at org.hibernate.metamodel.internal.MetamodelImpl.managedType(MetamodelImpl.java:582) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    at org.hibernate.metamodel.internal.MetamodelImpl.managedType(MetamodelImpl.java:85) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:75) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:66) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:229) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:179) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:162) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:72) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]

For the above, I added @Entity? annotation to my Configuration class

Next, it threw the error :

Caused by: org.hibernate.AnnotationException: No identifier specified for entity: com.myservice.model.Configuration
    at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:266) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:211) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:781) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    

Now, my Configuration is not a table in DB, still I added the attribute "id"

@Id
@GeneratedValue
private long id;

Next, I get this error:

Caused by: org.hibernate.MappingException: Could not determine type for: java.util.List, at table: configuration, for columns: [org.hibernate.mapping.Column(books)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:499) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:466) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    at org.hibernate.mapping.Property.isValid(Property.java:227) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]

There is of course no such table in my DB.

So, basically I am looking for a way to create a custom (Configuration here) object based on other objects (few from DB, few from other calls, etc) and this custom object is not in DB. So how to achieve the same?

You don't need this interface

public interface ConfigurationRepository extends JpaRepository<Configuration, Long>, ConfigurationRepositoryCustom {

}

Instead, use ConfigurationRepositoryCustom directly in your code, also you can use the name ConfigurationRepository (No need to suffix with custom).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM