get max value of column using jpa criteria query - jpa

I want to get the maximum value of column relationId from table ElementRelationType
I have written code but its giving error
CriteriaBuilder cb1 = entityManager.getCriteriaBuilder();
CriteriaQuery<ElementRelationTypes> cq1 = cb1.createQuery(ElementRelationTypes.class);
Root<ElementRelationTypes> root = cq1.from(ElementRelationTypes.class);
cq1.select(cb1.max(root.get("relationId")));
select and max both giving error
how to get the integer max value
public class ElementRelationTypes {
private RelationId relationLangPK=new RelationId();
private Country country;
private Status status;
#EmbeddedId
public RelationId getRelationLangPK() {
return relationLangPK;
}
public void setRelationLangPK(RelationId relationLangPK) {
this.relationLangPK = relationLangPK;
}
#Transient
public Integer getRelationId() {
return getRelationLangPK().getRelationId();
}
public void setRelationId(Integer relationId) {
getRelationLangPK().setRelationId(relationId);
}
#Transient
public Language getLanguage() {
return getRelationLangPK().getLanguage();
}
public void setLanguageCode(Language language) {
getRelationLangPK().setLanguage(language);
}
and
public class RelationId implements Serializable {
private static final long serialVersionUID = 1L;
private Integer relationId;
private Language language;
#JoinColumn(name=PersistenseConstants.ELEMENT_RELATION_TYPE_COL_RELATION_ID)
public Integer getRelationId() {
return relationId;
}
public void setRelationId(Integer relationId) {
this.relationId = relationId;
}
#OneToOne
#JoinColumn(name=PersistenseConstants.LANGUAGE_ENTITY_COL_LANG_CODE)
public Language getLanguage() {
return language;
}
public void setLanguage(Language language) {
this.language = language;
}

You didn't post which errors do you receive, so I have to guess.
CriteriaBuilder.max accepts Expression<N> where N extends Number
At the same time Root.get by default returns Path<Object> which is inconvertible to Expression<Number>.
So to make your call to max work you need to specify generic parameter to root.get:
cq1.select(cb1.max(root.<Number>get("relationId")));
here you can replace Number with an actual type of relationId (Long, BigInteger etc.)
UPDATE: #perissf addressed another issue with your code. If you are going to select maximal value (which is numeric) you should declare your CriteriaQuery as a query to Number not ElementRelationTypes

Related

Is it possible to achieve sum of multiple fields using group by in spring data query methods?

I've a table given below
CREATE TABLE `tbl_horses` (
`serial_no` BIGINT (5) NOT NULL AUTO_INCREMENT,
`horse_id` BIGINT (3) NOT NULL,
`point` DOUBLE NOT NULL,
PRIMARY KEY (`serial_no`)
) ;
Can I achieve output I'm getting through the following query
SELECT
th.`horse_id`,
AVG(th.point)
FROM
`tbl_horses` th
GROUP BY (`horse_id`) ;
The structure of model is given below
#Entity
#Table(name = "tbl_horses")
public class Horse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "serial_no")
private long serialNo;
#Column(name = "horse_id")
private long horseId;
#Column(name = "point")
private double point;
public long getSerialNo() {
return serialNo;
}
public void setSerialNo(long serialNo) {
this.serialNo = serialNo;
}
public long getHorseId() {
return horseId;
}
public void setHorseId(long horseId) {
this.horseId = horseId;
}
public double getPoint() {
return point;
}
public void setPoint(double point) {
this.point = point;
}
}
How can I get the result of above query through spring data query methods?
I don't want to use criteria builder over here or native query to achieve this.
If I understand your question correctly. You can write these queries using the #Query annotation.
public interface UserRepository extends JpaRepository<Horse , Long> {
#Query("SELECT AVG(th.point) from Horse th GROUP BY (th.horseId)")
int getAverageAge();
}

Using JPA 2.1 Converter with Java 1.8 Time API reults in Eclipse JPA-Error "The left and right expressions type must be of the same type"

