Nhibernate - QueryOver. IsLike with multiple conditions - nhibernate

I couldn't figure out how to create IsLike query with multiple conditions.
criteria = criteria.Add(Restrictions.Like("IpAdress", "%" + request.Keyword + "%") ||
Restrictions.Like("MacAdress", "%" + request.Keyword + "%") ||
Restrictions.Like("al.SerialNumber", "%" + request.Keyword + "%"));
How to translate query above to IQueryOver format?
Thanks!

You haven't posted what your entities look like, but you could write something along these lines:
query.Where(Restrictions.Disjunction()
.Add(Restrictions.On<Type>(x => x.IpAddress).IsLike(request.Keyword))
.Add(Restrictions.On<Type>(x => x.MacAdress).IsLike(request.Keyword))
.Add(Restrictions.On<Type2>(x => x.SerialNumber).IsLike(request.Keyword)));
or you could use || operator instead of disjunction:
query.Where(
Restrictions.On<Type>(x => x.IpAddress).IsLike(request.Keyword) ||
Restrictions.On<Type>(x => x.MacAdress).IsLike(request.Keyword) ||
Restrictions.On<Type2>(x => x.SerialNumber).IsLike(request.Keyword));
Here are some similar SO question for more info:
queryover and (x like 'a' or y like 'a')
QueryOver Or with Subquery

Related

QueryOver use Projections.Concat on GroupBy (NHibernate 3.3.5)

I'm trying to implement a bit complicated sql in QueryOver of NHibernate (3.3.5 version) that would be parsed in SQL Server as:
SELECT
CASE WHEN LTR_ReciboCompania IS NULL
THEN CAST(LTR_Id AS VARCHAR(255))
ELSE LTR_ReciboCompania + '#' + LTR_NumPoliza
END
FROM LotesRecibos
GROUP BY
CASE WHEN LTR_ReciboCompania IS NULL
THEN CAST(LTR_Id AS VARCHAR(255))
ELSE LTR_ReciboCompania + '#' + LTR_NumPoliza
END
I've tried a lot of combinations with Projections.Concat() and Projections.SqlFunction("concat", ...) without success.
Sample 1
var concatProjection = Projections.SqlFunction("concat", NHibernateUtil.AnsiString,
Projections.Property<LoteRecibo>(x => x.ReciboCompania), Projections.Constant("#"), Projections.Property<LoteRecibo>(x => x.NumPoliza));
var groupBy = Projections.Conditional(Restrictions.IsNull(Projections.Property<LoteRecibo>(p => p.ReciboCompania)),
Projections.Cast(NHibernateUtil.String, Projections.Property<LoteRecibo>(p => p.Id)),
concatProjection);
var result = sessionScope.Session.QueryOver<LoteRecibo>()
.Where(r => r.CreationDate.Value.YearPart() == 2021)
.Select(Projections.GroupProperty(groupBy))
.List<object[]>();
In that case, the generated query only generates a parameter for the separator in Select but not in Group By:
exec sp_executesql N'SELECT (case when this_.LTR_ReciboCompania is null then cast( this_.LTR_Id as NVARCHAR(255)) else (this_.LTR_ReciboCompania+#p0+this_.LTR_NumPoliza) end) as y0_ FROM LotesRecibos this_ WHERE datepart(year, this_.LTR_FC) = #p1 GROUP BY (case when this_.LTR_ReciboCompania is null then cast( this_.LTR_Id as NVARCHAR(255)) else (this_.LTR_ReciboCompania+?+this_.LTR_NumPoliza) end)',N'#p0 nvarchar(4000),#p1 int',#p0=N'#',#p1=2021
And more readable:
SELECT (
CASE
WHEN this_.LTR_ReciboCompania IS NULL
THEN cast(this_.LTR_Id AS NVARCHAR(255))
ELSE (this_.LTR_ReciboCompania + '#' + this_.LTR_NumPoliza)
END
) AS y0_
FROM LotesRecibos this_
WHERE datepart(year, this_.LTR_FC) = 2021
GROUP BY (
CASE
WHEN this_.LTR_ReciboCompania IS NULL
THEN cast(this_.LTR_Id AS NVARCHAR(255))
ELSE (this_.LTR_ReciboCompania + ? + this_.LTR_NumPoliza)
END
)
var result = sessionScope.Session.QueryOver<LoteRecibo>()
.Where(r => r.CreationDate.Value.YearPart() == 2022)
.SelectList(list => list
.SelectGroup(p => Projections.Concat(p.CodReciboCompania, "#", p.NumPoliza))
)
.List<object[]>();
Sample 2 (simplified without conditional)
var result = sessionScope.Session.QueryOver<LoteRecibo>()
.Where(r => r.CreationDate.Value.YearPart() == 2022)
.SelectList(list => list
.SelectGroup(p => Projections.Concat(p.CodReciboCompania, "#", p.NumPoliza))
)
.List<object[]>();
It throws the following exception:
An unhandled exception of type 'System.Exception' occurred in NHibernate.dll
Unrecognised method call in expression Concat(new [] {p.CodReciboCompania, "#", p.NumPoliza})
But if I set in Select (not in SelectGroup) it works. And I can't understand how to set the Concat function in the group by part of the query.
I should use QueryOver, because we connect to SQL Server and Oracle DB Servers.
UPDATE (Workaround)
While I don't found a better solution, I'll use the first sample without the constant separator. Really I don't need to separate both fields, in my real query I only use the field to group.
var concatProjection = Projections.SqlFunction("concat", NHibernateUtil.AnsiString,
Projections.Property<LoteRecibo>(x => x.ReciboCompania), Projections.Property<LoteRecibo>(x => x.NumPoliza));
var groupBy = Projections.Conditional(Restrictions.IsNull(Projections.Property<LoteRecibo>(p => p.ReciboCompania)),
Projections.Cast(NHibernateUtil.String, Projections.Property<LoteRecibo>(p => p.Id)),
concatProjection);
var result = sessionScope.Session.QueryOver<LoteRecibo>()
.Where(r => r.CreationDate.Value.YearPart() == 2021)
.Select(Projections.GroupProperty(groupBy))
.List<object[]>();

