JPA EclipseLink 'Characters' in IN clause - oracle

How can I use a character in JPA's IN Clause in JPQL?
For Example In oracle DB I have this Query:
select * from channel o where channel_mode IN ('O','R')
Channel mode is a char column in DB.
I get a error from JPQL that invalid IN argument[o], it is a character.
#Chris
This is the JPQL:
typeMasterList = em.createQuery("select object(o) from ChannelRequest as o where o.crqState IN ('O','R') and o.crqMode = 'B' ").getResultList();
And the Entity ChannelRequest is:
#Entity
#Table(name = "CHANNEL_REQUEST")
#XmlRootElement
public class ChannelRequest implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "CRQ_ID")
private Long crqId;
#Size(max = 100)
#Column(name = "CRQ_QUEUE")
private String crqQueue;
#Size(max = 160)
#Column(name = "CRQ_DATA")
private String crqData;
#Column(name = "CRQ_STATE")
private Character crqState;
#Column(name = "ACTIVE_FLAG")
private Short activeFlag;
#Column(name = "ENABLED")
private Short enabled;
#Size(max = 100)
#Column(name = "CRQ_ADDRESS")
private String crqAddress;
#Column(name = "CRQ_MODE")
private Character crqMode;
#Column(name = "DCO")
#Temporal(TemporalType.TIMESTAMP)
private Date dco;
#Column(name = "DLUO")
#Temporal(TemporalType.TIMESTAMP)
private Date dluo;
#OneToMany(mappedBy = "rpmrqCrId")
private Collection<RpmRequest> rpmRequestCollection;
#JoinColumn(name = "MM_ID", referencedColumnName = "MM_ID")
#ManyToOne
private MediumMaster mmId;
#JoinColumn(name = "MC_ID", referencedColumnName = "MC_ID")
#ManyToOne
private MediumChannel mcId;`enter code here`
This is the error I get:
invalid IN expression argument [O], expected argument of type [java.lang.Character]

The JPA specification states that a string literal is enclosed in single quotes (e.g. 'X' is a string of length 1 not the character X).
It looks like in your case, JPQL is expecting a list of characters, not strings. You can work around the issue by passing in the character list as a parameter instead:
typeMasterList = em.createQuery("... o.crqState IN :states ...")
.setParameter("states", Arrays.asList('O', 'R'))
.getResultList();
Side note: you could make your life a lot easier by using an enum instead of characters. You could then reference the enum values directly in the query without issue. At the database-level, the enums could still map to a single character.

Did you try using a string instead of a char, i.e. "O", "R".

Related

Trying to Convert a SQL Query to a JPA Query

