ERROR - new Global exception handled! Message = java.util.LinkedHashMap cannot be cast to java.math.BigInteger - spring-boot

DataType of patientId is BigInteger in entity Object
private BigInteger patientId;
Code:
#Override
public List<ChatRoomHistory> getLastChatDetails(List<String> patientIds) {
String queryStr = "FROM ChatRoomHistory where type = 'NO' and patientId in :patientIds ORDER BY chatCloseTime DESC";
TypedQuery<ChatRoomHistory> query = sessionFactory.getObject().getCurrentSession().createQuery(queryStr, ChatRoomHistory.class);
query.setParameter("patientIds", patientIds);
return query.getResultList();
}
Error
2020-08-16 19:52:27,939 [http-nio-8080-exec-5:] c.t.c.u.e.GlobalExceptionHandler.handleException:243
ERROR - new Global exception handled! Message = java.util.LinkedHashMap cannot be cast to java.math.BigInteger
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to java.math.BigInteger
at org.hibernate.type.descriptor.java.BigIntegerTypeDescriptor.unwrap(BigIntegerTypeDescriptor.java:19)
at org.hibernate.type.descriptor.sql.DecimalTypeDescriptor$1.doBind(DecimalTypeDescriptor.java:47)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:74)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:280)

Like said in the comment, you can't pass a list of String as a parameter intended for a numeric field.
You should declare your parameter as
public List<ChatRoomHistory> getLastChatDetails(List<BigInteger> patientIds)

You can correct your method in this way:
#Override
public List<ChatRoomHistory> getLastChatDetails(List<BigInteger> patientIds)
{
String hql = "select c from ChatRoomHistory c where c.type = 'NO' and c.patientId in :patientIds ORDER BY c.chatCloseTime DESC";
TypedQuery<ChatRoomHistory> query = sessionFactory.getCurrentSession().createQuery(hql, ChatRoomHistory.class);
query.setParameter("patientIds", patientIds);
return query.getResultList();
}
Comments:
Even though HQL does not require the presence of a select_clause, it is generally good practice to include one.
The list of values must not be empty; it must contain at least one value. (See this).

Related

InvalidPathException while sorting with org.springframework.data.domain.Pageable

