I have two tables defined as follows:
Action
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "\"action_recipient_log\"")
#Getter
#Setter
public class ActionRecipientLog {
// generated id
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonManagedReference(value = "action_id") #JsonInclude(JsonInclude.Include.NON_NULL)
private Long action_id;
#JsonManagedReference(value = "recipient_id") #JsonInclude(JsonInclude.Include.NON_NULL)
private String recipient_id;
#JsonManagedReference(value = "is_read") #JsonInclude(JsonInclude.Include.NON_NULL)
private boolean is_read;
}
ActionRecipientLog
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "\"action_recipient_log\"")
#Getter
#Setter
public class ActionRecipientLog {
// generated id
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonManagedReference(value = "action_id") #JsonInclude(JsonInclude.Include.NON_NULL)
private Long action_id;
#JsonManagedReference(value = "recipient_id") #JsonInclude(JsonInclude.Include.NON_NULL)
private String recipient_id;
#JsonManagedReference(value = "is_read") #JsonInclude(JsonInclude.Include.NON_NULL)
private boolean is_read;
}
Inside ActionRepository, I'm trying to fetch the fields from both Action table and ActionRepository:
#Query("SELECT a, b.is_read FROM Action a LEFT JOIN FETCH ActionRecipientLog b " +
"ON b.recipient_id = a.user.id WHERE a.id = b.action_id ORDER BY a.lastModifiedDate DESC")
List<Action> findUnreadActionByUserId(#Param("userId") String userId, Pageable pageable);
But I'm not sure how to do that because current implementation only returns data from Action (because return type is List<Action>). Can anyone help me figure out how I can return data from both Action table and ActionRecipientLog (b.is_read column)?
Related
I have a spring boot project with many entities and relationships. I am able to store the records successfully and retrieve it using POST and GET methods. Now I have a requirement to filter the records based on a few parameters which are optional to be passed in API and I am using the JPA specification to manage the queries but I am getting the duplicate records in the response.
Project
#Getter
#Setter
#ToString
#Entity
#Table(name = "Project")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "`Id`")
#Schema(example = "")
private Long id;
#Column(name = "`Name`")
#Schema(example = "")
private String name;
#OneToMany(mappedBy = "project", cascade = CascadeType.ALL)
private List<ProjectCode> projectCodes;
}
ProjectCode
#Getter
#Setter
#ToString
#Entity
#Table(name = "ProjectCode")
public class ProjectCode {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "`Id`")
#Schema(example = "")
private Long id;
#Column(name = "`Code`")
#Schema(example = "")
private String code;
...
#ManyToOne
#JsonIgnore
private Project project;
#OneToMany(mappedBy = "projectCode", cascade = CascadeType.ALL)
private List<ProjectAllocation> projectAllocations;
}
ProjectSpecification
public class ProjectSpecification implements Specification<Project> {
private final ProjectFilters projectFilters;
/**
* ProjectSpecification constructor. *
*/
public ProjectSpecification(ProjectFilters projectFilters) {
this.projectFilters = projectFilters;
}
/**
* Create predicate. *
*/
public Predicate toPredicate(Root<Project> root, CriteriaQuery<?> cq,
CriteriaBuilder cb) {
log.info("Request to filter project with: {}", projectFilters);
Predicate predicate = cb.conjunction();
Join<Project, ProjectCode> projectCodeJoin = root.join("projectCodes");
// If I remove this line I do not get duplicated records
Join<ProjectCode, ProjectAllocation> projectAllocationJoin =
projectCodeJoin.join("projectAllocations");
// Join<ProjectAllocation, Employee> projectAllocationEmployeeJoin =
// projectAllocationJoin.join("employee");
return predicate;
}
}
#Entity
#Data
#NoArgsConstructor
public class Offer {
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
}
#Data
#EqualsAndHashCode
#Entity
#NoArgsConstructor
public class User {
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL,fetch=FetchType.LAZY)
private Set<Offer> offers = new HashSet<Offer>();
}
Please help if the mapping is correct in table User and Offer .user_id column have null values ....:(
I'm not sure if these are only parts of the entities but in order for the entity to have an id, you need to provide it with one and annotate the relevant field as #Id.
I also use #GeneratedValue(strategy = GenerationType.IDENTITY) so each table will get it's own id (generated by Hibernate, you don't provide the id when you save a new entity and not a global id, otherwise let's say you add an Offer, you get id with value x, then add new User you get id with value x+1 and so on...
#Entity
#Data
#NoArgsConstructor
public class Offer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
}
#Data
#EqualsAndHashCode
#Entity
#NoArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL,fetch=FetchType.LAZY)
private Set<Offer> offers = new HashSet<Offer>();
}`
I have 2 tables, products, and product_photos. I need to insert data to both tables in one transaction.
#Entity
#Table(name = "products", schema = "my_schema")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
...
//getter + setter + constructor
}
#Entity
#Table(name = "product_photos", schema = "my_schema")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class ProductPhoto {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "product_id")
private Integer productId;
...
}
}
Is there a way to retrieve the id of the Product before writing the entity to DB in order to put it on ProductPhoto (column product_id)?
I have a problem with retrieving an entity using the child's entity as a search parameter. Entities are related to many to one relationship as unidirectional and each object is fetched as FetchType.LAZY.
When I looking for an entity by a child entity, the result is null. But when I set to fetch as Eager it is correct.
My Entities:
#NoArgsConstructor
#Getter
#Entity
#Table(name = "partner")
public class PartnerEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String login;
public PartnerEntity(String login) {
this.login = login;
}
}
#NoArgsConstructor
#Getter
#Entity
#Table(name = "point")
public class PointEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "partner_Id")
private PartnerEntity partnerEntity;
public PointEntity(PartnerEntity partnerEntity) {
this.partnerEntity = partnerEntity;
}
}
#NoArgsConstructor
#Getter
#Entity
#Table(name = "orer")
public class OrdEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PAYMENT_POINT_ID")
private PointEntity pointEntity;
public OrdEntity(PointEntity pointEntity) {
this.pointEntity = pointEntity;
}
}
#NoArgsConstructor
#ToString
#Getter
#Entity
#Table(name = "BL")
public class BLEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PARTNER_LOGIN", referencedColumnName = "login")
private PartnerEntity partnerEntity;
private String number;
public BLEntity(PartnerEntity partnerEntity, String number) {
this.partnerEntity = partnerEntity;
this.number = number;
}
}
And I looking for BLEntity using OrdEntity child:
final OrdEntity byId = ordRepo.findById(id);
final PartnerEntity partnerEntity = order.getPointEntity().getPartnerEntity();
final BLEntity blEntityResult= blRepo.findOneByNumberAndPartner(number, partnerEntity);
The object partnerEntity is not null, it is correct object.
I got blEntityResult as null but if I change in PointEntity fetch to FetchType.EAGER, blEntityResult is not null(correct).
My custom query in repository below:
public interface BLRepo extends JpaRepository<BLEntity, Long> {
#Query("select b from BLEntity b where b.number = :number and b.partnerEntity= :partner")
BLEntity findOneByNumberAndPartner(#Param("number") String number, #Param("partner") PartnerEntity partner);
}
why does happens, if the partner object being downloaded is not null and is correct?
I think you should add the mapping in both sides,
because of default fetch type for #AllToMany=Lazy and #ManyToAll = Eager.
just add below code inside PartnerEntity.
#OneToMany(mappedBy="partnerEntity" , fetch = FetchType.Eager )
List<BLEntity> blEntity = new ArrayList<>();
I change FetchType into Eager in PointEntity:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "partner_Id")
private PartnerEntity partnerEntity;
And everything is ok, but I don't understand why it does not work with PaymentType.Lazy. When I am looking for:
final PartnerEntity partnerEntity = order.getPointEntity().getPartnerEntity();
I get correct entity "PartnerEntity" which has proper login's field (login'field has value "test").
When I turned logged level to 'TRACE' I saw, Hibernate not binding correct login's parameter, it set null instead "test") why? :)
I have these entities:
#Entity
#Table(name = "my_table")
public class MyTable implements Serializable {
#Id
#Column(name = "RECORD_ID")
private Long recordId;
#Column(name = "CNAME")
private String changeName;
#Transient
MyTableTwo tableTwo;
//getters and setters
}
MyTableTwo entity:
#Entity
#Table(name = "my_table_two")
public class MyTableTwo implements Serializable {
#Id
#Column(name = "REC_ID")
private Long recId;
#Column(name = "CNAME")
private String changeName;
#Column(name = "CVAL")
private String changeValue;
//getters and setters
}
I want to get my_table.record_id. 'my_table.cname', 'my_table_two.cval' in a result.
How to write a query on these two entities?
Can we write a join query with first entity and #transient entity field of 2nd entity?
I need to write HQL
You can do a cross join like
select a,b from MyTable a,MyTableTwo b where a.prop1 = b.prop2