JPA namedQuery: select delivers only first entry - named-query

this is my problem:
I have a DB-table like:
CFG_NAME | CFG_CLASS_NAME
cfg1 | class1
cfg1 | class2
cfg1 | class3
an my namedQuery is:
#NamedQuery(name = "getCfgClassByName", query = "SELECT e FROM CfgClasses e WHERE e.cfgName = :name") })
my select looks like this:
TypedQuery namedQuery = em.createNamedQuery("getCfgClassByName", CfgClasses.class).setParameter("name", "cfg1");
List result = tq.getResultList();
result -> only one entry (the first in the table)
where is my fault?

Related

TypeScript Sequelize : How to join two tables with common

There are three tables.
Tables :
Trip
id | start_destination_id | end_destination_id | arrive_time |
-------------------------------------------------------------------
1 | S | E | 09:00 |
Destination
id | name
---------
S | Start
E | End
Schedule
id | start_destination_id | end_destination_id | should_arrive |
-------------------------------------------------------------------
1 | S | E | 08:00 |
2 | A | E | 10:00 |
Query
SELECT
Trip.*,
Schedule.should_arrive
FROM
Trip
LEFT JOIN
Schedule
ON
Trip.start_destination_id = Schedule.start_destination_id
AND
Trip.end_destination_id = Schedule.end_destination_id
I am trying to include Schedule in Trip.findAll but receive error
Exception: SequelizeEagerLoadingError: Schedule is not associated to Trip!
Is there a way that I can join them together without using foreign keys and raw queries?
Many thanks.
Finally I found a solution (not sure if it is a hack).
Schedule.ts
// add these lines
...
#ForeignKey(() => Trip)
#Column({ type: DataType.VIRTUAL })
private _dummyForTrip: undefined;
...
Then create an association between Schedule and Trip.
Trip.ts
#HasMany(() => Schedule)
public schedules: Schedule[] | null
Then you can include Schedule inside Trip by using include.on
const trips = await Trip.findAll({
include: [{
model: Schedule,
on: {
'$schedules.start$': { [Op.col]: "Trip.start_destination" },
'$schedules.end$': { [Op.col]: "Trip.end_destination" },
}
}],
where: {
id: { [Op.in]: payload.inputTripIdArr }
}
});

Linq-like group by for sql

It seems like sql group by is more of aggregate functions (COUNT, MAX, MIN, SUM, AVG).
select count(Id), Country
from Customer
where Country <> 'CountryX'
group by Country
But do we have a linq-like query where we want to return all results grouped by a certain column, E.g. in linq I would do
id | title | category | email
------------------------------------------
1 | tname-1 | cat1 | test#example.com
2 | tname-2 | cat1 | test1#example.com
3 | tname-3 | cat2 | TEst#example.com
linq group-by:
var groupedBy = list.GroupBy(item => item.Email);
or even throw in some comparison
var groupedBy = list.GroupBy(item => item.Email, StringComparer.OrdinalIgnoreCase);
and a result will be something like:
key | items
----------------------------------------------------------------------------------------------
test#example.com | [{Id :1, Title : "tname-1", category: "cat1", email: "test#example.com" },{Id :3, Title : "tname-3", category: "cat2", email: "TEst#example.com" } ]
test1#example.com| [{Id :2, Title : "tname-2", category: "cat1", email: "test1#example.com" }]
but with sql I would definitely want to return only the subset of the columns, say id, title and email.

Codeigniter merge into one row record with sql one to many relationship

I would like to query one to many relationship
eg:
Table A: Table B:
id | country_name id | name | table_A_id
1 | Usa 1 | kerry | 1
2 | Australia 2 | jerry | 1
3 | tommy | 2
4 | cherry | 2
my purpose is to query the result to merge one row record
eg: result list:
1 Record 2 Record
Usa Australia
kerry tommy
jeryy cherry
Currently, I am using Codeignter framework and beginner for sql, please don't mind me guys.
$this->db->select('*')
>from("table A")
->join("table B", "table.A.id = table_A_id");
$query = $this->db->get();
if($query->num_rows() > 0) {
return $query->result();
}
My view
<?php foreach($posts as $post) {
echo $post->country_name;
echo $post->name;
} ?>
However, it gives me 4 row records.
1 Record 2 Record
Usa Usa
kerry jerry
3 Record 4 Record
Australia Australia
tommy cherry
Thanks you guys in advance for helping me.
Here is what you missed
$this->db->select('*')
>from("table A")
->join("table B", "table.A.id = table_A_id");
$query = $this->db->get();
if($query->num_rows() > 0) {
return $query->result();
}
it should have been
->join("table B", 'B.table_A_id=A.id');
hope this make sense
option B
$this->db->join('table B','B.table_A_id=A.id','INNER');
$query = $this->db->get('table A');
Try out this
SELECT country, group_concat(name) FROM city c INNER JOIN employee e
ON c.id = e.city_id group by c.id
output
('USA ' , 'jerry ,kerry'),
('Australia', 'cherry ,tommy');
My solution found without using inner join:
public function mergeRecord() {
$array_store = array();
foreach($this->one() as $row) {
$child = $this->many($row['id']);
if($child) {
$return = array_merge(array("parent" => $row), array("child" =>$child));
array_push($array_store, $return);
}
}
return $array_store;
}
public function one() {
$query = $this->db->select("*")
->get("table A")
->result_array();
return $query;
}
public function many($id) {
$query = $this->db->select("id, name")
->where("table_A_id", $id)
->get("table B")
->result_array();
return $query;
}