I want to convert this sql query to a JPA query, but I can't seem make sense of it... Should I use findByMarinaIdAndMovementGroupMeanId?? or findByMarinaIdAndMovementGroupMeanIdAndMovementMeanId??
Sql:
select m.* from movement_group m
join movement_group_mean mgm on m.id = mgm.movement_group_id
join movement_mean mm on mgm.movement_mean_id = mm.id
where mm.id = 1 and m.marina_id = :marinaId and mm.active = true;
MovementGroup:
#Entity
public class MovementGroup {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String code;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private Boolean active;
private String iconUrl;
#OneToMany(mappedBy = "movementGroup")
private Set<MovementGroupMean> movementGroupMeans;
#JsonIgnore
#ManyToOne()
#JoinColumn(name = "marina_id")
private Marina marina;
MovementGroupMean:
#Entity
public class MovementGroupMean {
#EmbeddedId
#JsonIgnore
private MovementGroupMeanPK movementGroupMeanPK;
#JsonBackReference
#ManyToOne
#JoinColumn(name = "movement_group_id", insertable = false, updatable = false)
private MovementGroup movementGroup;
#ManyToOne
#JoinColumn(name = "movement_mean_id", insertable = false, updatable = false)
private MovementMean movementMean;
MovementMean:
#Entity
public class MovementMean {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#Enumerated(EnumType.STRING)
private MovementMeanType movementMeanType;
private Boolean active;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
#JsonBackReference
#ManyToOne()
#JoinColumn(name = "marina_id")
private Marina marina;
Not sure where the problem lies, so excuse the lengthy explanation on SQL->JPQL:
Replace your table names with your entity names
movement_group -> MovementGroup
Replace your joins with the java references, letting JPA use the relationship mapping you've defined instead.
"join movement_group_mean mgm on m.id = mgm.movement_group_id" becomes "join m.movementGroupMeans mgm"
"join movement_mean mm on mgm.movement_mean_id = mm.id becomes "join mgm.movementMean mm"
Only tricky spot is your entities do not define a basic mapping for the marina_id value. So to get at m.marina_id, you will have to use the 'marina' reference and use its presumably ID value:
"m.marina_id = :marinaId" -> "m.marina.id = :marinaId"
Giving you JPQL:
"Select m from MovementGroup m join m.movementGroupMeans mgm join mgm.movementMean mm where mm.id = 1 and m.marina.id = :marinaId and mm.active = true"

How to write custom findAll() with Specification in JPA repository

When I use skuRepository.getAll(), it works OK, but when I apply filters, defined in Specification (List filteredRegs = skuRepository.getAll(specification)) I still get all the rows of the table
What should i do to apply the specifications to my custom method?
public interface SkuRepository extends CrudRepository<Sku, Integer>, JpaSpecificationExecutor<Sku> {
#Query("select s from Sku s join fetch s.unit un join fetch s.supplier sup WHERE un.id = sku_unit_id AND sup.id = supplier_id")
List<Sku> getAll(#Nullable Specification<Sku> var1);
#Query("select s from Sku s join fetch s.unit un join fetch s.supplier sup WHERE un.id = sku_unit_id AND sup.id = supplier_id")
List<Sku> getAll();
}
UPD:
Here is my entities.
When I make sampling by a Sku table using the Specification API, I see three separate selects in log: one for Sku entity, one for Unit and one for Suppliers. I want my app to make one select with joins.
I read that this is due to the fact that I use EAGER fetch type, so I change it to LAZY, but then I got another problem: "InvalidDefinitionException: No serializer found..." This is logical because related entities Unit and Supplier are not loaded.
Then I decided to write my custom getAll() with request:
#Query("select s from Sku s join fetch s.unit un join fetch s.supplier sup WHERE un.id = sku_unit_id AND sup.id = supplier_id ORDER BY s.name")
But now it does not support Specification.
Please advise what to do.
#Entity
#Table(name = "sku")
public class Sku implements Cloneable, CloneableEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "sku_code", length = 6, nullable = false, unique = true)
private String code;
#Column(name = "sku_name", nullable = false)
private String name;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JoinColumn(name = "sku_unit_id", nullable = false)
private Unit unit;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JoinColumn(name = "supplier_id", nullable = false)
private Supplier supplier;
#Column(name = "qty_in_sec_pkg")
private int quantityInSecondaryPackaging;
#Column(name = "sku_is_active", nullable = false)
private boolean isActive;
//constructors, getters, setters
}
#Entity
#Table(name = "units")
public class Unit {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id ")
private int id;
#Column(name = "unit", nullable = false, unique = true)
private String unit;
#Column(name = "description")
private String description;
//constructors, getters, setters
}
#Entity
#Table(name = "suppliers")
public class Supplier {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id ")
private int id;
#Column(name = "supplier_code", length = 6, nullable = false, unique = true)
private String supplierCode;
#Column(name = "supplier_name", nullable = false)
private String name;
#Column(name = "create_date", length = 19, nullable = false)
private String createDate;
#Column(name = "update_date", length = 19)
private String updateDate;
//constructors, getters, setters
}
You can't mix #Query and Specification
You can only use JpaSpecificationExecutor interface methods to use Specification.
Find more details here

I am not getting unique column using hibernate , for postgresql db

#Entity
#Table(uniqueConstraints={#UniqueConstraint(columnNames={"catgoryId","applcationNo"})})
I tried this explicitly #table
and unique , //but not getting result.
public class DmsDocDetailPojo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(columnDefinition = "serial")
private Long dmsDocId;
#Column
private String stateCode="AI";
#Column(name = "applicationNo", unique = true,nullable=false)
#NotNull
private String applcationNo;
#Column(name = "catgoryId", unique = true,nullable=false)
private String catgoryId;
#CreationTimestamp
#Column( nullable = false, updatable=false)
private Date doc_uploaded_dt;
#UpdateTimestamp
private Date doc_updated_dt;
#Column(name = "document_file", columnDefinition = "BYTEA")
private byte[] document_file;
#Column
private String fileName;
#Column
private Integer fileSize;
}
check your database primary key it should be an auto increment

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

how to find objects field [duplicate]

This question already has answers here:
Spring JPA selecting specific columns
(18 answers)
Closed 5 years ago.
I have Location and I want to retrieve all locations in db by company
I can do this in this way List<Location> findByCompanyId(Long companyId);
but How can I retrieve ids of Locations not whole object
List<Long> findByCompanyId(Long companyId);
I want the same thing as in first method but without whole object only ids
public class Location extends BaseEntity {
#Column(name = "`street_first`", nullable = false)
private String streetFirst;
#Column(name = "`street_second`")
private String streetSecond;
#Column(name = "`city`", nullable = false)
private String city;
#Column(name = "`zip`")
private String zip;
#Column(name = "`state`", nullable = false)
private String state;
#Column(name = "`phone`", nullable = false)
private String phone;
#JoinColumn(name = "`company_id`", nullable = false)
private Company company;
}
//getters and setters
#Query("SELECT l.id FROM Location l WHERE l.company.id = :companyId");
List<Long> getLocationIds(#Param("companyId")Long companyId);

Resources