How to pass subquery as table name to another query in yii2

I have a query which I am trying to convert into yii2 syntax. Below is the query
SELECT project_id, user_ref_id FROM
(
SELECT `project_id`, `user_ref_id`
FROM `projectsList`
WHERE user_type_ref_id = 1) AS a WHERE user_ref_id = '.yii::$app->user->id;
I am trying to convert it into yii2 format like
$subQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from('projectsList')->where(['user_type_ref_id' => 1]);
$uQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from($subQuery)->where(['user_ref_id ' => yii::$app->user->id])->all();
It is giving an error like
trim() expects parameter 1 to be string, object given
How to I pass subquery as table name to another query
Not tested, but generally this is how it goes. You need to pass the subQuery as a table. So change ->from($subQuery) in the second query to ->from(['subQuery' => $subQuery])
$subQuery = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from('projectsList')->where(['user_type_ref_id' => 1]);
Then
$query = (new Query())->select(['p.project_id', 'p.user_ref_id'])->from(['subQuery' => $subQuery])->where(['subQuery.user_ref_id ' => yii::$app->user->id])->all();

Using IsLike in NHibernate QueryOver

I know that it gives some solutions for this error already but I dont find out why I got this error. When I load the List without filtered it works.
if (searchString != "") {
query = _pagedDataQueryProcessor.GetDefaultQuery<Data.Entities.Password>()
.Where(
Restrictions.Disjunction()
.Add(Restrictions.On<Data.Entities.Password>(x => x.Name).IsLike(searchString))
.Add(Restrictions.On<Data.Entities.Password>(x => x.Description).IsLike(searchString))
.Add(Restrictions.On<Data.Entities.Password>(x => x.PasswordText).IsLike(searchString))
);
}
I found out what the problem was
Solution:
if (searchString != "") {
query = _pagedDataQueryProcessor.GetDefaultQuery<Data.Entities.Password>()
.Where(
Restrictions.Disjunction()
.Add(Restrictions.On<Data.Entities.Password>(x => x.Name).IsLike("%" + searchString + "%"))
.Add(Restrictions.On<Data.Entities.Password>(x => x.Description).IsLike("%" + searchString + "%"))
.Add(Restrictions.On<Data.Entities.Password>(x => x.PasswordText).IsLike("%" + searchString + "%"))
);
What did i changed? i didn't had the "%".
Here I want to filter a list but when I wrote something in the input i always got a empty list.
searchstring is the filtered word
data.entities.password is the list on the db
Can someone help me I dont know what i make wrong.
You need to add wildcards or add a second argument to IsLike.
...IsLike("%" + searchString + "%"))
You can put the wildcard anywhere in the string, e.g. only at the beginning or only at the end.
Or
...IsLike(searchString, MatchMode.Anywhere)
You can also use MatchMode.Start or MatchMode.End.

