Check value of field of argument in Drools query - drools

How would I check the value of an argument's field in a Drools query?
I have a Contract Java class I'm passing to the query:
public class Contract {
... other vars
private prodContractNum;
public String getProdContractNum() {
return prodContractNum;
}
... other getters
}
and I'd like to check the equality of the prodContractNum field. I've tried:
query checkContractNum(Contract contract)
contract := Contract(prodContractNum == "D");
end
but that's not matching any of my Contract inputs. Any suggestions?

Related

JPQL Query - No constructor taking error?

I have a Card entity class with many columns.
I used dto because I want to get some columns from this Entity.
I created a DTO class and wrote a query to CardRepositoryCustom.
But when I try to run the Query I get various errors "No constructor taking".
My dto class:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CardDTO {
private String test1;
private String test2;
private String test3;
private String test4;
}
JPQL RepositoryCustom :
#Repository
#Transactional
public class CardRepositoryCustom {
public CardDTO test1() {
JpaResultMapper jpaResultMapper = new JpaResultMapper();
String q = "SELECT "+
" c.test1 "+
"FROM "+
" CardEntity c ";
Query query = entityManager.createQuery(q);
try {
return jpaResultMapper.uniqueResult(query, CardDTO.class);
} catch (NoResultException nre) {
return null;
}
}
}
Errors:
java.lang.RuntimeException: No constructor taking: java.lang.String
at org.qlrm.mapper.JpaResultMapper.findConstructor(JpaResultMapper.java:107) ~[qlrm-1.7.1.jar:na]
at org.qlrm.mapper.JpaResultMapper.uniqueResult(JpaResultMapper.java:64) ~[qlrm-1.7.1.jar:na]
at ....
I know how to fix this error.
You just need to write the following constructor in the DTO class as shown below.
public CardDTO(String test1) {
this.setTest1(test1);
}
Here I am curious, if I want test2, test3, test4 and write Query in Custom class, should there be as many constructors in DTO class as that number?
I think this method is really inefficient. Is there any solution I am not aware of?
This seems to be more about QLRM than JPA or Spring.
Judging from the error message the constructor has to match the arguments provided. Probably the easiest variant is to always provide all arguments, possibly with a value of null or some other literal.
The query in your example would then become.
SELECT c.test1, null, null, null FROM CardEntity c
Of course QLRM just provides a JpaResultMapper and it would probably not too difficult to provide your own, or offer a PR to QLRM that inspects names of the result set and tries to match them to parameter names or the constructor.

Is there a way to query by superclass id using JPA Criteria, Specification and metamodel?

I have classes Car that has field Driver driver and Driver that inherites from Employee. Employee has field id.
I have to find and provide to frontend the driver's id for the car using JPA Criteria and metamodel. It turnes out difficult because id is inherited from superclass. The query should be made by:
public static <U, T, P> Specification<U> isEqualTo(SingularAtribute<U, T> joinField, SingularAtribute<T, P>, field, P param{
if (param == null){
return null;
}
return (root, query, cb) -> cb.equal(root.join(joinField).get(field), param);
}
However when I want to use it in:
static Specification<Car> hasDriverId(Long value){
return isEqualTo(Car_.driver, Driver_id, value);
}
I get error:
method isEqualTo cannot be aplied to given types;
required: SingularAtribute<U,T>, SingularAtribute<T,P>, P
found: SingularAtribute<Car, Driver>, SingularAtribute<Employee, Long>, Long
reason: inference variable T has incompatible equality constraints Employee, Driver
I know that inheritance can cause problems in ORM however I cannot change it in project. Is there way to overcome this?

How to add element to array with Drools (mvel)

I need insert a new value in a exist array with Drools. My example:
rule "insert new address"
dialect "java"
when
$data : Data( source.address != null)
then
Address address = (Address) $data.source.address
System.out.println("Element: "+address );
$data.target.addressList.add(address);
end
The error that happend is this:
Exception executing consequence for rule "insert new address" in rules: [Error: $data.target.addressList.add(address): null]
EDIT: Added the model
public class Data {
private Source source;
private Client target;
}
public class Source {
...
private Address address;
}
public class Client {
...
private List<Address> addressList;
}
In answer to the question in your title, which is how to add an element to array -- the answer is basically "the same way you would in Java."
To answer the question you actually asked, which has no arrays, your error is effectively a NullPointerException, or another indicator that the field cannot be modified (eg an immutable list.)
This:
Error: $data.target.addressList.add(address): null]
Means that either $data.target or $data.target.addressList is null, or possibly $data.target.addressList is an immutable list.
Make sure that whatever "target" is has been initialized, and that its "addressList" is also initialized as a mutable list type.

