QueryDSL like operation SimplePath - sql

Similarly to this question I would like to perform an SQL "like" operation using my own user defined type called "AccountNumber".
The QueryDSL Entity class the field which defines the column looks like this:
public final SimplePath<com.myorg.types.AccountNumber> accountNumber;
I have tried the following code to achieve a "like" operation in SQL but get an error when the types are compared before the query is run:
final Path path=QBusinessEvent.businessEvent.accountNumber;
final Expression<AccountNumber> constant = Expressions.constant(AccountNumber.valueOfWithWildcard(pRegion.toString()));
final BooleanExpression booleanOperation = Expressions.booleanOperation(Ops.STARTS_WITH, path, constant);
expressionBuilder.and(booleanOperation);
The error is:
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [7!%%] did not match expected type [com.myorg.types.AccountNumber (n/a)]
Has anyone ever been able to achieve this using QueryDSL/JPA combination?

Did you try using a String constant instead?
Path<?> path = QBusinessEvent.businessEvent.accountNumber;
Expression<String> constant = Expressions.constant(pRegion.toString());
Predicate predicate = Expressions.predicate(Ops.STARTS_WITH, path, constant);

In the end, I was given a tip by my colleague to do the following:
if (pRegion != null) {
expressionBuilder.and(Expressions.booleanTemplate("{0} like concat({1}, '%')", qBusinessEvent.accountNumber, pRegion));
}
This seems to do the trick!

It seems like there is bug/ambiguity. In my case, I need to search by couple fields with different types (String, Number), e.g. SQL looks like:
SELECT * FROM table AS t WHERE t.name = "%some%" OR t.id = "%some%";
My code looks like:
BooleanBuilder where = _getDefaultPredicateBuilder();
BooleanBuilder whereLike = new BooleanBuilder();
for(String likeField: _likeFields){
whereLike = whereLike.or(_pathBuilder.getString(likeField).contains(likeValue));
}
where.and(whereLike);
If first _likeFields is type of String - request works fine, otherwise it throws Exception.

Related

Nhibernate and like statement on XML field

I have a wrapped fluent nhibernate framework that I'm reusing and have no control over the actual mapping.
In my entity object I have a property mapped as string to an XML column in sql.
Hence when I run a query like:
var myResult = (from myTable in DataManager.Session.Query<Table>()
where myTable.thatXmlFieldWhichIsMappedAsString.Contains(AnXmlSnippet))
select myTable).FirstOrDefault();
It is trying to use the LIKE operator in SQL which is invalid on that column type.
How can I get around this without having to select all the rows and converting to List first?
In case, that we do not need .Query() (LINQ), and we can use Criteria query or QueryOver, we can use conversion:
// the projection of the column with xml
// casted to nvarchar
var projection = Projections
.Cast(NHibernateUtil.StringClob
, Projections.Property("thatXmlFieldWhichIsMappedAsString"));
// criteria filtering with LIKE
var criteria = Restrictions.Like(projection, "searched xml");
// query and result
var query = session.QueryOver<MyEntity>()
.Where(criteria)
;
var result = query
.SingleOrDefault<MyEntity>()
;
From my experience this could lead to conversion into small nvarchar(255) - sql server... Then we can do it like this:
var projection = Projections
.SqlProjection("CAST(thatXmlFieldWhichIsMappedAsString as nvarchar(max)) AS str"
, new string[]{}
, new NHibernate.Type.IType[]{}
);

LinqToSql: ExecuteQuery an ExecuteQuery-result?

I use this code to get all customers from my database...
Dim customerResult = db.ExecuteQuery(Of VIEW_customers)("SELECT * FROM TOPL_Customers").ToList
Now that I have all customers fetched from the database, I want to run a "filter" query against customerResult - how do I do that?
Was hoping for something like this...
Dim filterResult = customerResult.ExecuteQuery(Of VIEW_customers)("SELECT * WHERE active=1").ToList
Any suggestions? I don't want to query the database twice.
I need to use a string as a search query because it's dynamic.
Thanks
Try this:
var filteredResult = from a in customerResult
//Add suitable filter condition based on column values
where a.Active == 1
select a;
I'm assuming here that VIEW_customers represents your model for the result set.
You can use Expressions to build up a series of filters and then join them together to create a single, dynamic where clause to run against your result set.
Expression<Func<VIEW_customers, bool>> predicate1 = x => x.someField == 'something';
Expression<Func<VIEW_customers, bool>> predicate2 = x => x.otherField == 'something else';
Then you can join them together with .And or .Or as appropriate:
Expression<Func<VIEW_customers, bool>> combinedPredicate = predicate1.And(predicate2);
You can chain any number of these together; it's boolean logic (basically think of each additional clause as being wrapped by a set of parenthesis). When you're ready to consume the predicate, compile it and run it like a normal .Where clause.
Func<VIEW_customers, bool> compiledPredicate = combinedPredicate.Compile();
var results = customerResult.Where(compiledPredicate);

SQL attribute name in parameterized query

