Related
i'm trying to extract data from the ANTLR parse tree, but not fully grasping how this should be done correctly
Let's say i have the following two SQL queries:
// language=SQL
val sql3 = """
CREATE TABLE session(
id uuid not null
constraint account_pk
primary key,
created timestamp default now() not null
)
""".trimIndent()
// language=SQL
val sql4 = """
CREATE TABLE IF NOT EXISTS blah(
id uuid not null
constraint account_pk
primary key,
created timestamp default now() not null
)
""".trimIndent()
Now i parse both of them:
val visitor = Visitor()
listOf(sql3, sql4).forEach { sql ->
val lexer = SQLLexer(CharStreams.fromString(sql))
val parser = SQLParser(CommonTokenStream(lexer))
visitor.visit(parser.sql())
println(visitor.tableName)
}
In my visitor if i visit the tableCreateStatement, i get the parse tree, but obviously just grabbing child1 will work for sql3, but not for sql4 since child1 in sql4 is IF NOT EXISTS
class Visitor : SQLParserBaseVisitor<Unit>() {
var tableName = ""
override fun visitCreate_table_statement(ctx: SQLParser.Create_table_statementContext?) {
tableName = ctx?.getChild(1)?.text ?: ""
super.visitCreate_table_statement(ctx)
}
}
Is there a way to find a specific token in the parse tree?
I'm assuming the payload has something to do with it, but since it's of type Any, i'm not sure what to check it against
override fun visitCreate_table_statement(ctx: SQLParser.Create_table_statementContext?) {
ctx?.children?.forEach {
if (it.payload.javaClass == SQLParser::Schema_qualified_nameContext) {
tableName = it.text
}
}
super.visitCreate_table_statement(ctx)
}
EDIT: the .g4 files are from
https://github.com/pgcodekeeper/pgcodekeeper/tree/master/apgdiff/antlr-src
this seems to work
override fun visitCreate_table_statement(ctx: SQLParser.Create_table_statementContext?) {
ctx?.children?.forEach {
if (it.payload.javaClass == Schema_qualified_nameContext::class.java) {
tableName = it.text
}
}
super.visitCreate_table_statement(ctx)
}
For branching trees
fun walkLeaves(
childTree: ParseTree = internalTree,
leave: (childTree: ParseTree) -> Unit) {
if (childTree.childCount == 0) {
if (!childTree.text?.trim().isNullOrBlank()) {
leave(childTree)
}
} else {
for (i in 0 until childTree.childCount) {
walkLeaves(childTree = childTree.getChild(i), leave = leave)
}
}
}
fun extractSQL(
childTree: ParseTree,
tokens: MutableList<String> = mutableListOf()
): String {
walkLeaves(childTree = childTree) { leave ->
tokens.add(leave.text)
}
...
}
I am trying to call a select query from my Java Program but i am getting Invalid Numbererror.
I am trying to call the query something like this
code
String[] l_arr = new String[]{"CUSTOMERCUMULATIVELIMIT"};
l_rs = JDBCEngine.executeQuery(MessageFormat.format(
" SELECT LIMITS, P.PACKAGE_ID FROM MSTGLOBALLIMITSPACKAGE P ,MSTCUSTOMERPROFILE C WHERE P.PACKAGE_ID = {0} AND C.ID_CUST = ? AND C.ID_ENTITY = ? AND C.TYPEUSER = ? AND C.ID_ENTITY = P.ID_ENTITY AND P.PACKAGE_ID NOT LIKE ?",l_arr );
I am getting query something like this:
Result
SELECT LIMITS, P.PACKAGE_ID
FROM MSTGLOBALLIMITSPACKAGE P, MSTCUSTOMERPROFILE C
WHERE P.PACKAGE_ID = CUSTOMERCUMULATIVELIMIT
AND C.ID_CUST = '00000144'
AND C.ID_ENTITY = 'B001'
AND C.TYPEUSER = 'ECU'
AND C.ID_ENTITY = P.ID_ENTITY
AND P.PACKAGE_ID NOT LIKE '*%'
I am getting the error Invalid number in the line P.PACKAGE_ID = {0}. I gone through and come to know that if i use to_char i can avoid this error. But I am not sure how to use to_char in P.PACKAGE_ID = {0}.
Also PACKAGE_ID is of type Varchar2 and CUSTOMERCUMULATIVELIMIT is a column in MSTCUSTOMERPROFILE of type Number.
Any help or suggestion will be appreciated. Thanks.
just add to_char to your sql, change {0} to to_char({0})
l_rs = JDBCEngine.executeQuery(MessageFormat.format( " SELECT LIMITS, P.PACKAGE_ID FROM MSTGLOBALLIMITSPACKAGE P ,MSTCUSTOMERPROFILE C WHERE P.PACKAGE_ID = to_char({0}) AND C.ID_CUST = ? AND C.ID_ENTITY = ? AND C.TYPEUSER = ? AND C.ID_ENTITY = P.ID_ENTITY AND P.PACKAGE_ID NOT LIKE ?",l_arr );
You are working with this line :
WHERE P.PACKAGE_ID = CUSTOMERCUMULATIVELIMIT
As there are no single quotes, SQL consider CUSTOMERCUMULATIVELIMIT as a number, not a string.
Adding quotes should solve this.
l_rs = JDBCEngine.executeQuery(MessageFormat.format(
" SELECT LIMITS, P.PACKAGE_ID FROM MSTGLOBALLIMITSPACKAGE P ,MSTCUSTOMERPROFILE C WHERE P.PACKAGE_ID = '{0}' AND C.ID_CUST = ? AND C.ID_ENTITY = ? AND C.TYPEUSER = ? AND C.ID_ENTITY = P.ID_ENTITY AND P.PACKAGE_ID NOT LIKE ?",l_arr );
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!
Is it possible to query a firestore collection to get all document that starts with a specific string?
I have gone through the documentation but do not find any suitable query for this.
You can but it's tricky. You need to search for documents greater than or equal to the string you want and less than a successor key.
For example, to find documents containing a field 'foo' staring with 'bar' you would query:
db.collection(c)
.where('foo', '>=', 'bar')
.where('foo', '<', 'bas');
This is actually a technique we use in the client implementation for scanning collections of documents matching a path. Our successor key computation is called by a scanner which is looking for all keys starting with the current user id.
same as answered by Gil Gilbert.
Just an enhancement and some sample code.
use String.fromCharCode and String.charCodeAt
var strSearch = "start with text here";
var strlength = strSearch.length;
var strFrontCode = strSearch.slice(0, strlength-1);
var strEndCode = strSearch.slice(strlength-1, strSearch.length);
var startcode = strSearch;
var endcode= strFrontCode + String.fromCharCode(strEndCode.charCodeAt(0) + 1);
then filter code like below.
db.collection(c)
.where('foo', '>=', startcode)
.where('foo', '<', endcode);
Works on any Language and any Unicode.
Warning: all search criteria in firestore is CASE SENSITIVE.
Extending the previous answers with a shorter version:
const text = 'start with text here';
const end = text.replace(/.$/, c => String.fromCharCode(c.charCodeAt(0) + 1));
query
.where('stringField', '>=', text)
.where('stringField', '<', end);
IRL example
async function search(startsWith = '') {
let query = firestore.collection(COLLECTION.CLIENTS);
if (startsWith) {
const end = startsWith.replace(
/.$/, c => String.fromCharCode(c.charCodeAt(0) + 1),
);
query = query
.where('firstName', '>=', startsWith)
.where('firstName', '<', end);
}
const result = await query
.orderBy('firstName')
.get();
return result;
}
If you got here looking for a Dart/Flutter version
Credit to the java answer by Kyo
final strFrontCode = term.substring(0, term.length - 1);
final strEndCode = term.characters.last;
final limit =
strFrontCode + String.fromCharCode(strEndCode.codeUnitAt(0) + 1);
final snap = await FirebaseFirestore.instance
.collection('someCollection')
.where('someField', isGreaterThanOrEqualTo: term)
.where('someField', isLessThan: limit)
.get();
I found this, which works perfectly for startsWith
const q = query(
collection(firebaseApp.db, 'capturedPhotos'),
where('name', '>=', name),
where('name', '<=', name + '\uf8ff')
)
The above are correct! Just wanted to give an updated answer!
var end = s[s.length-1]
val newEnding = ++end
var newString = s
newString.dropLast(1)
newString += newEnding
query
.whereGreaterThanOrEqualTo(key, s)
.whereLessThan(key, newString)
.get()
I'm developing software which allows a user to select dynamically one or several users from a database using jpa/Criteria.
Edits/updates:
-I now use a growing predicate with ands. The problem is that i'm not indicating the right field but instead just a string in which java is looking for what th user has entered.
-I still have to check how i can work with pathes as i've been advised to do.
When an user inputs d as PC_Name, d as Name and c as Vorname, the verbose eclipselink shows me this:
[EL Fine]: sql: 2012-07-25 15:44:13.173--ServerSession(24105143)--Connection(13480046)--Thread(Thread[main,5,main])--SELECT PERSONALNUMMER, GEBURTSTAG, GRUPPE, IP, MOBIL, NAME, PC_NAME, TELEFON, VORNAME FROM MITARBEITERTABELLE WHERE ((? LIKE ? AND ? LIKE ?) AND ? LIKE ?)
bind => [PC_Name, %d%, Name, %b%, Vorname, %c%]
This confirms what i'm saying, when i input n as name, i get the entire database because n always belongs to name..
End of edits/updates
Here is the sql version which works:
try{
String selectString ="SELECT * FROM mitarbeitertabelle WHERE ";
selectString=StringModulierung(selectString);
PreparedStatement selectMitarbeiter = con.prepareStatement(selectString);
int i =1;
if(isNameSuche()){selectMitarbeiter.setString (i,this.wc+_Name+this.wc); i++;}
if(isVornameSuche()){ selectMitarbeiter.setString (i, this.wc+_Vorname+this.wc); i++;}
if(isPersonalnummerSuche()){selectMitarbeiter.setString (i, this.wc+_Personalnummer+this.wc); i++;}
if(isPC_NameSuche()){selectMitarbeiter.setString (i, this.wc+_PC_Name+this.wc); i++;}
if(isIPSuche()){selectMitarbeiter.setString (i, this.wc+_IP+this.wc); i++;}
if(isTelefonSuche()){ selectMitarbeiter.setString (i, this.wc+_Telefon+this.wc); i++;}
if(isGeburtstagSuche()){selectMitarbeiter.setString (i, this.wc+_Geburtstag+this.wc); i++;}
if(isGruppeSuche()){ selectMitarbeiter.setString (i, this.wc+_Gruppe+this.wc); i++;}
if(isMobilSuche()){ selectMitarbeiter.setString (i, this.wc+_Mobil+this.wc); i++;}
System.out.println(selectMitarbeiter.toString());
ResultSet ergebnis=selectMitarbeiter.executeQuery();`
with:
public String StringModulierung(String str){
boolean erster=true;
if(isNameSuche()){ str=str.concat("Name LIKE ? ");
erster=false;
}
if(isVornameSuche()){ if(erster){str=str.concat("Vorname LIKE ? ");erster=false;
}else{str=str.concat("AND Vorname LIKE ? ");}
}
if(isPersonalnummerSuche()){ if(erster){str=str.concat("Personalnummer LIKE ? ");erster=false;
}else{str=str.concat("AND Personalnummer LIKE ? ");}
}
if(isPC_NameSuche()){ if(erster){str=str.concat("PC_Name LIKE ? ");erster=false;
}else{str=str.concat("AND PC_Name LIKE ? ");}
}
if(isIPSuche()){ if(erster){str=str.concat("IP LIKE ? ");erster=false;
}else{str=str.concat("AND IP LIKE ? ");}
}
if(isTelefonSuche()){ if(erster){str=str.concat("Telefon LIKE ? ");erster=false;
}else{str=str.concat("AND Telefon LIKE ? ");}
}
if(isGeburtstagSuche()){ if(erster){str=str.concat("Geburtstag LIKE ? ");erster=false;
}else{str=str.concat("AND Geburtstag LIKE ? ");}
}
if(isGruppeSuche()){ if(erster){str=str.concat("Gruppe LIKE ? ");erster=false;
}else{str=str.concat("AND Gruppe LIKE ? ");}
}
if(isMobilSuche()){ if(erster){str=str.concat("Mobil LIKE ? ");erster=false;
}else{str=str.concat("AND Mobil LIKE ? ");}
}
return str;
}
Here's what i've done with jpa:
CriteriaBuilder cb = EM.getCriteriaBuilder();
CriteriaQuery<Mitarbeiter2> q = cb.createQuery(Mitarbeiter2.class);
Root<Mitarbeiter2> mit= q.from(Mitarbeiter2.class);
ParameterExpression<String> pc_name = cb.parameter(String.class,"PC_Name_p");
ParameterExpression<String> ip = cb.parameter(String.class,"IP_p");
ParameterExpression<String> pers_num = cb.parameter(String.class,"Personalnummer_p");
ParameterExpression<String> name = cb.parameter(String.class,"Name_p");
ParameterExpression<String> vorname = cb.parameter(String.class,"Vorname_p");
ParameterExpression<String> telefon = cb.parameter(String.class,"Telefon_p");
ParameterExpression<String> geburtstag = cb.parameter(String.class,"Geburtstag_p");
ParameterExpression<String> gruppe = cb.parameter(String.class,"Gruppe_p");
ParameterExpression<String> mobil = cb.parameter(String.class,"Mobil_p");
Predicate p = cb.conjunction();
if(isPC_NameSuche()){
p = cb.and(p, cb.like(pc_name, this.getWc()+_PC_Name+this.getWc() ));
}
if(isIPSuche()) {
p = cb.and(p, cb.like(ip,this.getWc()+_IP+this.getWc()));
}
if(isPersonalnummerSuche()) {
p = cb.and(p, cb.like(pers_num, this.getWc()+_Personalnummer+this.getWc() ));}
if(isNameSuche()){
p = cb.and(p, cb.like(name, this.getWc()+_Name+this.getWc()));
}
if(isVornameSuche()) {
p = cb.and(p, cb.like(vorname, this.getWc()+_Vorname+this.getWc()));}
if(isTelefonSuche()) {
p = cb.and(p, cb.like(telefon, this.getWc()+_Telefon+this.getWc() ));}
if(isGeburtstagSuche()){
p = cb.and(p, cb.like(geburtstag, this.getWc()+_Geburtstag+this.getWc()));}
if(isGruppeSuche()) {
p = cb.and(p, cb.like(gruppe, this.getWc()+_Gruppe+this.getWc()));}
if(isMobilSuche()) {
p = cb.and(p, cb.like(mobil, this.getWc()+_Mobil+this.getWc()));}
q.where(p);
q.select(mit);
TypedQuery<Mitarbeiter2> tq = EM.createQuery(q);
tq.setParameter("PC_Name_p", "PC_Name"); // searches this.getWc()+_Mobil+this.getWc() in PC_Name !
tq.setParameter("IP_p", "IP");
tq.setParameter("Personalnummer_p", "Personalnummer");
tq.setParameter( name/**entered by user*/, "Name"/**should be the field */);
tq.setParameter("Vorname_p", "Vorname");
tq.setParameter("Telefon_p", "Telefon");
tq.setParameter("Geburtstag_p","Geburtstag" );
tq.setParameter("Gruppe_p", "Gruppe");
tq.setParameter("Mobil_p" ,"Mobil");
List<Mitarbeiter2> ergebnis= tq.getResultList();
I've incorporated the two following solutions:
In order to add dynamically where conditions, you can either use a
List where each Predicate is defined like this:
> Predicate p = cb.like(...);
or you can modify dynamically a single Predicate like this:
> Predicate p = cb.conjunction(); for ( filter : filters) {
> p = cb.and(p, cb.like(...)); }
and
When you do q.where you set the WHERE expression.
It does not append, meaning, the last q.where you invoked is the one
set for the query.
What you need to do is build a Boolean Expression (I think ANDs is
what you want).
Then at the and user q.where to set the expression.
Thanks for your help ;) .
Harald
The two problems i had were these:
1) How to build dynamically a query with Criteria , in order to get a query like (in SQL) this(with many different predicates)?
SELECT * FROM mitarbeitertabelle where (1) like (2) and (3) like (4) ...
This means that at runtime, the user can select one or several criteria he'll use to search an mitarbeiter(german for employee).
2)How to set a link to the attributes of my object?
1) In order to do this, you have to build a predicate, using a predicate which is modified at each adding of a new predicate if the criterion is selected.
p= criteriabuilder.and(p, criteriabuilder.like(path object linking to the right attribute, String s used for the search));
2) The right path enables us to have a link to the right attribute. I use it above. Here, the thing is that without pathes, it is not possible to have a link to your attributes so far i know ;) .
After that, you simply have to achieve your sql command by adding the where clause which takes the predicate as a parameter and the select clause which takes the root(where we'll search in the database) as a parameter:
q.where(p);
q.select(mit);
Then , get your results:
List<Mitarbeiter2> ergebnis= EM.createQuery(q).getResultList();
Theere is no need to fill and use parameterexpression objects, because i am not using parameterexpression objects. The string used to search is set directly in the like clause at runtime execution.
The entire code(with my variables,names,..) is:
CriteriaBuilder cb = EM.getCriteriaBuilder();
CriteriaQuery<Mitarbeiter2> q = cb.createQuery(Mitarbeiter2.class);
Root<Mitarbeiter2> mit= q.from(Mitarbeiter2.class);
Path<String> pc_name2 = mit.get("PC_Name");
Path<String> ip2 = mit.get("IP");
Path<String> pers_num2 = mit.get("Personalnummer");
Path<String> name2 = mit.get("Name");
Path<String> vorname2 = mit.get("Vorname");
Path<String> telefon2 = mit.get("Telefon");
Path<String> geburtstag2 = mit.get("Geburtstag");
Path<String> gruppe2 = mit.get("Gruppe");
Path<String> mobil2 = mit.get("Mobil");
Predicate p = cb.conjunction();
if(isPC_NameSuche()){
p = cb.and(p, cb.like(pc_name2, this.getWc()+_PC_Name+this.getWc() ));
}
if(isIPSuche()) {
p = cb.and(p, cb.like(ip2,this.getWc()+_IP+this.getWc()));
}
if(isPersonalnummerSuche()) {
p = cb.and(p, cb.like(pers_num2, this.getWc()+_Personalnummer+this.getWc() ));}
if(isNameSuche()){
p = cb.and(p, cb.like(name2, this.getWc()+_Name+this.getWc()));
}
if(isVornameSuche()) {
p = cb.and(p, cb.like(vorname2, this.getWc()+_Vorname+this.getWc()));}
if(isTelefonSuche()) {
p = cb.and(p, cb.like(telefon2, this.getWc()+_Telefon+this.getWc() ));}
if(isGeburtstagSuche()){
p = cb.and(p, cb.like(geburtstag2, this.getWc()+_Geburtstag+this.getWc()));}
if(isGruppeSuche()) {
p = cb.and(p, cb.like(gruppe2, this.getWc()+_Gruppe+this.getWc()));}
if(isMobilSuche()) {
p = cb.and(p, cb.like(mobil2, this.getWc()+_Mobil+this.getWc()));}
q.where(p);
q.select(mit);
List<Mitarbeiter2> ergebnis= EM.createQuery(q).getResultList();
Thank you very much for your help #perissf and #aviram-segal ! Don't hesitate to comment if you think something isn't easy to understand in my answer.
When you do q.where you set the WHERE expression.
It does not append, meaning, the last q.where you invoked is the one set for the query.
What you need to do is build a Boolean Expression (I think ANDs is what you want).
Then at the and user q.where to set the expression.
In your equal clauses, you are using this expression:
ParameterExpression<String> pc_name = cb.parameter(String.class,"PC_Name");
Try instead this:
Path<Mitarbeiter2> pc_name = mit.get("PC_Name");
Or, using Metamodel generated classes,
Path<Mitarbeiter2> pc_name = mit.get(Mitarbeiter2_.pc_name);
I cannot test the Path expressions right now, but I am sure that the following works:
q.where(cb.like(mit.get("PC_Name"), pc_name));
or:
q.where(cb.like(mit.get(Mitarbeiter2_.pc_name), pc_name));
In order to add dynamically where conditions, you can either use a List<Predicate> where each Predicate is defined like this:
Predicate p = cb.like(...);
or you can modify dynamically a single Predicate like this:
Predicate p = cb.conjunction();
for ( filter : filters) {
p = cb.and(p, cb.like(...));
}
Finally, if you are comparing strings, don't forget to transform everything to the same case, before doing the comparison.