I need to test whether the predicate object matches the exchange for various expression languages. I need to know what exchange value I need to set in exchange to validate the predicate.
public void test() {
String expression="//orders/value>10"';
CamelContext context = new DefaultCamelContext();
Predicate predicate=new JXpathExpression(expression,boolean.class);
Exchange exchange = new DefaultExchange(context);
Message in = exchange.getIn();
in.setBody(""); // how i need to set the message in exchange in order to evaluate it against predicate
exchange.setIn(in);
boolean check=predicate.matches(exchange);
}
For JXPath the predicate object contains JXpath[//orders/value>10] when I print it using predicate.toString().
How do I set the exchange so that this expression can be validated?
JXPath works on java objects. So you have to set a suitable object in the message body.
If the object you set there has o.getOrders().getValue() and returns a numeric value > 10 then the predicate should evaluate to true.
Related
I'm trying to mapp an scalar Function of my DB that has a custom schema. This is how I'm registering the function in the context:
[DbFunction("ProjectMaterial_GetCostPrice","Project")]
public static decimal ProjectMaterial_GetCostPrice (int ProjectMaterialID, decimal ExtCost)
{
return 0;
}
I'm registering the Scalar function in a partial class of the context. And this is the Schema of the Scalar Function in the DB:
-- Select Project.ProjectDriver_GetCostPrice (5456921)
ALTER FUNCTION [Project].[ProjectMaterial_GetCostPrice] (#ProjectMaterialID int, #ExtCost money)
RETURNS MONEY
AS
Also I change the body of the method with a throw as the documentation suggest:
throw new NotSupportedException();
And it's thrown the exception instead of calling the function
This is how I call the function:
var newCostPrice= NsiteDBContext.ProjectMaterial_GetCostPrice(projectMaterial.ProjectMaterialId, projectMaterial.CostPrice.Value);
Using the call itself it throws the exception because it actually executes the C# code. The reason it is recommended to throw an exception is exactly this, to avoid inadvertent use, ie by directly calling it. That signature will be interpreted by the given LINQ provider and translate into the proper SQL statements.
To do so EF context needs to know how to use so some way might be
var items = await ctx.Materials.Select(c = > new {
Material= c,
CostPrice = ProjectMaterial_GetCostPrice(c.ProjectMaterialId, c.CostPrice.Value),
}).ToListAsync();
Now the ctx object will know how to translate the ProjectMaterial_GetCostPrice signature when it parses the expression trees.
Doing outside a select statement, even via the static call won't work as expected, and it throws that exception (to inform us this).
As described in the previous answer, you can use functions, defined in that way, in the LINQ queries only.
To call SQL scalar-valued functions directly, you should define it using DbContext.Database.ExecuteSqlCommand method. Like this, it should work:
public decimal ProjectMaterial_GetCostPrice(int ProjectMaterialID, decimal ExtCost)
{
System.Data.SqlClient.SqlParameter resultParam =
new System.Data.SqlClient.SqlParameter
{
ParameterName = "#resultCost",
SqlDbType = System.Data.SqlDbType.Money,
Direction = System.Data.ParameterDirection.Output
};
System.Data.SqlClient.SqlParameter parMaterialID =
new System.Data.SqlClient.SqlParameter("#MaterialID", ProjectMaterialID);
SqlParameter parExtCost =
new System.Data.SqlClient.SqlParameter("#ExtCost", ExtCost);
Database.ExecuteSqlCommand(
"select #resultCost = [Project].[ProjectMaterial_GetCostPrice](#MaterialID, #ExtCost);",
resultParam, parMaterialID, parExtCost);
return (decimal)resultParam.Value;
}
I just encountered this use case myself and came up with the following solution. Suppose you have a user-defined scalar function dbo.GetCost(#MatID int, #ExtCost money) that returns a decimal(18, 2). Then define a method in your DbContext as follows:
[DbFunction]
public decimal GetCost(int matID, decimal extCost) {
NonEmptyTable.Take(1).Select(x => GetCost(matId, extCost))
.SingleOrDefault();
}
Usage:
decimal cost = db.GetCost(matID, extCost);
There's a bit of magic happening here, but it makes sense when you think it through. You're defining a C# method mapping to the database function as the EF Core docs suggest, but instead of the method body throwing an exception, it's actually invoking the same method in a Linq-to-SQL context, then returning the result (you could do this with two separate methods to avoid the appearance of recursion, but this is more concise).
What's important is that NonEmptyTable is mapped to a table that is never empty, otherwise it will return a default value (you could also use .Single() to throw an exception in this case, if preferred).
I am reading Spring 5.1.3 reference docs, and SpEL Type Conversion gets following sample code:
class Simple {
public List<Boolean> booleanList = new ArrayList<Boolean>();
}
Simple simple = new Simple();
simple.booleanList.add(true);
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
// false is passed in here as a string. SpEL and the conversion service
// correctly recognize that it needs to be a Boolean and convert it
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");
// b is false
Boolean b = simple.booleanList.get(0);
It works as the documents mentioned, and changes the value of the property, but according to Javadocs forReadOnlyDataBinding()
Create a {#code SimpleEvaluationContext} for read-only access to public properties via {#link DataBindingPropertyAccessor}.
Shouldn't the SpEL Expression be read-only, and does not change the property value?
The field's contents are mutable but the field itself is immutable.
i.e. you are not allowed to replace booleanList with a new array but there is nothing to prevent the contents of the existing array from being mutated.
I am using StoredProcedureItemReader in Spring Batch for Reading Items from a DB via Stored Procedure (Which accepts input parameters).
I have done setting the basic configurations for StoredProcedureItemReader but Not getting how to set the parameters values in it.
StoredProcedureItemReader storedProcItemReader = new StoredProcedureItemReader();
storedProcItemReader.setDataSource(dataSource);
storedProcItemReader.setProcedureName("proc_name");
SqlParameter[] parameter = {new SqlParameter(OracleTypes.VARCHAR),new SqlParameter(OracleTypes.VARCHAR),new SqlParameter(OracleTypes.CURSOR)};
storedProcItemReader.setParameters(parameter);
storedProcItemReader.setPreparedStatementSetter(??)
I want to set the values for two input parameters via PreparedStatementSetter. How do i set it. Do i need to use a preparedstatement for it. As i have already given the proc name (which has all the query to execute).
Thanks
You need to use an ItemPreparedStatementSetter :
public class MyItemPreparedStatementSetter implements ItemPreparedStatementSetter<T> {
#Override
public void setValues(T item, PreparedStatement ps) throws SQLException {
//Set your values here, example :
ps.setString(1, item.getProperty());
}
}
Statement fields are 1-indexed.
Then you can pass it to your reader :
storedProcItemReader.setPreparedStatementSetter(new MyItemPreparedStatementSetter());
I have an application that uses Apache Camel with Active MQ. In my RouteBuilder class where I configure the routes, it is possible that a parameter may be missing from the in body. In that case, I would like to give it a default value.
Here is what I have now:
#Override
public void configure() throws Exception {
...
String invocation = "aMethod( ${body[context]}, ${body[aParam]}, ${body[param2]} )";
from(url).routeId(url).bean(bean, invocation);
}
In my case, param2 is a boolean which I would like to send forward to aMethod as false in case it doesn't exist. How can I do that?
I saw something here: http://camel.apache.org/simple.html#Simple-OGNLexpressionsupport where it says "You can also use the null safe operator (?.) to avoid NPE if for example the body does NOT have an address", but I can't figure how to write the invocation so I don't have an error in the specified case.
I believe you are looking to use a conditional similar to this:
from("")
.choice()
.when(header("myHeader").isNull())
.setHeader("myHeader").simple("false")
.end() //This might be endChoice can't remember syntax exactly
.bean(myBean, myMethod);
..revised for Object in the body
from("")
.processor( new Processor(Exchange exchange) {
MyObject obj = exchange.getIn().getBody(MyObject.class);
Boolean b = obj.getParam2();
if(b == null)
obj.setParam2(Boolean.FALSE);
}
.bean(myBean, myMethod);
NOTE: If your actual java class uses 'boolean' and not the 'Boolean' class wrapper, then all booleans when initialized are by default set to false. So if you have an object in your body and nobody has the the boolean it will default to false.
I am using this code to retrieve an object from a database. This code returns an object, but the type of that object is just Object.
I however want to return the type Pcinitialdata. As said, it returns just Object and the type of that is Object
How can I solve this?
String qryStrforCom = "select pci.fileNo,pci.projectNo,pci.fundId,pci.decrp,pci.devSec,pci.estBy,pci.areaCode,pci.targetDate,pci.jobnoRecedate,pci.conBy,pci.supBy,pci.ht33,pci.lt11,pci.sub11,pci.lt3Phase,pci.ltsPhase,pci.abc5w,pci.abc4w,pci.abcsecct,pci.perCapacity,pci.newCapacity,pci.proLtrToEsOn,pci.stdCost,pci.detailCost,pci.varianceNew from Pcinitialdata pci where TRIM(pci.estNo) = :value";
Query querycom = getEntityManager(webAppName).createQuery(qryStrforCom);
querycom.setParameter("value", value);
List<Pcinitialdata> listCom=querycom.getResultList();
if (listCom.isEmpty()) {
return null;
}
return listCom;
The query language that is used with the createQuery method is JPQL, not SQL.
In JPQL you can query directly for Entities, and there is no need to list all individual properties. Listing them anyway is supported, but the result is a list of separate properties and not a single entity.
Furthermore, you can enter a class type when you construct the Query object if you're using at least JPA 2.0 (Java EE 6). The code will then become:
String qryStrforCom = "select pci from Pcinitialdata pci where TRIM(pci.estNo) = :value";
TypedQuery<Pcinitialdata> querycom = getEntityManager(webAppName).createQuery(qryStrforCom, Pcinitialdata.class);
querycom.setParameter("value", value);
List<Pcinitialdata> listCom = querycom.getResultList();
if (listCom.isEmpty()) {
return null;
}
return listCom;
Note that with JPA you can chain calls and oftentimes it's better to work with empty lists instead of null. It's also more convenient to declare your query upfront, either in XML or via an annotation. Finally, try to cut down on the abbreviations used and give your variables meaningful names (e.g. value should not be called that if it's used for the estNo, etc.)
Your code would then become simply:
return getEntityManager(webAppName)
.createNamedQuery("Pcinitialdata.byEstNo", Pcinitialdata.class)
.setParameter("estNo", estNo)
.getResultList();