Invalidate and update the object from the cache with eclipselink - eclipselink

If i execute this query
#Modifying
#Query("delete from anomaly a where a.personId in ?1 and a.date in ?2 ")
void deleteByPersonIdAndDate(List<Long> personIds,
Collection<LocalDate> days);
How the objects affected by this query are deleted from the eclipselink-cache ?

Related

Using sub-select in FROM clause inside JPA #NamedQuery

In my app I need to use #NamedQuery to find the type of the most frequent operation assigned to specific account
#Entity
#Table(name="\"ACCOUNTOPERATION\"")
#NamedQuery(name="AccountOperation.findTypeOfMostFrequentOperation", query="" +
"SELECT ao.type from AccountOperation ao WHERE ao.account.id = ?1 " +
"GROUP BY ao.type HAVING COUNT(ao) = (" +
"SELECT MAX(typeCountQuery.typeCount) " +
"FROM (" +
"SELECT COUNT(aop) as typeCount " +
"FROM AccountOperation aop WHERE aop.account.id = ?1 GROUP BY aop.type" +
") as typeCountQuery" +
")"
)
public class AccountOperation {
#ManyToOne
private Account account;
private BigDecimal amount;
private OperationType type;
...
Right after FROM clause at '(' character, which begins typeCountQuery's body I'm getting
')', ',', GROUP, HAVING, IN, WHERE or identifier expected, got '('
I've read that JPA does not support sub-selects in the FROM clause, so is there any way to rewrite SQL code to still use it in #NamedQuery?
I'm using IntelliJ IDE with H2 DB and with eclipselink and javax.persistence in dependencies.
Link to source
In JPQL, you cannot use subqueries. To resolve this issue, you need to use some keywords like ALL, ANY, which work similiar.
So in your situation it could be:
#NamedQuery(name="AccountOperation.findTypeOfMostFrequentOperation", query="" +
"SELECT ao.type from AccountOperation ao WHERE ao.account.id = ?1 " +
"GROUP BY ao.type HAVING COUNT(ao) >= ALL (" +
"SELECT COUNT(aop) as typeCount " +
"FROM AccountOperation aop WHERE aop.account.id = ?1 GROUP BY aop.type)"
The type with a highest count returns the following query
select type
from AccountOperation
where id = ?
group by type
order by count(*) desc
fetch first 1 ROWS only
You should be anyway avare of the existence of ties, i.e. more types with the identical maximal count and should make some thought how to handle them.
I.e. in Oracle you may say fetch first 1 ROWS WITH TIES to get all the types with tha maximal count.

Unable to run CASE WHEN for array in Spring Boot repository

I am trying to run this
#Query(value = "SELECT t.*\n" +
"FROM tlm_trade t\n" +
"left join tlm_trade_nugget n\n" +
"on t.trade_nugget_id=n.id\n" +
"where \n" +
"(year(t.created_date) in (case when ?1 is null then year(t.created_date) else ?1 end))\n" +
";", nativeQuery = true)
List<TlmTrade> findByFilter(Set<Integer> year);
;
When I pass this as the argument
[2021,2020,2019]
Got this error instead
SQLException: Operand should contain 1 column(s)
Any idea what's wrong?
case when ... end is an expression, they evaluate to a single value.
In your example you are hoping that you could use a case expression to act as "dynamic sql". i.e. if ?1 is null, then insert the term "year(t.created_date)" but if ?1 is not null then insert ?1
You cannot do that.
It would make more sense to do this by branching before forming #Query, one branch for ?1 being null, and another which uses ?1
Also, avoid case expressions in where clauses, it is better to express filters in binary terms such as this, using parentheses where needed:
"where (?1 IS NULL AND year(t.created_date) = '2021' )\n"
?1 by the way will need to equal something, or be greater than something etc. ?1 by itself will not form a filtering condition.

JPQL query for updating an object