I am using following function for retrieving record on choice. I gave table my column name and value and it shows the result. but the problem is, Its not getting column name as parameter like:
public List<Products> ListAllProducts(string searchOption, string searchValue)
{
db.ClearParameters();
db.AddParameter(db.MakeInParam("#ColumnName", DbType.String, 50, searchOption));
db.AddParameter(db.MakeInParam("#Value", DbType.String, 50, searchValue));
string query = #"SELECT *
FROM [Products]
WHERE #ColumnName LIKE '%'+#Value+'%'";
ds = db.GetDataSet(query);
//Rest of code but above query is not executing
}
but when I use query like this:
string query = #"SELECT *
FROM [Products]
WHERE "+searchOption+" LIKE '%'+#Value+'%'";
It runs fine and give me result. I read this, this and this one specially, but got no idea.
Kindly guide me.
Parameters can be used in place of values inside expressions, and for nothing else: in particular, you cannot use parameters to denote table names, column names, sort order specifiers, or other parts of SQL statement that are not values.
Your non-parametersized query works, because searchOption is copied into your SQL, and becomes part of the query string.
If you need to build a query that changes conditions based on a parameter, you need to change the condition to account for all possible values of #ColumnName, like this
string query = #"SELECT *
FROM [Products]
WHERE (#ColumnName='FirstName' AND FirstName LIKE '%'+#Value+'%')
OR (#ColumnName='LastName' AND LastName LIKE '%'+#Value+'%')
OR (#ColumnName='Location' AND Location LIKE '%'+#Value+'%')";
or fall back on generating your query dynamically. As long as searchOption is not coming from user's input directly, you are safe from SQL injection attacks even though your SQL is generated dynamically.
While Trying, I came across following option and posted in answer ,so other may get benifit of this.
string query = String.Format(
#"SELECT *
FROM [Products]
WHERE {0} LIKE '%'+#Value+'%'", searchOption
);
So the complete function becomes:
public List<Products> ListAllProducts(string searchOption, string searchValue)
{
db.ClearParameters();
db.AddParameter(db.MakeInParam("#Value", DbType.String, 50, searchValue));
string query = String.Format(
#"SELECT *
FROM [Products]
WHERE {0} LIKE '%'+#Value+'%'", searchOption
);
ds = db.GetDataSet(query);
//Rest of code
}

NHibernate Like with integer

I have a NHibernate search function where I receive integers and want to return results where at least the beginning coincides with the integers, e.g.
received integer: 729
returns: 729445, 7291 etc.
The database column is of type int, as is the property "Id" of Foo.
But
int id = 729;
var criteria = session.CreateCriteria(typeof(Foo))
criteria.Add(NHibernate.Criterion.Expression.InsensitiveLike("Id", id.ToString() + "%"));
return criteria.List<Foo>();
does result in an error (Could not convert parameter string to int32). Is there something wrong in the code, a work around, or other solution?
How about this:
int id = 729;
var criteria = session.CreateCriteria(typeof(Foo))
criteria.Add(Expression.Like(Projections.Cast(NHibernateUtil.String, Projections.Property("Id")), id.ToString(), MatchMode.Anywhere));
return criteria.List<Foo>();
Have you tried something like this:
int id = 729;
var criteria = session.CreateCriteria(typeof(Foo))
criteria.Add(NHibernate.Criterion.Expression.Like(Projections.SqlFunction("to_char", NHibernate.NHibernateUtil.String, Projections.Property("Id")), id.ToString() + "%"));
return criteria.List<Foo>();
The idea is convert the column before using a to_char function. Some databases do this automatically.
AFAIK, you'll need to store your integer as a string in the database if you want to use the built in NHibernate functionality for this (I would recommend this approach even without NHibernate - the minute you start doing 'like' searches you are dealing with a string, not a number - think US Zip Codes, etc...).
You could also do it mathematically in a database-specific function (or convert to a string as described in Thiago Azevedo's answer), but I imagine these options would be significantly slower, and also have potential to tie you to a specific database.

Linq.Where-to-SQL on a text field comparing to a list of values

Customer.text is a field in an T-SQL DB (that I do not control and thus may not alter) of type "text".
I'd like to do something like this:
List<string> compare = new List<string>();
compare.Add("one");
compare.Add("two");
var q = from t in customer
where t.text.Contains( compare.First())
select t;
this will work.
But now I'd like to do something like: (!NOT WORKING!)
var q = from t in customer
where compare.Contains( t.text )
select t;
How can I achieve this? Is it even possible?
EDIT: The problem is obviously not exactly clear: A text column in SQL cannot be queried using "=" but only with LIKE. Thus the compare.Contains( t.text ) will result in an error, as it is converted into a query using "=".
What I did not tell - I thought it is irrelevant - is, that I use LINQ-to-ORM (LLBLGen in this case).
What I tried instead:
var q = from t in customer
where compare.Any( x => t.text.Contains(x) )
select t;
Now this did not work also. Currently I'm not at work, but the exception was something with a ConstantExpression not being convertable into a SetExpression.
I hope this gave some clarification.
EDIT2:
Joseph pointed this out to me: PredicateBuilder. It creates an Expression on a given ObjectType.
Now my problem is, that my type is an anonymous type out of multiple joins.
Is there an easy or elegant way to handle this?
Now I might be missing something, but your code looks like it should work. Did you include the namespaces at the top of the file?
using System.Linq;
using System.Linq.Expressions;
You could also rewrite it without the Linq2Sql syntax, like:
var q = customer.Where(c => compare.Contains(c.text));
You could build your query using LinqKit's free predicate builder class. Here is a blog post which describes its use and has a link to the download site.
http://thecodeslinger.wordpress.com/2008/10/28/linqkit-predicatebuildert-goodness/
Below is a code sample from the post
//First get a list of keywords that match the description entered.
string[] parts = txtInclude.Text.Split(new[] {‘ ‘});
string[] noparts = null;
if(txtButNot.Text.Trim().Length > 0)
noparts = txtExclude.Text.Trim().Split(new[] {‘ ‘});
var pred = PredicateBuilder.True<Pet>();
//here is where you would loop through your compare object
parts.ForEach(p => pred = pred.And(pl => pl.description.Contains(p)));
if(noparts != null)
noparts.ForEach(p => pred = pred.And(pl => !pl.description.Contains(p)));
var pets = from s in db.Pets.Where(pred)
select s;
You have to convert the text field to string
var query = from t in dataContext.table
where compare.Contains(t.textField.ToString())
select t;