How do I restrict a query by the length of a string property? eg. something like:
NHSession.QueryOver<Customer>()
.Where(p => p.RegistryCode.Length == 8)
Something like this may do the trick
NHSession.QueryOver<Customer>()
.Where(
Restrictions.Eq(
Projections.SqlFunction("length", NHibernateUtil.String,
Projections.Property<Customer>(x => x.RegistryCode)),
8
)
)
Instead of "NHibernateUtil.String" i should use this "NHibernateUtil.Int16" type, because a 'length' parameter should always be a number and not a String.
Something like this:
NHSession.QueryOver<Customer>()
.Where(
Restrictions.Eq(
Projections.SqlFunction("length", NHibernateUtil.Int16,
Projections.Property<Customer>(x => x.RegistryCode)),
8
)
)
Related
I have the following query:
var result = _session.QueryOver<Entity>()
.Where(e => e.Property == value)
.SelectList(list => list
.Select(f => Projections.Concat("prefix-", e.BigIntProperty)).WithAlias(() => alias.Whatever)
...
)
.TransformUsing(Transformers.AliasToBean<Model>())
.Future<Model>();
The problem is that Projections.Concat() accepts only strings and since e.BigIntProperty is not, the above doesn't compile. Is there a way to cast e.BigIntProperty to string?
I tried something like the following, which doesn't work either:
.Select(f => Projections.Concat("prefix-", Projection.Cast(NHibernateUtil.String, e.BigIntProperty))).WithAlias(() => alias.Whatever)
, since Projections.Cast returns an IProjection and not a string.
Projections.Cast seems terribly limited in that it can't take arbitrary Projections. Luckily you can easily create your own custom projection that enables you to do that:
public static class CustomProjections
{
public static IProjection Concat(params IProjection[] projections)
{
return Projections.SqlFunction(
"concat",
NHibernateUtil.String,
projections);
}
}
Then, you'll be able to use your CustomProjections class like this:
var result = _session.QueryOver<Entity>()
.Where(e => e.Property == value)
.SelectList(list => list
.Select(CustomProjections.Concat(
Projections.Constant("prefix-"),
Projections.Cast(
NHibernateUtil.String,
Projections.Property<Entity>(e => e.BigIntProperty))))
.WithAlias(() => alias.Whatever)
...
)
.TransformUsing(Transformers.AliasToBean<Model>())
.Future<Model>();
I've already accepted Andrew's answer, but just for reference, you could use Projections.SqlFunction("concat", ...) directly which solves the whole issue since it can take IProjection's as arguments and not only string.
var result = _session.QueryOver<Entity>()
.Where(e => e.Property == value)
.SelectList(list => list
.Select(Projections.SqlFunction("concat",
NHibernateUtil.String,
Projections.Constant("prefix-"),
Projections.Cast(NHibernateUtil.String, Projections.Property<Entity>(e => e.BigIntProperty))))
.WithAlias(() => alias.Whatever)
...
)
.TransformUsing(Transformers.AliasToBean<Model>())
.Future<Model>();
NOTE: It seems that when calling either Projections.Concat(...) or Projections.SqlFunction("concat", ...), the query that is produced actually uses the + operator, e.g.:
SELECT (a + b) as foo FROM table
instead of:
SELECT concat(a, b) as foo FROM table
Of course, CONCAT is only available from MS SQL Server versions 2012 and above, so this is correct. Possibly the MsSQl2012Dialect could make use of the CONCAT, since CONCAT doesn't require that the arguments are varchar, they might as well be integers.
Unfortunately MsSQl2012Dialect doesn't do that, but it is very easy to build a custom Dialect:
public class CustomMsSql2012Dialect : MsSql2012Dialect
{
protected override void RegisterFunctions()
{
base.RegisterFunctions();
base.RegisterFunction("concat", new VarArgsSQLFunction(NHibernateUtil.String, "concat(", ",", ")"));
}
}
So, if you use version 2012 or above and you declare the above as your Dialect, you can ditch the Projections.Cast(...) part
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>();
I need to build a dynamic sql queue with 2 incoming params. It is easy when both params are defined.
MyClass.where(:column1 => param[:first], :column2 => params[:second])
but when for example param[:first] = 0 I want to select all(not null) fields for this column(so when both params are = 0 it would be equal to select * from tablename). Tried this syntax:
MyClass.where(:column1 => param[:first], :column2 => !nil)
but it gives me wrong output. Any suggestions how to elegantly resolve this?
You could use the ?: operator inside where:
MyClass.where(params[:first] ? {:column1 => params[:first]} : "column1 IS NOT NULL")
.where(params[:second] ? {:column2 => params[:second]} : "column2 IS NOT NULL")
What about MyClass.where('column1 IS NOT NULL AND column2 IS NOT NULL').where({:column1 => params[:first], :column2 => params[:second]}.delete_if{|k,v| v.nil?})?
I think this may work from what I've found. It appears to work in the rails console and considering active record alows active chaining:
MyClass.where(:column1 => params[:first], :column2 => params[:second]).where("column1 is NOT NULL").where("column2 is NOT NULL")
I've a little problem: I would insert a condition into my QueryOver that checks also the variable value. Something like this:
var qOver = QueryOver.Of<MyModel>(() => myMod)
.JoinAlias(() => myMod.SubMod, () => subMod, JoinType.LeftOuterJoin)
.Where(Restrictions.Or(
Restrictions.On(() => myMod.ID).IsIn(MyIDList)
, Restrictions.On(MyIDList == null))
In SQL sintax something like
WHERE #Variable = '' OR MyTable.MyField = #Variable
So, if I my variable is filled I'll filter on my field. If my variable is empty (or null) I'll select every record without filter any content.
How can I reach this result using QueryOver and Restrinctions?
Thank you!
If the variable is null or not set, dont add it to your query.
var qOver = QueryOver.Of<MyModel>(() => myMod)
.JoinAlias(() => myMod.SubMod, () => subMod, JoinType.LeftOuterJoin);
if( MyIDList != null )
qOver = qOver.Where(Restrictions.Or(Restrictions.On(() => myMod.ID).IsIn(MyIDList))
I am wondering can I do a where clause that takes in a collection?
List<string> myStrings = new List<strings> {"1", "2"};
session.Query<Table>().Where(x => x.Id == myStrings).ToList();
I basically want to get all rows from my db table that match everything in that query.
session.Query<Table>().Where(x => x.Id == myStrings[0]).ToList();
session.Query<Table>().Where(x => x.Id == myStrings[1]).ToList();
session.Query<Table>().Where(x => x.Id == myStrings[N]).ToList();
So thats what I would have to do right now. I would probably through that in a for loop but that is alot of queryies and I rather just do one query.
Or do I have to use the nhibernate create query syntax
var query = "Select * From Where In (:Id)";
session.CreateQuery(query)SetParameter("Id",myStrings) // not sure if I have to something like .ExecuteUpdate(); but just for select instead
session.Query<Table>().Where(x => myStrings.Contains(s => x.Id));
session.Query<Table>().Where(x => myString.All(s => x.Id == s));
you should use Any or All extension method on your collection