JPA Criteria Builder - getting an attribute that is a list - java

I'm trying to access an attribute in one of my entity classes: "products" that is a list:
#Entity
#Table(name = "TRANSACTION")
#Getter
#NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Transaction extends BaseTransaction {
...
#OneToMany(mappedBy="transaction)
private List<Product> products;
...
}
#Entity
#Table(name = "PRODUCT")
#Getter
#AllArgsConstructor
#NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Product {
....
#ManyToOne
#PrimaryKeyJoinColumn
#Getter
#NonNull
private Transaction transaction;
....
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "name", column = #Column(name = "seller_name")),
#AttributeOverride(name = "country", column = #Column(name = "seller_country")) })
private NameAndCountry seller;
...
}
#Embeddable
#AllArgsConstructor
#Getter #Setter
#NoArgsConstructor(access = AccessLevel.PRIVATE)
public class NameAndCountry {
private String name;
private String country;
}
Given a string: "myName", and by using JPA criteria builder, I'm trying to retrieve the name of the seller of the transaction, and this is what have when I'm trying to build the predicate:
Join<Object, Object> transactionProductJoin = root.join("products");
Predicate predicate_ = criteriaBuilder.equal(transactionProductJoin.get("products").get("seller").get("name"), "myName");
However I'm facing an error which says:
Unable to locate Attribute with the the given name [products] on this ManagedType [work.my.domain.models.BaseTransaction]
Why is JPA criteria builder trying to retrieve the "products" attribute from the parent class of Transaction? What should be the correct way to construct the predicate?

Following is the example where we map Parent and Child entity classes using JPA Annotations.
#Entity
#Table(name = "Parent")
#Inheritance(strategy = InheritanceType.JOINED)
public class Parent {
// Getter and Setter methods
}
#Inheritance – Defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the entity class that is the root of the entity class hierarchy.
#InheritanceType – Defines inheritance strategy options.
Single table per class hierarchy strategy: a single table hosts all the instances of a class hierarchy
Joined subclass strategy: one table per class and subclass is present and each table persist the properties specific to a given subclass. The state of the entity is then stored in its corresponding class table and all its superclasses
Table per class strategy: one table per concrete class and subclass is present and each table persist the properties of the class and its superclasses. The state of the entity is then stored entirely in the dedicated table for its class.
#Entity
#Table(name="Child")
public class Child extends Parent {
//Getter and Setter methods,
}
#Inheritance(strategy = InheritanceType.JOINED)
Should be added to the parent entity. (Depending on the InheritanceType required for your scenario.)
Check these links for reference:
Chapter 10. Inheritance mapping
5.1.6. Inheritance strategy

The issue is solved, the problem was in the construction of the predicate:
Wrong:
Predicate predicate_ = criteriaBuilder.equal(transactionProductJoin.get("products").get("seller").get("name"), "myName");
Correct:
Predicate predicate_ = criteriaBuilder.equal(transactionProductJoin.get("seller").get("name"), "myName");

Related

Fail to map by MappedSuperclass's attribute

Entities:
#Entity
#Table(name = "ITEM")
#Inheritance(strategy = InheritanceType.JOINED)
public class Item extends Base {
#OneToOne(mappedBy = "item")
protected Doc doc;
}
#MappedSuperclass
public abstract class Doc extends BaseDoc {
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "itemId")
private Item item;
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class BaseDoc extends Base {}
Tables:
BASEDOC
- itemId int8
(other attributes)
ITEM
(other attributes)
BASE
(other attributes)
During runtime it fails with:
Caused by:
org.hibernate.AnnotationException: Unknown mappedBy in: com.ghiton.updater.entity.Item.doc, referenced property unknown: com.ghiton.updater.entity.Doc.item"}}
I think the reason is the MappedSuperclass, since 'item' is stored in the Base table. Is there a practice to solve these type of cases?
I found that "Mapped superclasses can't be targets of entity relationships.", in this case how I can achieve that Doc to be persisted into the BaseDoc table?
At DB level it has all the columns what are needed, so not necessary to have a separate DOC table.
You cant join mappedsuperclass annotated class with entity class. Mappedsuperclases are not an entity
Link
I think you can change your code like this.
#Entity
#Table(name = "ITEM")
#Inheritance(strategy = InheritanceType.JOINED)
public class Item extends Base {
#OneToOne(mappedBy = "item")
protected Doc doc;
}
#Entity
#Table(name = "DOC")
public abstract class Doc extends BaseDoc {
#OneToOne(mappedBy = "doc")
private Item item;
}
#MappedSuperclass
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class BaseDoc extends Base {}

#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) problem with #Id and sequence