I'm using Eclipe IDE Neon.2 working on a JavaEE 7 project (JPA 2.1 & Java 8).
In my Entities new Java 8 Time API is used and therefore i need to use JPA-AttributeConverter to convert them to sql-datatypes. In most cases i want to use named queries with JPQL.
#Entity
#NamedQuery(name = Account.QUERY_FIND_LOGGED_USER_TODAY, query = "SELECT a from Account a where a.lastLoggedInDate == CURRENT_DATE")
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
public final static String QUERY_FIND_LOGGED_USER_TODAY = "account_find_logged_user_today";
#Id
private Integer id;
private String name;
#Convert(converter = LocalDateAttributeConverter.class)
private LocalDate lastLoggedInDate;
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public LocalDate getLastLoggedInDate() {
return this.lastLoggedInDate;
}
public void setLastLoggedInDate(LocalDate lastLoggedInDate) {
this.lastLoggedInDate = lastLoggedInDate;
}
}
The AttributeConverter looks like this
#Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
#Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
#Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}
Eclipse shows me an error-message pointing to "a.lastLoggedInDate == CURRENT_DATE" saying
The left and right expressions type must be of the same type.
Is this a real JPA-Error, or does Eclipse-JPA-Validation not support the combination JPA-Converter & JPQL.

Creating JPA entity with composite primary key with #Id from #MappedSuperclass

