Get Max Value with Spring-JPA - spring

I want do query to my table with spring-JPA (I can't use #Query) for get the max register
The query have any conditions:
Initially my query get register where version is "x" and Validated is 1 and the process is a list.
version: "1A"
validated: 1 -> It is always 1.
lista: ["process1","process2"] or with 3,4 process...
myRepo.findByIdVersionCierreAndAndValidatedAndIdProcessIn(version, 1, lista);
But In my database I can be two registers:
1º
version: "1A"
validated: 1
lista: ["process1","process2"]
Exec: 1
2º
version: "1A"
validated: 0
lista: ["process1","process2"]
Exec: 2
I need get the register with max Exec, because in my register 1º, validated is 1, BUT in my register 2, validated is 0 y con my old code, I get the register Exec1 - "myRepo.findByIdVersionCierreAndAndValidatedAndIdProcessIn(version, 1, lista);"
First I saw the post:
Spring CRUD repository: is there findOneByMaxXYZColumn()?
So I modified my code:
myRepo.findFirstfindByIdVersionCierreAndAndValidatedOrderbyIdExecDescAndIdProcessIn(version, 1, lista);
Err:
Caused by: java.lang.IllegalArgumentException: Failed to create query method public abstract java.util.List es.repository.DataValidationRepository.findFirstfindByIdVersionCierreAndAndValidatedOrderbyIdExecDescAndIdProcessIn(java.lang.String,int,java.util.List)! No property orderbyIdExecDesc found for type int! Traversed path: TpValidaAuto.validated.
And
myRepo.findFirstfindByIdVersionCierreAndAndValidatedAndIdProcessInOrderbyIdExecDesc(version, 1, lista);
however I get a error when I run the SpringBoot:
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property inOrderbyIdExecDesc found for type String! Traversed path: TpValidaAuto.idProcess.
EDIT:
#Repository
public interface DataValidationRepository extends CrudRepository<TpValidaAuto, String> {
List<TpValidaAuto> findByIdVersionCierreAndAndValidatedAndIdProcessIn(String version, int validated, List<String> process);
}
Entity:
#Entity
#Table(name = "MyTable")
#GETTER
#SETTER
public class TpValidaAuto {
#Id
#NotNull
#Column(name = "ID")
#JsonProperty("id")
private String id;
#NotNull
#Column(name = "ID_FICHERO")
#JsonProperty("file")
private String idFile;
#NotNull
#Column(name = "ID_EJECUCION")
#JsonProperty("exec")
private int idExec;
#NotNull
#Column(name = "ID_PROCESO")
#JsonProperty("process")
private String idProcess;
#Column(name = "ID_PERIODO")
#JsonProperty("period")
private String idPeriod;
#Column(name = "FC_ULT_DATO")
#JsonProperty("lastdatedata")
private String lastDateData;
#Column(name = "IND_INCLUIR_CIERRE")
#JsonProperty("validated")
#JsonFormat(shape = JsonFormat.Shape.BOOLEAN)
private int validated;
#Column(name = "ID_VERSION_CIERRE")
#JsonProperty("lastdateclose")
private String idVersionCierre;
#NotNull
#Column(name = "IND_DATOS_MODIF")
#JsonProperty("modificated")
private int modificated;
#NotNull
#Column(name = "FC_ALTA")
#JsonProperty("createDate")
private String createDate;
#NotNull
#Column(name = "USR_ALTA")
#JsonProperty("createUser")
private String createUser;
#NotNull
#Column(name = "FC_MODIFICACION")
#JsonProperty("modificationDate")
private String modificationDate;
#NotNull
#Column(name = "USR_MODIFICACION")
#JsonProperty("modificationUser")
private String modificationUser;
#JsonGetter("validated")
public boolean validated() {
boolean result = true;
if (this.validated == 0) {
result = false;
}
return result;
}
#JsonSetter("validated")
public void validated(boolean validated) {
if (validated) {
this.validated = 1;
} else {
this.validated = 0;
}
}

Related

JPA-Spring Repository #OneToOne save/create new child object when the parent object already exists is not working

I got this strange issue when I tried to save a child object of a #OneToOne relationship when the parent object it already exist. Something like that:
Please find below the description of the problem.
I'm using spring-boot with JPA
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
The DB schema diagram looks like
The spring implementation looks like that:
AND THE PROBLEM (the cardnumber, even is not null, I check debugging) it is saved NULL (??!!)
Also please note a trick I used to make the save working. I have to manually check (into DB schema) as not null (uncheck the NN of the cardnumber column on fcrd_clients - child table).
Additionally I'll attach the source code to make easy the code modifications suggestions:
PARENT OBJECT source code
#Entity(name = "FcrdRandcrdnr")
#Table(name = "fcrd_randcrdnr")
public class FcrdRandcrdnr {
#Id
#Column(name = "CARDNUMBER", length = 15)
private Long cardnumber;
#Column(name = "FLG_CRDNRISSUED", length = 1)
private int flgCrdnrissued;
#Column(name = "DT_CREATE")
private Timestamp dtCreate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "DT_UPDATE")
private Date dtUpdate;
public FcrdRandcrdnr() {
}
...
}
CHILD OBJECT source code
import javax.persistence.CascadeType;
...
import javax.persistence.OneToOne;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity(name = "FcrdClient")
#Table(name = "fcrd_clients")
public class FcrdClient {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "IDCLIENT")
private Long idClient;
#OneToOne
#MapsId("CARDNUMBER")
#JoinColumn(name = "CARDNUMBER",
foreignKey = #ForeignKey(name = "FK_1TO1_P_RANDCRDNR_C_CLIENT"))
#JsonIgnore
private FcrdRandcrdnr fcrdRandcrdnr;
#OneToMany(mappedBy = "fcrdClient", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
private List<FcrdBarcodecard> fcrdBarcodecards = new ArrayList<>();
#Column(name = "APP_USE_COUNTER", length = 9)
private int appUseCounter;
#Column(name = "APP_VERSION", length = 20)
private String appVersion;
#Column(name = "DT_CREATE")
private Timestamp dtCreate;
#Column(name = "DT_MODIFIED")
private Timestamp dtModified;
#Column(name = "EMAIL", length = 100)
private String email;
#Column(name = "FACEBOOKID", length = 35)
private String facebookid;
#Column(name = "FIRSTNAME", length = 20)
private String firstname;
#Lob
#Column(name = "GCM_REGID")
private String gcmRegid;
#Column(name = "LASTNAME", length = 20)
private String lastname;
#Column(name = "LOGIN_NAME", length = 15)
private String loginName;
#Column(name = "LOGIN_PASSWORD", length = 520)
private String loginPassword;
#Column(name = "LOGIN_TYPE", length = 50)
private String loginType;
#Column(name = "PHONE_MODEL", length = 50)
private String phoneModel;
#Column(name = "PLATFORM", length = 100)
private String platform;
#Column(name = "SEND_PUBKEY", length = 3)
private int sendPubkey;
#Column(name = "SYSTEM_LANGUAGE", length = 10)
private String systemLanguage;
#Column(name = "TOKEN_PKEY", length = 4000)
private String tokenPkey;
public FcrdClient() {
}
...
public void addBarcodecard(FcrdBarcodecard fcrdBarcodecard) {
fcrdBarcodecards.add(fcrdBarcodecard);
fcrdBarcodecard.setFcrdClient(this);
}
public void removeBarcodecard(FcrdBarcodecard fcrdBarcodecard) {
fcrdBarcodecards.remove(fcrdBarcodecard);
fcrdBarcodecard.setFcrdClient(null);
}
}
THE SERVICE source code
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class FcrdClientService {
#Autowired
FcrdClientRepository fcrdClientRepository;
#Autowired
FcrdRandcrdnrRepository fcrdRandcrdnrRepository;
public List<FcrdClient> findAll(){
return fcrdClientRepository.findAll();
}
/*
* Issue a new card for client
*/
public FcrdClient save(FcrdClient fcrdClient) {
// fetch a card from the table fcrd_randcrdnr
// the cards was randomly created by other mechanism
FcrdRandcrdnr fcrdRandcrdnr
= fcrdRandcrdnrRepository.findByFlgCrdnrissued(0).get(0);
// create new client
FcrdClient client = new FcrdClient();
client.setAppUseCounter(fcrdClient.getAppUseCounter());
client.setFirstname(fcrdClient.getFirstname());
// add the card to the new client
client.setFcrdRandcrdnr(fcrdRandcrdnr);
// save the client to the DB (fcrd_clients)
return fcrdClientRepository.save(client);
}
}