I am facing troubles with #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) and autogenerated table Ids.
Here below is my model:
#Getter
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#DiscriminatorColumn(name = "type")
#SuperBuilder
#NoArgsConstructor
public abstract class MenuEntity {
#Id
#EqualsAndHashCode.Include
#GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
//...
}
#Getter
#Entity
#Table(name = "tasting_menu")
#SuperBuilder
#NoArgsConstructor
public class TastingMenuEntity extends MenuEntity {
//...
}
#Getter
#Setter
#Entity
#Table(name = "simple_menu")
#SuperBuilder
#NoArgsConstructor
public class SimpleMenuEntity extends MenuEntity {
//...
}
In development process, I have defined a data.sql scripts which inserts test data into my H2 inmemory database. Those scripts will work fine only if I specify the ID value in the statement, in other case I get NULL not allowed for column "ID". Thus, I have to set the ID in the insert statement (the issue does not appear in other entities with no inheritance strategy and #GeneratedValue(strategy = GenerationType.IDENTITY)).
A new problem comes: when the application tries to insert a SimpleMenuEntity on execution time an exception is thrown: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.SIMPLE_MENU(ID) because the sequence is still value 1 even it already has some test data.
I have some questions so far.
1. Is my model right?
I have to use #Entity instead of #MappedSuperclass in my abstract class because it has #ManyToOne annotation.
ID property is common for all child tables, but I would like that each table has its own id sequence.
2. How should I handle the autogenerated ID for SQL INSERT statements?
I definitive need the test data in my application for development porpouse.

Relationship with a subclass of SINGLE_TABLE inheritance

I translated some hbm configuration to annotated java class. In the hbm some classes were defined with inheritance strategy "SINGLE_TABLE" and some other entity refer to it with many to one relationship as Map.
when I try to lauch the application I get the following error :
Caused by: org.hibernate.AnnotationException: Map key property not found: com.package.MyClass.Id
I searched for some explanation online, but nothing describing at the same time the SINGLE_TABLE inheritance strategy and the OneToMany behavior in this case.
I have the parent class as follows :
#Entity
#Table(name = "parentclass")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "type", length = 10, discriminatorType = DiscriminatorType.INTEGER)
#DiscriminatorValue("100")
public abstract class ParentClass {
#Id
#Column(name = "Id", length = 11)
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
....
}
the child class :
#Entity
#DiscriminatorValue("2")
public abstract class ChildClass {
....
}
the class with the relation :
#Entity
#Table(name = "otherclass")
#PrimaryKeyJoinColumn(name = "IdSys")
public class OtherClass extends OtherParent {
....
#OneToMany
#JoinColumn(name = "IdOther")
#MapKey(name = "Id")
#Where(clause = "type = 2")
private Map<String, ChildClass> childClassMap;
....
}
It worked when it was defined in hbm so I guess it should work with annotation.
I finally find out what was the issue.
In hbm file, the MapKey name refer to the column name. But the annotation refer to the field name.
So instead of
#MapKey(name = "Id")
I must have
#MapKey(name = "id")

JPA query results in No Identifier

I am using JPA query in spring , My subclass extends Baseclass whic contains an Id only and My subclass has all the variavles that is used by the JPA query given below:
Base Class:
#MappedSuperclass
#Table(name = "partcost")
#NoArgsConstructor
#AllArgsConstructor
#Data
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Pg6p0012_01PartCostBaseQueryModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
String part_no;
}
Subclass :
#Entity
#Table(name = "partcost")
#NoArgsConstructor
#AllArgsConstructor
#Data
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Pg6p0012_01PartCost1QueryModel extends Pg6p0012_01PartCostBaseQueryModel implements Serializable {
private static final long serialVersionUID = 1L;
private String stock_take_cost ;
private String cost_type ;
}
when I am hiting below JPA Query :
#Repository
#Transactional
public interface Pg6p0012_01PartcostRepository extends JpaRepository<Pg6p0012_01PartCostBaseQueryModel, String> {
#Query(value = "SELECT stock_take_cost,cost_type FROM partcost where part_no = :p_part_no", nativeQuery = true)
public List<Pg6p0012_01PartCost1QueryModel>getPartcost1Result(#Param("p_part_no") String p_part_no);
}
its throwing Error: No such column name
which is clear because query is returning only one column but Model has two columns .
How to tackle this ? please suggest.
You make part_no transient . It means that it is not persisted in the database.Therefore you are getting no such column name error. Remove #Transient from the base class which is above the part_no.
And also annotate your base class with
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
Hibernate supports the three basic inheritance mapping strategies:
table per class hierarchy
table per subclass
table per concrete class

Entity inheritance "Attempt to add id property private ...but already have property private"

I got this error:
org.springframework.data.mapping.model.MappingException: Attempt to
add id property private java.lang.String
com.example.estrans.domain.entities.bookshop.Entity.id but already
have property private java.lang.String
com.example.estrans.domain.entities.bookshop.Book.bookId registered as
id. Check your mapping configuration!
When trying to use spring-data the Book entity that inherits form Entity. The Entity tries to cover all of the common functionalities from all potential specific entities.
Entity
#Getter
public class Entity {
#Id
private String id;
public IndexQuery getIndexQuery(){
return new IndexQueryBuilder().withId(this.getId()).withObject(this).build();
}
}
Book
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Document(indexName = "bookshop", type = "book", shards = 1, replicas = 0, refreshInterval = "-1")
public class Book extends Entity {
#Id
private String bookId;
#Field(type = FieldType.String, store = true)
private String title;
}
How can I handle the inheritance while persiting only the concrete Book entity not the general Entity?
EDIT
Take a look at the discusion with #builder inheritance support https://github.com/rzwitserloot/lombok/issues/853

Categories

Resources