Substring search a numeric field with JPA/Hibernate

I have a JPA entity that has a numeric field. Something like:
#Basic(optional = false)
#Column(name = "FISCAL_YEAR", nullable = false)
private int fiscalYear;
I have a requirement to sub-string search this field. For example, I want a search for 17 to give me 2017 and 1917 and 1789. Forget for a minute what a crazy request this is and assume I have a real use case that makes sense. Changing the column to a varchar in the database is not an option.
In PL/SQL, I'd covert the field to a varchar and do a like '%17%'. How would I accomplish this with Hibernate/JPA without using a native query? I need to be able to use HQL or Criteria to do the same thing.
Achieving like on numeric values using criteria builders
Table
Employee | CREATE TABLE `Employee` (
`id` int(11) NOT NULL,
`first` varchar(255) DEFAULT NULL,
`last` varchar(255) DEFAULT NULL,
`occupation` varchar(255) DEFAULT NULL,
`year` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Entity
private Integer year;
public Integer getYear() {
return year;
}
public void setYear(Integer year) {
this.year = year;
}
Data in the table
+----+-------+------+------------+------+
| id | first | last | occupation | year |
+----+-------+------+------------+------+
| 2 | Ravi | Raj | Textile | 1718 |
| 3 | Ravi | Raj | Textile | 1818 |
| 4 | Ravi | Raj | Textile | 1917 |
| 5 | Ravi | Raj | Textile | NULL |
| 6 | Ravi | Raj | Textile | NULL |
| 7 | Ravi | Raj | Textile | NULL |
+----+-------+------+------------+------+
constructing query using criteria builder
public List<Employee> getEmployees() {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
Root<Employee> emp = q.from(Employee.class);
Predicate year_like = cb.like(emp.<Integer>get("year").as(String.class), "%17%");
CriteriaQuery<Employee> fq = q.where(year_like);
List<Employee> resultList = (List<Employee>) entityManager.createQuery(fq).getResultList();
return resultList;
}
query generated(using show_sql: true)
Hibernate: select employee0_.id as id1_0_, employee0_.first as first2_0_, employee0_.last as last3_0_, employee0_.occupation as occupati4_0_, employee0_.year as year5_0_ from Employee employee0_ where cast(employee0_.year as char) like ?
Query Output
// i have printed only id and year in the console
id, year
2, 1718
4, 1917
------------------------------------------------------------
Alternate way
LIKE worked in JPA for numeric field when Tested with JPA, hibernate, mysql.
Note:- May not work with other jpa providers
Query r = entityManager.createQuery("select c from Employee c where c.year like '%17%'");
query fired(using show_sql=true)
Hibernate: select employee0_.id as id1_0_, employee0_.first as first2_0_, employee0_.last as last3_0_, employee0_.occupation as occupati4_0_, employee0_.year as year5_0_ from Employee employee0_ where employee0_.year like '%17%'
Query Result
// i have printed only id and year in the console
id, year
2, 1718
4, 1917
You can declare your own Criterion type
public class CrazyLike implements Criterion {
private final String propertyName;
private final int intValue;
public CrazyLike(String propertyName, int intValue) {
this.propertyName = propertyName;
this.intValue = intValue;
}
#Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
if ( columns.length != 1 ) {
throw new HibernateException( "Crazy Like may only be used with single-column properties" );
}
final String column = columns[0];
return "cast(" + column + " as text) like '%" + intValue + "%'";
}
#Override
public TypedValue[] getTypedValues(Criteria criteria,
CriteriaQuery criteriaQuery) throws HibernateException {
return new TypedValue[] { };
}
}
And then use it like this:
Criteria criteria = session.createCriteria(Person.class);
List<Person> persons = criteria.add(new CrazyLike("year", 17)).list();
assuming that Person has an int property called year. This should produce a SQL like this:
select
this_.id as id1_2_0_,
this_.birthdate as birthdat2_2_0_,
this_.firstname as firstnam3_2_0_,
this_.lastname as lastname4_2_0_,
this_.ssn as ssn5_2_0_,
this_.version as version6_2_0_,
this_.year as year7_2_0_
from
Person this_
where
cast(this_.year as text) like '%17%'
This was tested with Postgres. The cast() syntax may vary for your database engine. If it is, just use that syntax in the Criterion class that you implement.

Hibernate/SQL: Selecting records only if exist in one-to-many relationship, returns too many