Question on persisting entity with Bidirectional #ManyToOne relationship using Mapstruct

This is my first time implementing #ManyToOne relationship using JPA/Mapstruct/Spring boot. I am running into the below exception: (NOTE: Using generic names as I am unable to share all the details)
java.sql.SQLIntegrityConstraintViolationException: Column 'A_ID' cannot be null for class B when I try to persist A.
Below are the relevant details. Can you help me understand what is the mistake I am making here? I have spent few hours debugging this and reading the posts without success yet.
#Mapper(componentModel="spring", uses= {BMapper.class}, collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
public interface AMapper {
#Mapping(target = "aId", source="id")
#Mapping(target = "aName", source = "name")
ADTO toDTO(final A a);
#Mapping(target = "id", ignore=true)
#Mapping(target = "name", source = "aName")
A toEntity(final ADTO aDTO);
#AfterMapping
default void setBSet(A a, #MappingTarget aDTO dto) {
for(B b : a.getBs())
b.setA(a);
}
}
#Mapper(componentModel="spring", uses= {CMapper.class}, injectionStrategy = InjectionStrategy.CONSTRUCTOR )
public interface BMapper {
#Mapping(target = "bId", source="id")
#Mapping(target = "aName", ignore=true)
BDTO toDTO(final B b);
#Mapping(target = "id", ignore=true)
#Mapping(target = "a", ignore=true)
B toEntity(final BDTO bDTO);
Set<B> bDtoToBSetEntity(Set<BDTO> set);
Set<BDTO> bSetEntityToBDto(Set<B> set);
}
Below are the class definitions of ADTO and BDTO
public class ADTO implements Serializable {
private static final long serialVersionUID = 8307772637314390585L;
private Long aId;
private String aName;
private LocalDate startDate;
private LocalDate endDate;
private Set<BDTO> bs = new HashSet<>();
// Getters / Setters here
public void addToBs(BDTO b) {
if(b != null) {
bs.add(b);
}
}
// hashCode/equals/toString methods here...
}
public class BDTO implements Serializable {
private static final long serialVersionUID = 2562084231749296452L;
private Long bId;
private String name;
private LocalDate startDate;
private LocalDate endDate;
private String aName;
// getters / setters go here..
// hashCode/equals/toString methods here...
}
Below are the class definitions of entity classes, particularly pay attention to class B where the exception is related to.
#Entity
#Table(name = "TABLEB", uniqueConstraints = {
#UniqueConstraint(columnNames = "ID")})
public class B implements Serializable {
private static final long serialVersionUID = 1407209531508355406L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Enumerated(EnumType.STRING)
#Column(name = "NAME", nullable = false)
private String name;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "A_ID", referencedColumnName="ID")
private A a;
#Column(name = "START_DATE", unique = false, nullable = false)
private LocalDate startDate;
#Column(name = "END_DATE", unique = false, nullable = false)
private LocalDate endDate;
}
#Entity
#Table(name = "TABLEA", uniqueConstraints = {
#UniqueConstraint(columnNames = "ID")})
public class A implements Serializable {
private static final long serialVersionUID = 6926335188960198569L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Column(name = "NAME", unique = false, nullable = false, length = 100)
private String name;
#OneToMany(mappedBy="a"/*, fetch = FetchType.EAGER*/, cascade = {CascadeType.ALL})
private Set<B> bs = new HashSet<>();
#Column(name = "START_DATE", unique = false, nullable = false)
private LocalDate startDate;
#Column(name = "END_DATE", unique = false, nullable = false)
private LocalDate endDate;
}
I am just calling save method of ADao class that persists using entity Manager.

