i have this classes
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "processType")
public abstract class BaseProcess extends BaseModel {
}
#Entity
public class MainProcess extends BaseProcess {
}
#Entity
public class SubProcess extends BaseProcess {
}
#Entity
public class Tank {
#Column
private Long id;
}
#Entity
public class TagAddress {
#Id
private Long id
#ManyToOne
private BaseProcess process;
#ManyToOne
private Tank tank;
}
public interface TagAddressDao extends JpaRepository<TagAddress, Long> {
#Query("FROM TagAddress WHERE tank.id = ?1 AND process.processType = 'MainProcess' ")
List<TagAddress> findMainProcessByTankId(Long tankId);
#Query("FROM TagAddress WHERE tank.id = ?1 AND process.processType = 'SubProcess' ")
List<TagAddress> findSubProcessByTankId(Long tankId);
}
i got this error
org.hibernate.QueryException: could not resolve property: processType ...
How do i filter by concrete class MainProcess and SubProcess in TagAddressDao?
something like i can do "instanceof MainProcess" or "instanceof SubProcess"
Related
I'm playing around with generics and Spring Data repository. I created a simple project with almost zero configuration, entities are in subpackage of main class.
Entity
#Data
#ToString(callSuper = true)
#Entity
public class Person extends GenericEntity {
private String name;
}
#Data
#MappedSuperclass
public class GenericEntity {
#Id
#GeneratedValue
private Integer id;
#CreationTimestamp
#Column(name = "TMS_INSERIMENTO")
private LocalDateTime tmsInserimento;
#UpdateTimestamp
#Column(name = "TMS_AGGIORNAMENTO")
private LocalDateTime tmsAggiornamento;
}
Repository
public interface GenericRepository<T extends GenericEntity> extends JpaRepository<T, Integer> {
}
Service
public List<Person> findAllPeople() {
return genericRepository.findAll();
}
Call to findAll() throws the following exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Not an entity: class com.example.demot.entity.GenericEntity; nested exception is java.lang.IllegalArgumentException: Not an entity: class com.example.demot.entity.GenericEntity
Try with the following
#Data
#MappedSuperclass
public class GenericEntity <T extends GenericEntity> {
...
}
And then
#Data
#ToString(callSuper = true)
#Entity
public class Person extends GenericEntity<Person> {
...
}
And then you need the generic repository which should return generic entities not specific persons
public interface GenericRepository extends JpaRepository<GenericEntity, Integer> {
}
which can be called in service as
public List<GenericEntity> findAllGenericEntities() {
return genericRepository.findAll();
}
And then you can also have a person repository
public interface PersonRepository extends JpaRepository<Person, Integer> {
}
which can be called in service as
public List<Person> findAllPersons() {
return personRepository.findAll();
}
I have 3 entities, all mapped to the same base table, like this:
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(
discriminatorType = DiscriminatorType.STRING,
name = "disc_type"
)
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "unique_id", nullable = false)
private long id;
}
#DiscriminatorValue(value = DiscType.Values.ONE)
public class Child1 extends Parent {
}
#DiscriminatorValue(value = DiscType.Values.TWO)
public class Child2 extends Parent {
}
What doesn't work for me is when I try get by id for the child entities - I would have expected the following code to work (and adding the matching disc_type filter), but unfortunately - this returns null:
return sessionFactory.getCurrentSession().get(Child1.class, id);
While this returns (as expected) the Parent object:
return sessionFactory.getCurrentSession().get(Parent.class, id);
I need to return a Child1 entity, and converting the Parent to Child1 seems like a pretty bad solution. Ideas on how to get over this?
I have tried following code and it works (hope this helps):
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(
discriminatorType = DiscriminatorType.STRING,
name = "disc_type"
)
#Entity
#Table(name = "parent")
#Data
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "unique_id", nullable = false)
private long id;
}
#Entity
#DiscriminatorValue(value = "ONE")
public class Child1 extends Parent {
}
#Entity
#DiscriminatorValue(value = "TWO")
public class Child2 extends Parent {
}
public interface EntityRepository extends CrudRepository<Parent, Long> {
}
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Component
#AllArgsConstructor
public class ApplicationRunner implements CommandLineRunner {
private final EntityRepository repository;
#Override
public void run(String... args) throws Exception {
repository.save(new Child1());
repository.save(new Child2());
Parent one = repository.findById(1L).get();
System.out.println(one);
Parent two = repository.findById(2L).get();
System.out.println(two);
}
}
}
Output:
Hibernate: insert into parent (unique_id, disc_type) values (null, 'ONE')
Hibernate: insert into parent (unique_id, disc_type) values (null, 'TWO')
Hibernate: select parent0_.unique_id as unique_i2_2_0_, parent0_.disc_type as disc_typ1_2_0_ from parent parent0_ where parent0_.unique_id=?
Parent(id=1)
Hibernate: select parent0_.unique_id as unique_i2_2_0_, parent0_.disc_type as disc_typ1_2_0_ from parent parent0_ where parent0_.unique_id=?
Parent(id=2)
Update:
public interface Child1Repository extends CrudRepository<Child1, Long> {
}
#Component
#AllArgsConstructor
public class ApplicationRunner implements CommandLineRunner {
private final EntityRepository repository;
private final Child1Repository child1Repository;
#Override
public void run(String... args) throws Exception {
repository.save(new Child1());
repository.save(new Child2());
Parent one = repository.findById(1L).get();
System.out.println(one);
Parent two = repository.findById(2L).get();
System.out.println(two);
Child1 child1 = child1Repository.findById(1L).get();
System.out.println(child1);
}
}
I inherited some pretty awful code that I am looking to refactor to make more reusable. There is a set of reporting tables which are primarily composed of 3 columns: id, report_type_fk, and report_description. I would like to merge all the reporting tables into one for ease of use.
I am refactoring the code and think that it would be better to break our current entities up so that Report is an abstract class with type implementations. For example a DmvReport extends Report, CreditScoreReport extends Report, etc.
The problem I am running into is that there would only be 1 report table that all entities would need to save to. Is there a way to make all concrete implementations of the abstract Report object save into the same table?
Here's an example of the bad code I inherited
Report class
#Entity
#Table(name = "report")
public class Report<E extends Exception> {
private long id;
private ReportType type;
private String description;
...
...
}
CreditReport class
#Entity
#Table(name = "credit_report")
public class CreditScore Report<E extends Exception> extends Report<E> {
private long id;
private ReportType type;
private String description;
...
...
}
I am looking to turn it into:
#MappedSuperclass
#Table(name = "report")
public abstract class Report<E extends Exception> {
#Id #Column(name="id")
private long id;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "report_type_id")
private ReportType type;
#column(name="description")
private String description;
...
...
}
#Entity
#Table(name = "report")
public class CreditScoreReport<E extends Exception> extends Report<E> {
public void doCreditScoreStuff(){
...
}
}
#Entity
#Table(name = "report")
public class DmvReport<E extends Exception> extends Report<E> {
public void doDmvStuff(){
...
}
}
I think you should use #Inheritance instead of #MappedSuperClass. Your code would look like this:
#Entity
#Table(name = "report")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "report_type_id", discriminatorType = DiscriminatorType.INTEGER)
public abstract class Report<E extends Exception> {
#Id #Column(name="id")
private long id;
#column(name="description")
private String description;
...
...
}
#Entity(name = "CreditScoreReport")
#DiscriminatorValue("1") // the id corresponding to the credit score report
public class CreditScoreReport<E extends Exception> extends Report<E> {
#Column(name = "specific_credit_score_report_1)
private Integer specificCreditScoreReport1;
public void doCreditScoreStuff(){
...
}
}
#Entity(name = "DmvReport")
#DiscriminatorValue("2") // the id corresponding to the DMV report
public class DmvReport<E extends Exception> extends Report<E> {
#Column(name = "specific_dmv_score_report_1)
private Integer specificDmvScoreReport1;
public void doDmvStuff(){
...
}
}
This strategy allows you to store credit score report and DMV report data in one table (report), but instanciate the proper entity according to the report_value_id field. You don't have to define the report_value_id in your parameters because it was already used to create the required entity.
Is this what you're looking for?
I have four classes which should put in one db table.
First class represents basic information.
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "TYPE")
#Entity
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class A {
#Id
private String id;
private LocalDateTime date;
private String someString;
}
The second class extends class a and has some extra properties.
#Inheritance
#MappedSuperclass
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class B extends A {
private String extraProperty;
}
Finally there are two parallel classes with concrete type information.
#Entity
#DiscriminatorValue(value = "C1")
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class C1 extends B {
private String property1;
private String property2;
}
#Entity
#DiscriminatorValue(value = "C2")
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class C2 extends B {
private String propertyX;
private String propertyY;
}
The ReST repository looks like this:
#RepositoryRestResource(
path = "items",
collectionResourceRel = "items"
)
public interface ItemRepository extends PagingAndSortingRepository<A, String> { }
Now I have written a test where the expected format is tested.
#Test
public void shouldReturnItemlistWithCorrectDataStructure() throws Exception {
mockMvc.perform(get("/Items"))
.andExpect(jsonPath("$._embedded.items").isArray())
.andExpect(jsonPath("$._embedded.items", hasSize(2)))
.andExpect(jsonPath("$._embedded.items[0].id").value("1234567"))
...
}
I expected one array (items[]) in the result json but there are actually two different arrays c1[] and c2[].
Any ideas what I'm doing wrong?
I have a problem with a QueryDSL query. Classes:
#Entity
#Table(name="project")
#Cacheable(true)
#Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Project extends DomainObject implements Comparable<Project>, IconizedComponent, Commentable {
#ManyToMany(targetEntity=Student.class)
#JoinTable(name="project_student")
#Sort(type=SortType.NATURAL) //Required by hibernate
#QueryInit({"user"})
private SortedSet<Student> projectParticipants = new TreeSet<Student>();
private Project(){}
//attributes, get+set methods etc
}
#Entity
#Cacheable(true)
#Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) //Hibernate specific
public class Student extends Role {
public Student(){}
//attributes, get+set methods etc
}
#Entity
#DiscriminatorColumn(name = "rolename", discriminatorType = DiscriminatorType.STRING, length = 8)
#Table(name="role", uniqueConstraints={#UniqueConstraint(columnNames={"user_id","rolename"}, name = "role_is_unique")})
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Role extends LazyDeletableDomainObject implements Comparable<Role> {
#ManyToOne(optional=false)
protected User user;
public Role(){}
//attributes, get+set methods etc
}
#Entity
#Table(name="user")
#Cacheable(true)
#Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) //Hibernate specific
public class User extends LazyDeletableDomainObject implements Comparable<User>, IconizedComponent {
private String firstName;
private String lastName;
public User(){}
//attributes, get+set methods etc
}
Query:
private BooleanExpression authorsNameContains(String searchTerm){
QUser user = new QUser("user");
user.firstName.containsIgnoreCase(searchTerm).or(user.lastName.contains(searchTerm));
QStudent student = new QStudent("student");
student.user.eq(user);
return QProject.project.projectParticipants.contains(student);
//java.lang.IllegalArgumentException: Undeclared path 'student'. Add this path as a source to the query to be able to reference it.
}
I have also tried annotating the projectParticipants set in Project with
#QueryInit("*.*")
But that gives the same exception. Any hints?
#Timo Westkämper
#siebZ0r
Thanks for your attention. Sorry for the delayed reply and incorrectly phrased question. Actually what I wanted to do was to write a working BooleanExpression.
In combination with the annotations already made, this was what I was after:
private BooleanExpression authorsFirstNameContains(String searchTerm){
return QProject.project.projectParticipants.any().user.firstName.containsIgnoreCase(searchTerm);
}
I got this right with the help of a colleague.