JPA 2.0 IllegalArgumentException on existing entities and populated DB value

I am trying to return a string from a table based on a conditional ID (subid) from an already populated table. The query should return a list of type ItemDataPoint entity. In a JSF managed bean, the list will the be iterated by a an enhaned for loop. If the word "Include" is found by the loop, the method will create a specific type of chart. In simpler terms, I want to return a string based the ID condition being met. I am getting:
javax.ejb.EJBException
at com.sun.ejb.containers.EJBContainerTransactionManager.processSystemException
(EJBContainerTransactionManager.java:748)
at com.sun.ejb.containers.EJBContainerTransactionManager.
completeNewTx(EJBContainerTransactionManager.java:698)
at com.sun.ejb.containers.EJBContainerTransactionManager.postInvokeTx
(EJBContainerTransactionManager.java:503)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4475)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2009)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1979)
Caused by: java.lang.IllegalArgumentException: You have attempted to set
a parameter at position 2 which does not exist in this query string SELECT p FROM
Itemdatapoint p JOIN p.series s WHERE s.master.item.subs.subid = :subid.
at org.eclipse.persistence.internal.jpa.QueryImpl.setParameterInternal(QueryImpl.java:925)
at org.eclipse.persistence.internal.jpa.QueryImpl.setParameterInternal(QueryImpl.java:906)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:469)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:1)
at com.manaar.clientmods.gazprom.design3.data.facade.ItemdatapointFacade.
chartType(ItemdatapointFacade.java:78)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
The subid value of 2 exists if I run a native SQL query on the relevant parent table in the DB. Also the type of the subid is an int in the main entity class, the JPQL Facade class and the managed bean.
The JPQL:
public List<Itemdatapoint> chartType (int subid) {
Query q = em.createQuery("SELECT p FROM Itemdatapoint p JOIN p.series s WHERE s.master.item.subs.subid = :subid");
q.setParameter(subid, "subid");
return q.getResultList();
}
The managed bean:
#Named(value = "reportBean")
#SessionScoped
public class ReportBean implements Serializable {
#Inject
private ItemdatapointFacade facade;
public String typeSwitch1() {
subid = 2;
chartType = facade.chartType(subid);
for(Itemdatapoint e: chartType) {
status = e.getSeries().getMaster().getStatus();
if(status.equals("Include")) {
return "line";
}
}
return null;
}
The xhtml page:
<p:chart type="#{reportBean.typeSwitch1()}" model="#{reportBean.subLineChart1}"/>
I also tried a non Join JPQL just from a single table:
public List<Itemdatapoint> noJoin (int subid) {
Query q = em.createQuery("SELECT p FROM Itemdatapoint p WHERE p.pointid = :subid");
q.setParameter(subid, "subid");
return q.getResultList();
}
Similar problem:
java.lang.IllegalArgumentException: You have attempted to set a
parameter at position 2 which does not exist in this query string
SELECT p FROM Itemdatapoint p WHERE p.pointid = :subid.
I gather that IllegalArgumentException means that the selected entity does not exist or is not the correct type consistent with the query string in the facade class. But in my case the entity exists and the parameter is the correct type.
I would appreciate any help in understanding why i'm getting this error. Thank in advance!
UPDATE
Responding to the answer from lametaweb, I want to better understand the concept of JPA parameters.
According to the JPA documentation, the first argument of the setParameter method is the parameter name or number. The second argument is the object that should be bound to the named parameter. Why does the following work without throwing Illegal ArgumentException?
I tested an xhtml (web page):
<p:dataGrid id="rep1" columns="1" value="#{pageBean.itemPageList1}" var="items1" rows="4">
<p:commandLink value="#{items1.itemname}" action="#{pageBean.showItem1}" ajax="false"/>
</p:dataGrid>
The bean code:
public ListDataModel<Sectionitem> getItemPageList1() {
subid = 1;
reportStatus = "Include";
itemPageList1 = itemFacade.viewItems(subid, reportStatus);
return itemPageList1;
}
The JPA facade:
public ListDataModel<Sectionitem> viewItems(int subid, String stat) {
Query q = em.createQuery("select s from Sectionitem s JOIN s.subs c where c.subid = :subid AND s.status = :stat ORDER BY s.daterec");
q.setParameter("subid", subid);
q.setParameter("stat", stat);
ListDataModel<Sectionitem> res
= new ListDataModel<Sectionitem>(q.getResultList());
return res;
}
Why is it in this case, the object exist but in my original case the subid object does not exist?
You are invoking this method in your code:
setParameter(int position, Object value)
but you have to invoke this one instead:
setParameter(String name, Object value)
So your code should be:
q.setParameter("subid", Integer.valueOf(subid));
But, if you invoke:
q.setParameter(subid, "subid");
here the first parameter represents the position of the argument and the second the value for it. So you are passing a value of "subid" for the parameter in the second (2) position, which doesn't exist, because you only have one parameter in your JPQL query, hence the IllegalArgumentException exception.
Note: Why do you have a primitive type in your entity? Why not an Integer instead an int?

Ormlite and PostgreSQL - Error inserting text array with custom persister

I have been working to setup Ormlite as the primary data access layer between a PostgreSQL database and Java application. Everything has been fairly straightforward, until I started messing with PostgreSQL's array types. In my case, I have two tables that make use of text[] array type. Following the documentation, I created a custom data persister as below:
public class StringArrayPersister extends StringType {
private static final StringArrayPersister singleTon = new StringArrayPersister();
private StringArrayPersister() {
super(SqlType.STRING, new Class<?>[]{String[].class});
}
public static StringArrayPersister getSingleton() {
return singleTon;
}
#Override
public Object javaToSqlArg(FieldType fieldType, Object javaObject) {
String[] array = (String[]) javaObject;
if (array == null) {
return null;
} else {
String join = "";
for (String str : array) {
join += str +",";
}
return "'{" + join.substring(0,join.length() - 1) + "}'";
}
}
#Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
String string = (String) sqlArg;
if (string == null) {
return null;
} else {
return string.replaceAll("[{}]","").split(",");
}
}
}
And then in my business object implementation, I set up the persister class on the column likeso:
#DatabaseField(columnName = TAGS_FIELD, persisterClass = StringArrayPersister.class)
private String[] tags;
When ever I try inserting a new record with the Dao.create statement, I get an error message saying tags is of type text[], but got character varying... However, when querying existing records from the database, the business object (and text array) load just fine.
Any ideas?
UPDATE:
PostGresSQL 9.2. The exact error message:
Caused by: org.postgresql.util.PSQLException: ERROR: column "tags" is
of type text[] but expression is of type character varying Hint: You
will need to rewrite or cast the expression.
I've not used ormlite before (I generally use MyBatis), however, I believe the proximal issue is this code:
private StringArrayPersister() {
super(SqlType.STRING, new Class<?>[]{String[].class});
}
SqlType.String is mapped to varchar in SQL in the ormlite code, and so therefore I believe is the proximal cause of the error you're getting. See ormlite SQL Data Types info for more detail on that.
Try changing it to this:
private StringArrayPersister() {
super(SqlType.OTHER, new Class<?>[]{String[].class});
}
There may be other tweaks necessary as well to get it fully up and running, but that should get you passed this particular error with the varchar type mismatch.