I am trying to update a variable named endDate, which is of type LocalDate, using jpql. My query is as follow:
#Modifying
#Query("UPDATE TeamEntity t SET t.coach.endDate = ?2 WHERE t.coach.id = ?1")
public void updateCoachEndDate(long coachId, LocalDate endDate);
part of TeamEntity class is as follow
#Entity
public class TeamEntity{
#ManyToOne
#JoinColumn(name = "coach_id", nullable = true)
private CoachEntity coach;
}
part of CoachEntity class is as follow
#Entity
public class CoachEntity{
#Id
private long id;
private LocalDate endDate
}
When I run a test for it, it seems that it doesn't like
r.coach.endDate = ?2
and it gives me the following error
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "UPDATE Team CROSS[*] JOIN SET END_DATE=? WHERE COACH_ID=? "; expected "., AS, SET"; SQL statement:
update team cross join set end_date=? where coach_id=? [42001-199]
I just wondering if anyone know how to fix this error.
Your descriptions don't match, i.e. I'm unsure where "staff" comes from. Anyhow:
The Hibernate documentation says:
No join, either implicit or explicit, can be specified in a bulk HQL
query. Sub-queries can be used in the where-clause, where the
subqueries themselves may contain joins.
And you have an implicit join in there between TeamEntity and Coach.
So, the next question is, why go through the TeamEntity anyway, since you have the coachId?
update Coach c set c.endDate = ?2 where c.id = ?1
Should do the trick

ebean query with subquery

I'm trying to do using EBean the equivalent of
select * from myTable1 where id not in (select id2 from myTable2) ;
I have no reference of table1 Object in table2 Object and the same the other way around.
Does anyone knows how to that using EBean ?
For the moment all I have is :
List<MyTable1> myResult = MyTable1.find.where().eq("id","1" ).findList();
Thanks.
C.C.
Apparently it has been possible to do this since 2009 using the example given in this bug report:
http://www.avaje.org/bugdetail-92.html
The example:
Query<Product> subQuery =
Ebean.createQuery(Product.class)
.select("sku")
.where().idEq(4).query();
List<MinCustomer> list = Ebean.find(MinCustomer.class)
.where().in("name", subQuery)
.findList();
However:
I am unable to make it work because the SQL generated is invalid. Seemingly due to a string replacement happening behind the scene in Ebean where (for me at least) the table name in the subquery is lost.
I expect it has to do with my main query includes a reference to the table from which my subquery "is selecting".
Turning the valid SQL from the example:
select c.id, c.name, c.notes
from o_customer c
where (c.name) in (select p.sku from o_product p where p.id = ? )
... into this invalid SQL in my case:
select t0.id as c0, ... t0.location_id as c8
from myRecordClass t0
where (t0.location_id) in (
select t0.id
from t0.location_id t0 # should be: from location t0
where t0.customer_id = ?
) and t0.creation > ?
order by t0.creation desc
The workaround:
Use the RawSql approach like in https://stackoverflow.com/a/27431625/190599 - example here:
String sql = "select b.id, b.location_id ... " +
"from myRecordClass b " +
"where location_id in (" +
"select id " +
"from location " +
"where customer_id = " + user.getCustomer().getId() +
") " +
"order by creation desc limit 10";
RawSql rawSql = RawSqlBuilder
.parse(sql)
.columnMapping("b.id", "id")
.columnMapping("b.location_id", "location.id")
....
.create();
Query<MyRecordClass> query = Ebean.find(MyRecordClass.class);
query.setRawSql(rawSql);
final List<MyRecordClass> list = query.findList();
I hardly believe that RawSql is fastest way to achieve this kind of query, it allows you to return list of mapped objects.
It's also possible to use SqlQuery (described in Reference guide (PDF)) to fetch a list of SqlRows - so you can find required data without any mapping at all.

NHibernate HQL could not locate named parameter [parameterName] error

I am having problems with my HQL query bellow:
var merchantTransactions = session.CreateQuery("SELECT MS.Transaction "+
"FROM MerchantSite AS MS "+
"INNER JOIN MS.Transaction AS MST"+
"WHERE MS.Site.Name = :merchantName");
Then I set parameters like this:
merchantTransactions.SetParameter("merchantName", merchantName);
And it gives me a "could not locate named parameter" error, any ideas why?
merchantName does exist in this context and all the table names are correct.
You are missing a space between MST and WHERE.
You have to use methods to create an HQL statment using a fluent interface style. Try something like this:
var merchantTransactions = session.CreateQuery("SELECT MS.Transaction "+
"FROM MerchantSite AS MS "+
"INNER JOIN MS.Transaction AS MST"+
"WHERE MS.Site.Name = :merchantName")
.SetParameter("merchantName", merchantName);
Or
merchantTransactions = merchantTransactions.SetParameter("merchantName", merchantName);
And do not forget to call a method to concrete your query.
var result = merchantTransactions.List<Entity>();