In my app, I have 2 tables, Settlement Result and Settlement State
Settlement Result contains some basic data like name, type etc.
SettlementState is the "many" side of relatioship with Settlement Result and consist of Settlement Result PK and Status as Many-To-One ID as PK and a date. Example data:
Settlement Result
------------------------------
ID| Name | Sth
------------------------------
1 | Some Name | Something more
2 | Name2 | more2
Settlement State
----------
Result's ID | StatusId | Date
------------------------------
1 | 1 | some date
1 | 2 | date
1 | 3 | date
2 | 1 | date
Now I wish to select with HQL/Plain SQL that rows from Settlement Result, that have for example Status Id == 3, but not any with higher ID.
There are few possible statuses:
Status ID | Desc
-----------------
1 | Created
2 | Confirmed
3 | Accepted
4 | Rejected
When we are creating SettlementResult, there's always some "workflow". Firstly, Result has status Created (ID 1). Then it can be Rejected(ID 4) or Confirmed (ID 2). Then again we can Accept it or Reject.
So one SettlementResult can have SettlementStates with Status ID of 1,2,4 (Created, Confirmed, but not Accepted=Rejected).
The problem is, that I want to select only those SettlementResults which have certain status (for examle Created)."
With HQL query like this:
Query query = session.createSQLQuery( "select distinct s from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );
It returns every Settlement Result, even those with Statuses 1,2,3 (cause collection contains the one with ID equal to created).
Is it possible to select ONLY those Settlement Results which have ONLY certain status for example if we want Created[ID 1], we get all with Settlement State status of 1 only, without 2,3 or 4 status. When we choose to select those with status id 3, we can accept if it has Settlement State with status id = 1,2,3 but NOT 4. Some kind of max[status.id]?
#Entity
#Table(name = "SETTLEMENT_STATE")
public class SettlementState
{
#EmbeddedId
private SettlementStatePK settlementStatePK;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "STATUS_DTTM")
private Date statusDate;
}
#Embeddable
public class SettlementStatePK implements Serializable
{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STATUS_ID")
private Status status;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SETTLEMENT_RESULT_ID")
private SettlementResult settlementResult;
}
#Entity
#Table(name = "SETTLEMENT_RESULT")
public class SettlementResult implements Serializable
{
#Id
#Column(name = "SETTLEMENT_RESULT_ID")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STATUS_ID")
private Status status;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "MODEL_GROUP_ID")
private SettlementModelGroup settlementModelGroup;
#Column(name = "\"MODE\"")
private Integer mode;
#Column(name = "CREATED_DTTM")
private Date createdDate;
#Column(name = "DESCRIPTION")
private String description;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "settlementStatePK.settlementResult")
private List<SettlementState> settlementStates;
}
You have two options here:
If you see your query you are fetching SettlementResult objects
Query query = session.createSQLQuery( "select distinct s from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );
Your query is perfect but once you have parent object SettlementResult and you access OneToMany collection settlementStates, hibernate will load all of them on the basis of SettlementResult P.K. (This is what you have observed as well).
So Option-1:
Go through Child to Parent
This means return SettlementState objects from your query as:
Query query = session.createSQLQuery( "select distinct states from SettlementResult s join s.settlementStates states where states.settlementStatePK.status.statusId == 1" );
And then you can access SettlementResult from state object, because you have defined ManyToOne for SettlementResult in SettlementState class. In this case you will definitely have those SettlementResult objects what you are looking for.
Option-2: Divide your SettlementState objects
Option 1 will work for you but this solution might seem odd to you. So the best way to resolve this problem is you can divide Settlement State objects (as described in your problem)
1. RejectedSettlementState
2. NonRejectedSettlementState
These two classes will extend one base abstract class (SettlementState). You can define discriminator formula on status id. Once you have these classes then you can associate these subclasses into SettlementResult. Here are classes you need (sudo)
#DiscriminatorForumla("case when status_id == 4 then "REJECTEDSTATE" else "NONREJECTEDSTATE" end")
public abstract class SettlementState{
...
// Define all of your common fields in this parent class
}
#DiscriminatorValue("REJECTEDSTATE")
public class RejectedSettlementState extends SettlementState{
...
// define only fields specific to this rejected state
}
#DiscriminatorValue("NOTREJECTEDSTATE")
public class NonRejectedSettlementState extends SettlementState{
...
// define only fields specific to this non-rejected state
}
Now the SettlementResult class
public class SettlementResult{
#OneToMany(fetch = FetchType.LAZY, mappedBy = "settlementStatePK.settlementResult")
private List<RejectedSettlementState> rejectedSettlementStates;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "settlementStatePK.settlementResult")
private List<NonRejectedSettlementState> nonRejectedSettlementStates;
}
So once you have all these objects. Then you don't need query on status. You simply load the parent object SettlementResult and then access your rejected or non-rejected settlement states. Hibernate will use formula condition to initialize these collections using lazy load as defined in SettlementResult class.
Note
Both solutions to me are acceptable, it depends which one you will like in your system to be there. Second option gives you more edges for future.
Any more info: please ask! I have tried my best to get you through this idea :). Good Luck!