jpa findby with list of conditions

I am still a beginner with java, here I'm trying to fetch the data from mysql database using JPA.
but I'm getting a problem with setting the list of conditions with find by function.
i can set Object of date even it refused the inputs
below is my code for reference.
my query :
select t.id, t.MSISDN, t.Param1, t.param2
from BULK_REPOSITORY t
where t.Camp_Start_Date between Sysdate - 2 and sysdate
and t.status = 0
and t.camp_type = 1;
Application :
#SpringBootApplication
public class AccessingDataJpaApplication {
private static final Logger log = LoggerFactory.getLogger(AccessingDataJpaApplication.class);
Bulk_repository bulk ;
public static void main(String[] args) {
SpringApplication.run(AccessingDataJpaApplication.class);
}
#Bean
public CommandLineRunner demo(Bulk_repositoryRepository repository) {
return (args) -> {
// fetch customers by Status
log.info("Customer found with findByStatus('0'):");
log.info("--------------------------------------------");
repository.findAllByStatusAndCampTypeAndCampStart_dateBetween(1,2,Date,Date-2).forEach(on -> {
log.info(on.toString());
});
};
}
Bulk_repositoryRepository class :
import org.springframework.data.repository.CrudRepository;
public interface Bulk_repositoryRepository extends CrudRepository<Bulk_repository, Long> {
List<Bulk_repository> findAllByStatusAndCampTypeAndCampStart_dateBetween(int status, int campType,Date campStart_dateStart, Date campStart_dateEnd);
Bulk_repository findById(long id);
}
Bulk_repository:
#Entity
#Table(name = "BULK_REPOSITORY")
public class Bulk_repository {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "msisdn")
private String msisdn;
#Column(name = "camp_start_date")
private Date campStartDate;
#Column(name = "camp_end_date")
private Date campEndDate;
#Column(name = "camp_type")
private int campType;
#Column(name = "camp_cd")
private String camp_cd;
#Column(name = "status")
private int status;
#Column(name = "process_date")
private Date processDate;
#Column(name = "entry_date")
private Date entryDate;
#Column(name = "entry_user")
private String entry_user;
#Column(name = "param1")
private String param1;
#Column(name = "param2")
private String param2;
#Column(name = "param3")
private String param3;
#Column(name = "param4")
private String param4;
#Column(name = "param5")
private String param5;
#Column(name = "error_desc")
private String error_desc;
#Column(name = "fulfilment_status")
private int fulfilment_status;
## getter and setter and ToString
Use this way,
Escape the _ by using an additional underscore
List<Bulk_repository> findAllByStatusAndCamp__typeAndCamp__start__dateBetween(int status, int camp_type,Date camp_start_dateStart, Date camp_start_dateEnd);
I recommond to use this way in your model class. If so you have to change your repository according to this.
#Column(name = "camp_start_date")
private Date campStartDate; // better to use this way

JPA Specification filtering nested object

I am trying to fetch nested object property but getting illegalArgument exception.
AuditTestingPlanSpecification name = new AuditTestingPlanSpecification(new SearchCriteria("auditPlanId.auditPlanEntity", ":",dates));
Page<AuditTestingPlanMaster> a = auditTestingPlanMasterRepository.findAll(name, ten);
Please find below code,
public class AuditTestingPlanSpecification implements Specification<AuditTestingPlanMaster> {
private SearchCriteria criteria;
public AuditTestingPlanSpecification(SearchCriteria searchCriteria) {
this.criteria = searchCriteria;
}
#Override
public Predicate toPredicate(Root<AuditTestingPlanMaster> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if (root.get(criteria.getKey()).getJavaType() == String.class) {
return builder.like(root.<String>get(criteria.getKey()), "%" + criteria.getValue().get(0).toString() + "%");
} else {
return builder.equal(root.get(criteria.getKey()), criteria.getValue().get(0).toString());
}
return null;
}
}
Class SearchCriteria.java
public class SearchCriteria {
public SearchCriteria(String key, String operation, List<Object> value) {
super();
this.key = key;
this.operation = operation;
this.value = value;
}
private String key;
private String operation;
private List<Object> value;
// getters & setters
}
Class AuditTestingPlanMaster.java
#Entity
#Table(name = "audit_testing_plan_master")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class AuditTestingPlanMaster implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#Column(name = "risk_area_id")
private Long riskAreaId;
#Column(name = "expected_revert_date")
private Instant expectedRevertDate;
#Column(name = "created_date")
private Instant createdDate;
#Column(name = "last_modified_date")
private Instant lastModifiedDate;
#JoinColumn(name = "audit_plan_id", referencedColumnName = "id")
private AuditPlanMaster auditPlanId;
//getters & setters
}
Class AuditPlanMaster.java
#Entity
#Table(name = "audit_plan_master")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class AuditPlanMaster implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#Column(name = "remarks", length = 255)
private String remarks;
#Column(name = "audit_plan_entity", length = 50)
private String auditPlanEntity;
#Column(name = "start_date")
private Instant startDate;
#Column(name = "end_date")
private Instant endDate;
//getters & setters
}
I want to fetch all the AuditTestingPlanMaster objects whose AuditPlanMaster.auditPlanEntity string is matching with provided filter value.
Thank you for your time and help in advance.
I had the same problem, here is a snippet of how I handled it. My problem was when accessing id field from inner usuario object, in my case, id would be like your auditPlanEntity, and usuario would be like auditplanMaster:
public static Specification<UsuarioErrorEquipo> usuarioContains(String codigoUsuario) {
return (root, query, builder) -> {
Path<Usuario> u = root.get("usuario");
return builder.equal(u.get("id"), codigoUsuario);
};
}
I believe, that in your case it should be something like:
Path<AuditPlanMaster> u = root.get("auditPlanId");
return builder.equal(u.get("auditPlanEntity"), "the value you want to compare");