I am trying to sort my table's content on the backend side, so I am sending org.springframework.data.domain.Pageable object to controller. It arrives correctly, but at the repository I am getting org.hibernate.hql.internal.ast.InvalidPathException. Somehow the field name I would use for sorting gets an org. package name infront of the filed name.
The Pageable object logged in the controller:
Page request [number: 0, size 10, sort: referenzNumber: DESC]
Exception in repository:
Invalid path: 'org.referenzNumber'","logger_name":"org.hibernate.hql.internal.ast.ErrorTracker","thread_name":"http-nio-8080-exec-2","level":"ERROR","level_value":40000,"stack_trace":"org.hibernate.hql.internal.ast.InvalidPathException: Invalid path: 'org.referenzNumber'\n\tat org.hibernate.hql.internal.ast.util.LiteralProcessor.lookupConstant(LiteralProcessor.java:111)
My controller endpoint:
#GetMapping(value = "/get-orders", params = { "page", "size" }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<PagedModel<KryptoOrder>> getOrders(
#ApiParam(name = "searchrequest", required = true) #Validated final OrderSearchRequest orderSearchRequest,
#PageableDefault(size = 500) final Pageable pageable, final BindingResult bindingResult,
final PagedResourcesAssembler<OrderVo> pagedResourcesAssembler) {
if (bindingResult.hasErrors()) {
return ResponseEntity.badRequest().build();
}
PagedModel<Order> orderPage = PagedModel.empty();
try {
var orderVoPage = orderPort.processOrderSearch(resourceMapper.toOrderSearchRequestVo(orderSearchRequest), pageable);
orderPage = pagedResourcesAssembler.toModel(orderVoPage, orderAssembler);
} catch (MissingRequiredField m) {
log.warn(RESPONSE_MISSING_REQUIRED_FIELD, m);
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok(orderPage);
}
the repository:
#Repository
public interface OrderRepository extends JpaRepository<Order, UUID> {
static final String SEARCH_ORDER = "SELECT o" //
+ " FROM Order o " //
+ " WHERE (cast(:partnerernumber as org.hibernate.type.IntegerType) is null or o.tradeBasis.account.retailpartner.partnerbank.partnerernumber = :partnerernumber)"
+ " and (cast(:accountnumber as org.hibernate.type.BigDecimalType) is null or o.tradeBasis.account.accountnumber = :accountnumber)"
+ " and (cast(:orderReference as org.hibernate.type.LongType) is null or o.tradeBasis.referenceNumber = :orderReference)"
+ " and (cast(:orderReferenceExtern as org.hibernate.type.StringType) is null or o.tradeBasis.kundenreferenceExternesFrontend = :orderReferenceExtern)"
+ " and (cast(:dateFrom as org.hibernate.type.DateType) is null or o.tradeBasis.timestamp > :dateFrom) "
+ " and (cast(:dateTo as org.hibernate.type.DateType) is null or o.tradeBasis.timestamp < :dateTo) ";
#Query(SEARCH_ORDER)
Page<Order> searchOrder(#Param("partnerernumber") Integer partnerernumber,
#Param("accountnumber") BigDecimal accountnumber, #Param("orderReference") Long orderReference,
#Param("orderReferenceExtern") String orderReferenceExtern, #Param("dateFrom") LocalDateTime dateFrom,
#Param("dateTo") LocalDateTime dateTo, Pageable pageable);
}
Update:
I removed the parameters from the sql query, and put them back one by one to see where it goes sideways. It seems as soon as the dates are involved the wierd "org." appears too.
Update 2:
If I change cast(:dateTo as org.hibernate.type.DateType) to cast(:dateFrom as date) then it appends the filed name with date. instead of org..
Thanks in advance for the help
My guess is, Spring Data is confused by the query you are using and can't properly append the order by clause to it. I would recommend you to use a Specification instead for your various filters. That will not only improve the performance of your queries because the database can better optimize queries, but will also make use of the JPA Criteria API behind the scenes, which requires no work from Spring Data to apply an order by specification.
Since your entity Order is named as the order by clause of HQL/SQL, my guess is that Spring Data tries to do something stupid with the string to determine the alias of the root entity.

MyBatis / Srping-Boot Mapper method attempted to return null from a method with a primitive return type (int)

I'm using MyBatis / Spring-Boot
I'm learning it :)
I get this error message:
Mapper method attempted to return null from a method with a primitive return type (int)
I tried different way to write it, with the help of different advises in forum. None working
There is the code:
#Select("INSERT INTO TB_Users(userId, firstName, lastName) VALUES( #{userId}, #{firstName}, #{lastName})")
#SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", before = false, resultType = Integer.class)
public int save(UserEntity userEntity);
Thanks for your help

in my Spring Application,i want to update record in data base and see this : hibernate could not resolve property

I need to update the record in the database and try use this code, but i see this error: java.lang.IllegalArgumentException: org.hibernate.QueryException: could not resolve property: company_id_active of: account.User [update account.User h set h.company_id_active =: ActiveCompanyId where h.user_id =:userId]
User.java
#ManyToOne
#JoinColumn(name = "company_id_active")
#JsonManagedReference
private Company companyActive;
...
Geter,Seter
UserRepositoryImpl.java
public boolean updateActiveCompanyID(int userId, int ActiveCompanyId) {
try {
String SQL= "update User h set h.company_id_active =: ActiveCompanyId where h.user_id =:userId";
Query query = entityManager.createQuery(SQL);
query.setParameter("ActiveCompanyId", ActiveCompanyId);
query.setParameter("userId", userId);
query.executeUpdate();
return true;
} catch (Exception ex) {
MyLogger.logException(ex);
return false;
}
}
Home.java
....
userRepository.updateActiveCompanyID(49,11);
....
by entityManager.createQuery(SQL) you are creating a HQL query and not native query you should use field name corresponding to the definition in the user class. so instead of using company_id_active in your query string, you should use companyActive as :
String SQL= "update User h set h.companyActive= :ActiveCompanyId where h.user_id =:userId";
And also make sure user_id is also your field name in the class.

Cannot map raw SQL query to DataRow

I am trying to get IEnumerable from linq query below. What am I doing wrong?
IEnumerable<DataRow> results =
context.Database.SqlQuery<DataRow>("SELECT * FROM Customer").AsEnumerable();
DataRow class does not have default (parameterless) constructor, so you can't use it as query parameter type. There is no generic constraints on type parameter, and nothing mentioned on MSDN(!), but column map factory will throw exception if parameter type does not have default constructor:
The result type 'System.Data.DataRow' may not be abstract and must
include a default constructor.
Here is a code which throws this exception:
internal static CollectionColumnMap CreateColumnMapFromReaderAndClrType(
DbDataReader reader, Type type, MetadataWorkspace workspace)
{
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
ConstructorInfo constructor = type.GetConstructor(flags, (Binder) null, Type.EmptyTypes, (ParameterModifier[]) null);
if (type.IsAbstract || (ConstructorInfo) null == constructor && !type.IsValueType)
throw EntityUtil.InvalidOperation(InvalidTypeForStoreQuery((object) type));
// ...
}
BTW Mapping to DataRow makes no sense, even if it would have default public constructor. Because it is not simple primitive type and it does not have properties which match the names of columns returned from the query (yes, mapping uses properties only).
Correct usage of Linq will be
IEnumerable<Customer> results = context.Customers;
That will generate SELECT * FROM Customer query, and map query results to customer entities. If you really want to use raw SQL:
IEnumerable<Customer> results =
context.Database.SqlQuery<Customer>("SELECT * FROM Customers");
I think we were trying to solve the same problem (Google led me here, anyway). I am executing a raw SQL command through SqlQuery<TElement>(string sql, params object[] parameters and wanted to assert individual properties of the results returned from the query in a unit test.
I called the method:
var result = (db.SqlQuery<Customer>("select * from customers").First();
and verified the data it returned:
Assert.AreEqual("John", result.FirstName);
I defined a private class Customer inside my test class (unfortunately, I'm not using Entity Framework):
private class Customer
{
public string FirstName { get; set; }
}
The properties of Customer must match the column names returned in the SQL query, and they must be properties (not just variables of the Customer class. You don't have to create properties for all of the columns returned from the query.

CriteriaBuilder - Sum using SelectCase

I am trying to perform a summation SQL query like the following:
select group_ID, sum(case when user_type = 'Exec' then 1000
when user_type = 'Office' then 10 else 0 end)
from subscription
group by group_ID;
using the following snippet from a hiberate CriteriaBuilder query:
criteriaBuilder.sum(
criteriaBuilder.selectCase()
.when(criteriaBuilder.equal(subscriptionJoin.get(Subscription_.userType), "Exec"),1000)
.when(criteriaBuilder.equal(subscriptionJoin.get(Subscription_.userType), "Office"),1)
.otherwise(101))
However the following compile error appears:
Inferred type 'java.lang.object' for type parameter 'N' is not within its bound; should extend 'java.lang.number'
Any idea how to support performing a summation using the selectCase?
Sum is defined as follows:
<N extends Number> Expression<N> sum(Expression<N> x);
So reason to the compilation error is that sum method expect such arguments which is Expression with type that extends Number. It determines type from the selectCase and ends up with java.lang.Object, which is not acceptable.
Problem can be solved by giving type parameter (<Number>):
criteriaBuilder.sum(
criteriaBuilder.<Number>selectCase()
We are using Spring Data JPA in our project and i have the same case where i need to do sum. Instead of criteria query i'm just following the "named parameters" approach because this approach seems easy.
My method which gives me sum is as follows.
public interface ITransactionEntryRepo extends PagingAndSortingRepository<TransactionEntryEntity, String> {
#Query("select SUM(CASE WHEN te.debit = 'Y' THEN (te.amount * - 1) WHEN te.debit = 'N' THEN te.amount ELSE 0 END) AS availablebalance FROM TransactionEntity t, TransactionEntryEntity te WHERE t.id = te.transactionEntity.id and te.accountEntity.id = :id and te.valid = 'T' and t.retcode = 'XX' GROUP BY te.accountEntity.id")
public double findAvailableBalance(#Param("id") String id);
}
And I call this method in the class where i need
double balance = iTransactionEntryRepo.findAvailableBalance(accountEntity.getId());
and pass it(balance) wherever I need to. Hope this helps someone.
For aggregate operation you should pass the CriteriaQuery with numeric type to be proper expression for criteria builder, however this may not affect your criteria base restriction of you entity type. Finally you can append the desired predicates to your criteria query for having criteria base aggregation.
public class Aggregate<T, S extends Number> {
public Aggregate(Class<T> tableType, Class<S> type) {
this.criteriaBuilder = entityManager.getCriteriaBuilder();
this.criteria = criteriaBuilder.createQuery(type);
this.root = criteria.from(tableType);
}
public Aggregate<T, S> aggregate(String field) {
criteria.select(criteriaBuilder.sum(root.get(field)));
return this;
}
public <I> Aggregate<T, S> restrict(String field, I i) {
criteria.where(criteriaBuilder.equal(root.get(field), i));
return this;
}
public S perform() {
return entityManager.createQuery(criteria).getSingleResult();
}
private Root<T> root;
private final CriteriaQuery<S> criteria;
private final CriteriaBuilder criteriaBuilder;
}

Resources