Or Constraint for QueryOver

I want to get all PartitionStates by name where it exactly meets the partitionName or starts with it when containing a ..
This is the query I have
return session.QueryOver<PartitionState>()
.Where(p => p.Name == partitionName)
.WhereRestrictionOn(p => p.Name).IsLike(partitionName + ".", MatchMode.Start)
.OrderBy(p => p.StartDate).Desc
.Take(1)
.SingleOrDefault<PartitionState>();
The above query produces an AND expression, but i want it to be an OR.
In SQL it should look like this:
SELECT TOP 1 *
FROM PartitionState
WHERE (Name = #partitionName OR Name like #partitionName+'.%')
ORDER BY StartDate DESC
It seems there is no built in method, but it is possible to pass a restriction into where method.
return session.QueryOver<PartitionState>()
.Where(Restrictions.Or(
Restrictions.Where<PartitionState>(p => p.Name == partitionName),
Restrictions.On<PartitionState>(p => p.Name).IsLike(partitionName + ".", MatchMode.Start)))
.OrderBy(p => p.StartDate)
.Desc.Take(1)
.SingleOrDefault<PartitionState>();

Using SQL with elastic search and tire

With my current setup I need to add some custom SQL statement that scopes some data with the Tire Gem.
I'm using Rails 3.2 with Ruby 1.9.3
In my Listing controller, I have the following:
#listings = Listing.search()
For my Listing.rb, I'm using the search methods with a number of filters such as:
def self.search(params={})
tire.search(load: true, page: params[:page], per_page: 50) do |search|
search.query { string params[:query], :default_operator => "AND" } if params[:query].present?
search.filter :range, posted_at: {lte: DateTime.now}
search.filter :term, "property.rooms_available" => params[:property_rooms_available] if params[:property_rooms_available].present?
search.filter :term, "property.user_state" => params[:property_user_state] if params[:property_user_state].present?
...
end
What I need to do is add this SQL statement into the search method so that it scopes by the lonitude and latitute. The 'coords' are passed in by parameters in the URL in the form
http://localhost:3000/listings?coords=51.0000,-01.0000 52.0000,-02.0000
(there is a white space between the -01.0000 and 52.0000.)
Currently I have:
sql = "SELECT title, properties.id, properties.lng,properties.lat from listings WHERE ST_Within(ST_GeometryFromText('POINT(' || lat || ' ' || lng || ')'),ST_GeometryFromText('POLYGON((#{coords}))'));"
I thought about trying to scope it within the controller by something like this?
def self.polyed(coords)
joins(:property).
where("ST_Within(ST_GeometryFromText('POINT(' || properties.lat || ' ' || properties.lng || ')'),ST_GeometryFromText('POLYGON((#{coords}))'))").
select("title, properties.id, properties.lng,properties.lat")
end
And this...
listings_controller.rb
def index
#listings = Listing.polyed(poly_coordinates).search()
end
It needs to return the results as #listings by HTML and the json format
http://localhost:3000/listings.json?
I'm already using RABL to automatically produce the json.
Is this possible?
Many thanks in advance.
Ryan
One possibility is to pass the options joins, where, etc. in the :load option.
But if you want to filter the returned results in the Rails code, a much better approach seem to be loading just record IDs with Tire (use the fields option to limit the fields returned), and then use them in your SQL query.