I want to create a query that query only rows that have an empty list.
The list in my model :
public static final Finder<Long, BankDebit> find = new Finder<>(Long.class, BankDebit.class);
#ManyToMany(cascade = CascadeType.ALL)
public List<Mandate> mandates;
The function that do the query :
public static ExpressionList<BankDebit> findFilter(sepaId, mandat, day ....) {
ExpressionList<BankDebit> exp = find
.fetch("creditor")
.fetch("debitor")
.fetch("mandates")
.where()
.eq("sepa.id", sepaId);
if (day > 0) {
dateMax = dateMax.withDayOfMonth(day);
exp.eq("executionDate", dateMax.toDate());
}
if (!mandat.isEmpty())
exp.eq("mandates.id", 0); // here is the problem
return exp
}
I want to query only the BankDebit that have an empty list of mandates. I tried to do it with .isNull("mandates"), .isNull("mandates.id"), .lt("mandates.id", 1), .eq("mandates.id", null) and a lot more, nothing ever worked...
I don't understund how I'm supposed to do. Do a rawSql would be very painful (I didnt paste the whole code of the function)
I tried a lot of things and reached many 4th page on google (never a good sign). I just ran out of ideas.
Huh, you were faster actually I wanted to suggest you similar solution, probably lighter as doesn't require object mapping:
List<Integer> idsWithoutMandates = new ArrayList<>();
List<SqlRow> rowList = Ebean.createSqlQuery("SELECT debits.id id " +
"FROM bank_debit AS debits " +
"LEFT JOIN bank_debit_mandate AS jointable ON (debits.id = jointable.bank_debit_id) " +
"WHERE (jointable.mandate_id IS NULL OR jointable.mandate_id = 0)").findList();
for (SqlRow sqlRow : rowList) idsWithoutMandates.add(sqlRow.getInteger("id"));
List<BankDebit> debitsWithoutMandates = BankDebit.find.where().in("id", idsWithoutMandates).findList();
I found out that although .isNull() doesn't work, .isNotNull() did work. So I made a little ugly modification to use the existing ones to find the others...
if (!mandat.isEmpty()) {
List<BankDebit> tmp = find.fetch("mandates").where().eq("sepa.id", sepaId).isNotNull("mandates.id").findList();
List<Long> ids = Lists.newArrayList();
for (BankDebit bd : tmp) {
ids.add(bd.id);
}
exp.not(Expr.in("id", ids));
}
Related
I am using hibernate-generic-dao for a searching function. Since I only need to show one of the records if they have same value on a column field. But I am not sure how to achieve this by the search / filter functions.
package com.googlecode.genericdao.search;
PersonContact domain object:
...
#Column(name = "group_key", length = 20)
public String getGroupKey() {
return groupKey;
}
#Formula(value = "(SELECT status from person_contact m " +
" WHERE m.case = case AND m.movement_id = movement_id )")
public String getActiveRecord() {
return activeRecord;
}
...
Search search = new Search();
search.addFilterNotNull("groupKey"); //groupKey is the field I want to use "group by / unqiue" with it
search.addFilterEqual("type","C");
search.addFilterCustom("{activeRecord} != 'I' ");
search.setMaxResults(limit);//for paging
search.setFirstResult(startIdx);
SearchResult<PersonContact> resultObj = PersonContactDAO.searchAndCount(search);
You should probably ask this question by opening an issue in the repository for that project here: https://github.com/vincentruan/hibernate-generic-dao
It seems though as if the project is abandoned, so unless you feel like digging into the details, you should probably try to get away from it.
I have this query code in my application:
#Override
public MyParameter loadMyParameterSetByVersion(Long version) {
StringBuilder sb = new StringBuilder();
sb.append("SELECT mp FROM MyParameter mp ");
sb.append("INNER JOIN FETCH mp.priceParametersGood good ");
sb.append("WHERE mp.objId = :version ");
sb.append("ORDER BY good.isBc, good.isGd, good.priceFrom");
QueryBuilder builder = createQueryBuilder(sb.toString());
builder.addParameter("version", version);
List<MyParameter> result = executeQuery(builder.createQuery());
if (result.size() > 0) {
return result.get(0);
} else {
return null;
}
}
I did not write this method, I just added the ORDER BY condition, because it's needed right now. My problem is, the results are still not sorted that way. Do I need to rewrite this? If yes, what should I use to make it work?
I tried this query in my Oracle DB and there the results are sorted, so I assume it's something with this Query.
I think a orderby is added for you when no orderBy() is added.
So this essentially QueryBuilder will override your orderby that is in the string by adding yet another order by.
Instead of having a hard coded string as the SQL, you should use the DSL syntax that QueryBuilder offers you.
Using some code I found here you will see that you are using QueryBuilder in the wrong way and the original code should be re-written.
You code should look more the the article.
Statement statement = QueryBuilder.select().all().from( table.tableName() ).where( cName ).and( cBtm ).and( cTop ).orderBy( order );
final Iterator<Row> iter = session.execute( statement ).iterator();
for (Row row : iter ){
...
}
I'm currently working on a fetaure that will allow the system to search public services receipts by the combination of 6 parameters which can be null meaning that receipts shouldn't be filtered by this parameter: accountNumber, amountRangeMin, amountRangeMax, dateRangeMin, dateRangeMax, publicServiceId. However making a method for each combination of the parameters is not an option, I'm thinking that there must be a better way, at first my approach was as following:
On my Service I have this method:
public Map<String,Object> findPublicServiceReceiptsByParams(Integer accountNumber, BigDecimal amountRangeMin,
BigDecimal amountRangeMax, LocalDate dateRangeMin, LocalDate dateRangeMax, Integer publicServiceId) {
Map<String,Object> publicServiceReceipts = new HashMap<String,Object>();
String accountNumberFilter = !(accountNumber==null) ? accountNumber.toString() : "AccountNumberTableName";
String amountRangeMinFilter = !(amountRangeMin==null) ? amountRangeMin.toString() : "table.AmountColumnName";
String amountRangeMaxFilter = !(amountRangeMax==null) ? amountRangeMax.toString() : "table.AmountColumnName";
String dateRangeMinFilter = !(dateRangeMin==null) ? dateRangeMin.toString() : "Table.ReceiptCreationDateColumn";
String dateRangeMaxFilter = !(dateRangeMax==null) ? dateRangeMax.toString() : "Table.ReceiptCreationDateColumn";
String publicServiceIdFilter = !(publicServiceId==null) ? publicServiceId.toString() : "table.publicServiceIdColumn";
publicServiceReceipts = publicServiceReceiptRepository.findPublicServiceReceiptsByParams(accountNumberFilter,
amountRangeMinFilter, amountRangeMaxFilter, dateRangeMinFilter, dateRangeMaxFilter,
publicServiceIdFilter);
return publicServiceReceipts;
}
And then in my repository I had:
final static String FIND_PUBLIC_SERVICES_BY_ARGS = "Select (Insert whatever logic should go in here to select columns from receipts the where clause is the one that matters)"
+ " WHERE ACT.ACT_AccountNumber=:accountNumberFilter\n"
+ " AND PSE.PSE_Id=:publicServiceIdFilter\n"
+ " AND PSR.PSR_CreateDate BETWEEN :dateRangeMinFilter AND :dateRangeMaxFilter\n"
+ " AND PSR.PSR_Amount BETWEEN :amountRangeMinFilter AND :amountRangeMaxFilter\n"
+ " order by PSR.PSR_CreateDate desc";
#Query(nativeQuery = true, value = FIND_PUBLIC_SERVICES_BY_ARGS)
Map<String, Object> findPublicServiceReceiptsByParams(#Param("accountNumberFilter") String accountNumberFilter,
#Param("amountRangeMinFilter") String amountRangeMinFilter,
#Param("amountRangeMaxFilter") String amountRangeMaxFilter,
#Param("dateRangeMinFilter") String dateRangeMinFilter,
#Param("dateRangeMaxFilter") String dateRangeMaxFilter,
#Param("publicServiceIdFilter") String publicServiceIdFilter);
}
My reasoning was that if a parameter was null meant that whoever consumed the Web Service is not interested in that paramater so if that happens I set that variable as the Column Name so that it wouldn't affect in the WHERE clause and in theory make it simpler, but what I found was that It would send the names as Strings so it wouldn't be recognized as an sql statement which was the flaw in my thinking and as I said there must be another way other than writing each method for each combination, I appreciate any help :).
You should use the Criteria API, which was designed for creating dynamic queries. Named queries aren't really meant to be used in this case.
With it you can do something like this:
#PersistenceContext
EntityManager em;
List<YourEntity> method(String argument) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);
Root<YourEntity> root = cq.from(YourEntity.class);
List<Predicate> predicates = new ArrayList<>();
if (argument == null) {
predicates.add(cb.equal(root.get("yourAttribute"), argument);
}
// rest of your logic goes here
cq.where(predicates.toArray(new Predicate[]{}));
return em.createQuery(cq).getResultList();
}
I found a way to fix this, I did it like this (I'm going to show only the native Query since it's the inly thing that i changed):
DECLARE #actNum varchar(50),#crdNum varchar(50),#pseId varchar(50),#dateMin varchar(50),#dateMax varchar(50),#amountMin varchar(50),#amountMax varchar(50)
SET #actNum = :actNum
SET #crdNum = :crdNum
SET #pseId = :pseId
SET #dateMin = :dateMin
SET #dateMax = :dateMax
SET #amountMin = :amountMin
SET #amountMax = :amountMax
--Whatever Select with joins statement
WHERE ACT.ACT_AccountNumber = CASE WHEN #actNum = 'N/A'
THEN ACT.ACT_AccountNumber
ELSE #actNum END
AND CRD_CardNumber = CASE WHEN #crdNum = 'N/A'
THEN CRD_CardNumber
ELSE #crdNum END
AND PSE.PSE_Id= CASE WHEN #pseId = 'N/A'
THEN PSE.PSE_Id
ELSE #pseId END
AND PSR.PSR_CreateDate >= CASE WHEN #dateMin = 'N/A'
THEN PSR.PSR_CreateDate
ELSE #dateMin END
AND PSR.PSR_CreateDate <= CASE WHEN #dateMax = 'N/A'
THEN PSR.PSR_CreateDate
ELSE #dateMax END
AND PSR.PSR_Amount BETWEEN CASE WHEN #amountMin = 'N/A'
THEN PSR.PSR_Amount
ELSE #amountMin END
AND CASE WHEN #amountMax = 'N/A'
THEN PSR.PSR_Amount
ELSE #amountMax END
ORDER BY PSR.PSR_CreateDate DESC
The backend will send the parameters as either "N/A" (if it shouldn't be used to filter data) or the actual value, this worked fine for me!
I am trying insert an item in MongoDB using Java MongoDB driver.Before inserting I am trying to get nextId to insert,but not sure why I am always getting nextId as 4 .I am using below given method to get nextId before inserting any item in Mongo.
private Long getNextIdValue(DBCollection dbCollection) {
Long nextSequenceNumber = 1L;
DBObject query = new BasicDBObject();
query.put("id", -1);
DBCursor cursor = dbCollection.find().sort(query).limit(1);
while (cursor.hasNext()) {
DBObject itemDBObj = cursor.next();
nextSequenceNumber = new Long(itemDBObj.get("id").toString()) + 1;
}
return nextSequenceNumber;
}
I have total 13 record in my mongodb collection.What I am doing wrong here?
Please don't do that. You don't need create a bad management id situation as the driver already do this in the best way, just use the right type and annotation for the field:
#Id
#ObjectId
private String id;
Then write a generic method to insert all entites:
public T create(T entity) throws MongoException, IOException {
WriteResult<? extends Object, String> result = jacksonDB.insert(entity);
return (T) result.getSavedObject();
}
This will create a time-based indexed hash for id's which is pretty much more powerful than get the "next id".
https://www.tutorialspoint.com/mongodb/mongodb_objectid.htm
How can you perform Arithmetic operations like +1 to String
nextSequenceNumber = new Long(itemDBObj.get("id").toString()) + 1;
Try to create a Sequence collection like this.
{"id":"MySequence","sequence":1}
Then use Update to increment the id
// Query for sequence collection
Query query = new Query(new Criteria().where("id").is("MySequence"));
//Increment the sequence by 1
Update update = new Update();
update.inc("sequence", 1);
FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
findAndModifyOptions.returnNew(true);
SequenceCollection sequenceCollection = mongoOperations.findAndModify(query, update,findAndModifyOptions, SequenceCollection.class);
return sequenceModel.getSequence();
I found the work around using b.collection.count().I simply find the total count and incremented by 1 to assign id to my object.
I'm working on modifying an existing application and I've decided to work with these 2 things.
My unmapped object is a simple object that consists of 2 integer properties:
public class EmployeeScore {
private int id;
private int score;
}
and I have a DAO which does the following:
public List<EmployeeScore> findEmployeeTotals(int regionId, int periodId) {
DataVerify.greaterThan(regionId, 0, "Invalid Region id: Region Id cannot be zero");
DataVerify.lessThan(regionId, 4, "Invalid Region id: Region id cannot be greater than 3");
List<EmployeeScore> results = (List<EmployeeScore>) currentSession().createSQLQuery(
"select n.EMP_ID, SUM(DISTINCT(nom.TOTAL_POINT)) from" +
" NOMINEE n join NOMINATION nom on nom.NOM_ID = n.NOM_ID" +
" join EMPLOYEE e on n.EMP_ID = e.EMP_ID" +
" join COMPANY c on c.COMPANY_CODE = e.COMPANY_CODE" +
" join REGION r on r.REGION_ID = c.REGION_ID" +
" where nom.PERIOD_ID = :periodId" +
" AND nom.STATUS_ID = 2" +
" AND e.ISACTIVE = 1" +
" AND nom.CATEGORY_CODE != 'H'" +
" AND r.REGION_ID = :regionId" +
" group by n.EMP_ID")
.setParameter("regionId", regionId)
.setParameter("periodId", periodId)
.list();
return results;
}
It's a huge query i know. I'm having problems on my tests and I assume because I'm not understanding how to apply these 2 correctly.
My test goes as follows:
#Test
#Transactional(isolation = Isolation.SERIALIZABLE)
public void testEmpScore() {
NomPeriod period = nomPeriodHibernateDAO.findById(6);
Region region = regionHibernateDAO.findById(1);
List<EmployeeScore> results = winnerHibernateDAO.findEmployeeTotals(region.getId(), period.getId());
results.toString();
Assert.assertEquals(13, results.size());
}
It should return 13 objects type EmployeeScore but instead it returns 0 so the test fails.
Can you point me in the right direction of what I'm doing wrong? I know it has to be something with my object seeing as it is not mapped but I have no way of mapping the score value or the id value since they reference different tables or aggregates.
Thanks.
The problem is that you are querying for two integers and trying to interpret them as EmployeeScores. Hibernate can do it but it will take a bit more work than that.
Assuming EmployeeScore has a constructor that takes two integers, you can try
select new my.package.EmployeeScore(n.EMP_ID, SUM(DISTINCT(nom.TOTAL_POINT))) ...
You need to give it the full package path to your object.
Alternatively, by default, I think the query will return a List<Object[]>. So you could iterate through these and form your employee scores manually.
List<Object[]> results = query.list();
List<EmployeeScore> scores = new LinkedList<EmployeeScore>();
for (Object[] arr : results)
{
int id = (int) arr[0];
int total = (int) arr[1];
scores.add(new EmployeeScore(id, total));
}