SQL to JPQL, How to query Nested JPQL

I wonder if JPQL can be nested query. I am studying Spring Data JPA, and I also have uploaded several related questions.
If I have below sql in MySQL, how do I produce JPQL:
select
c.*
from
cheat c
left join (select * from cheat_vote where val = 1) v on c.cheat_seq = v.cheat_fk
group by
c.cheat_seq
having
count(*) < 10
limit 5
I have two entities.
public class Cheat implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "cheat_seq", length = 10)
private Long cheatSeq;
#Column(name = "question", unique = true, nullable = false)
private String question;
#Column(name = "answer", unique = true, nullable = false)
private String answer;
#Column(name = "writer_ip", nullable = false)
private String writerIP;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "reg_date", nullable = false)
private Date regDate;
#Transient
private String regDateText;
#OneToMany(mappedBy = "cheat", fetch=FetchType.LAZY)
private Set<CheatVote> vote;
#Override
public String toString() {
return "Cheat [cheatSeq=" + cheatSeq + "]";
}
}
Above entity has a #OneToMany collection, and the collection entity is below.
public class CheatVote implements Serializable{
private static final long serialVersionUID = 1L;
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Id
#Column(name="seq", nullable=false)
private Long seq;
#Column(name="val", nullable=false)
#NonNull
private Integer value;
#Column(name="ip_address", nullable=false)
#NonNull
private String ipAddress;
#JoinColumn(name="cheat_fk", referencedColumnName="cheat_seq")
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
#NonNull
private Cheat cheat;
#Override
public String toString() {
return "CheatVote [seq=" + seq + "]";
}
}
I want to get Cheat entitiy which has less than 10 children CheatVote entities.
You can try it:
#Query("SELECT c FROM Cheat c LEFT JOIN c.vote v WHERE v.value = 1 GROUP BY c.cheatSeq HAVING count(c) < 10")
About 'LIMIT' you can use parameter Pageable of Spring Data JPA

Resources