I have a class hierarchy for JPA entities with the base class being a MappedSuperclass which has one ID defined. I am trying to use a composite key in a subclass however that does not seem to work
My code looks like this
#MappedSuperclass
public class BaseEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
#Entity
#EntityListeners(EntityBaseListener.class)
#Inheritance(strategy=InheritanceType.JOINED)
#Table(name = "catalog_entity")
public class BaseCatalogEntity extends BaseEntity {
#Column(name = "created_at", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
#Column(name = "updated_at", nullable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
public void setCreatedAt(Date date)
{
createdAt = date;
}
public void setUpdatedAt(Date date)
{
updatedAt = date;
}
public Date getCreatedAt() {
return createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
}
#Entity
#Table(schema = "student_catalog")
#IdClass(value = StudentCatalog.StudentCatalogPK.class)
public class StudentCatalog extends BaseCatalogEntity {
#Id
#Column(name = "name", nullable = false, length = 100)
private String name;
#Id
#Column(name = "version", nullable = false)
private Integer version;
#Column(name = "description" , length = 255)
private String description;
#Column(name = "vendor" , length = 50)
private String vendor;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getVendor() {
return vendor;
}
public void setVendor(String vendor) {
this.vendor = vendor;
}
public static class StudentCatalogPK implements Serializable {
private Long id;
private String name;
private Integer version;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
#Override
public boolean equals(Object obj) {
boolean result = false;
if(obj != null && (obj instanceof StudentCatalogPK)) {
StudentCatalogPK other = (StudentCatalogPK)obj;
result = (Objects.equals(this.id, other.id) && Objects.equals(this.name, other.name) &&
Objects.equals(this.version, other.version));
}
return result;
}
#Override
public int hashCode() {
return (27780 + (this.id != null ? this.id.hashCode() : 0) +
(this.version != null ? this.version.hashCode() : 0) +
(this.name != null ? this.name.hashCode() : 0));
}
}
}
I get the following exception:
Exception Description: Invalid composite primary key specification. The names of the primary key fields or properties in the primary key class [com.example.jpa.StudentCatalog$StudentCatalogPK] and those of the entity bean class [class com.example.jpa.StudentCatalog] must correspond and their types must be the same. Also, ensure that you have specified ID elements for the corresponding attributes in XML and/or an #Id on the corresponding fields or properties of the entity class.
I am using Eclipselink 2.5.1. Is there a way I can get this to work without changing the BaseEntity and BaseCatalogEntity classes?
It is not legal in JPA to redefine the id in subclasses. This would lead to ambiguities in the table mappings as well as in polymorphic queries.
The desire to extend the key defined in a superclass is a common issue when business keys are used for DB identity. I would advise to use only surrogate keys (like UUID) for DB identity and business keys for instance identity.
Under following conditions:
your base entity should use TABLE_PER_CLASS inheritance (and as I can see it is)
your base entity (composite key) key is of the same type as that one you want to have in your derived class (so there should be also composite key of String and Integer).
You can use #AttributeOverride annotation under class declaration, removing #Id fields from it:
#AttributeOverride(name = "id", column = #Column(name = "NAME"))
This - in result, can change column name in derived entity's table and that's the most you can acheive.
When using #MappedSuperClass, it would be advisable to make the BaseEntity Class as abstract and then extending the Base class from other Entity classes.
Cleaner approach keeping inheritance in mind and designing your application.

How to make a request factory non-transportable type transportable?

According to this answer: Is com.vividsolutions.jts.geom.Geometry directly transportable using requestfactory? Geometry is ( a particular case of a type that is ) non- transportable using requestfactory.
So then would this work? :
#Entity
public class Poi {
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Id
private Integer id;
#Type(type="org.hibernate.spatial.GeometryType")
private Geometry geom;
//bi-directional many-to-one association to PoiCateg
#ManyToOne
#JoinColumn(name="id_cat")
private PoiCateg poiCateg;
#Version
private Integer version;
public Poi() {
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Geometry getGeom() {
return this.geom;
}
public void setGeom(Geometry geom) {
this.geom = geom;
}
public PoiCateg getPoiCateg() {
return this.poiCateg;
}
public void setPoiCateg(PoiCateg poiCateg) {
this.poiCateg = poiCateg;
}
//not your standard getters and setters
public String getGeomClient() {
return //result of method that converts from Geometry object to WKT string representation
}
public void setGeomClient(String geom) {
this.geom = // result of method that converts from String to Geometry
}
}
and then my modified entity proxy for Poi would look like:
#ProxyFor(value=Poi.class)
public interface PoiProxy implements EntityProxy {
public Integer getId() ;
public void setId(Integer id);
public PoiCategEntityProxy getPoiCateg() ;
public void setPoiCateg(PoiCateg poiCateg);
//not your standard getters and setters
public String getGeomClient() ;
public void setGeomClient(String geom) ;
}
since getGeomClient and setGeomClient in the server entity contain a geometry type will it be a problem on the client?
EDIT1: forgot about #Version private Integer version; mistake fixed.
Not only it'll work but that's the (simplest) way to make it work.
Alternatives involve using wrappers/builders. I've also seen people using EntityProxys where the stringified value is used as the identifier, but beware that RequestFactory requires a per-request cache.

Google Objectify v4 fetch by id

I'm trying to fetch an entity in App Engine with Objectify v4 but it doesn't work.
My #Entity: Translation.class
The #Id of the #Entity I want to fetch: 301L
My #Entity:
#Entity
public class Translation {
#Id
private Long id;
private String text;
public String getText() {
return text;
}
public Long getId() {
return id;
}
public void setText(String text) {
this.text = text;
}
}
The request that doesn't word:
Translation translation =ObjectifyService.ofy().load().type(Translation.class).id(301L).get(); // translation is null
But if I do:
Translation translation = ObjectifyService.ofy().load().type(Translation.class).first().get(); // translation is not null
Then:
System.out.println(translation.getId()); // translation id equal 301
So the fetch by id doesn't seem to work.
Where is the problem?
Since your entity has a #Parent field, in order to get it by id, you need to execute:
Translation translation = ObjectifyService.ofy().load().type(Thing.class).parent(par).id(301).get();
For more information take a look at Objectify Basic Operations - Loading
Hope this helps!
for #stickfigure, this is my real #Entity (PartOfSpeechGroup is obviously an #Entity too).
#Entity
public class Translation implements IsSerializable {
#Id
private Long id;
private String text;
#Parent
private Key<PartOfSpeechGroup> partOfSpeechEntryKey;
public Translation() {}
public Translation(Key<PartOfSpeechGroup> partOfSpeechEntryKey) {
this.partOfSpeechEntryKey = partOfSpeechEntryKey;
}
public String getText() {
return text;
}
public Long getId() {
return id;
}
public Key<PartOfSpeechGroup> getPartOfSpeechEntryKey() {
return partOfSpeechEntryKey;
}
public void setText(String text) {
this.text = text;
}
}