Can I use SQL functions in NHibernate QueryOver? - nhibernate

I have been searching the internet and can't find an example on how to use the queryover of nhibernate 3.0
For example I would like to use the string functions on the where clause of the queryover
ex:
var item = Query.Where(x => x.Name.ToLower() == name.ToLower()).FirstOrDefault();
But this doesn't work, because nhibernate can't understand the ToLower, so how can extend the dialect in a way that this becomes possible?

session.QueryOver<Foo>()
.Where(Restrictions.Eq(
Projections.SqlFunction("lower", NHibernateUtil.String,
Projections.Property<Foo>(x => x.Name)),
name.ToLower()))
should get you SQL like where lower(Name) = #p0

I believe it works at least in the build I am using (version 3.0.0.4000)... below is my example...
var reasons = _session.Query<Reason>();
var myReason = (from r in reasons
where r.IsCritical
&& r.ReasonCode.ToUpper() == reasonCode.ToUpper()
select r).FirstOrDefault();
Give it a shot and let me know if it works for you...

Related

Nhibernate Linq & operator RegisterFunction Firebird

I am using NHibernate with Firebird and would like to create the bitwise and operator to the Firebird function bin_and(a, b)
Something like this:
var result = customers.Where(c => (c.StatusValue & 3) > 0);
The above query will result in something like that:
select * from customers where (StatusValue & 3) > 0
Which is not valid in Firebird, the result should be:
select * from customers where bin_and(StatusValue,3) > 0
Is there a possibility to overwrite this translated result ?
Update
By declaring a function this is possible:
[LinqExtensionMethod("BIN_AND")]
public static int BinAnd(int a, int b)
{
return a & b;
}
var result = customers.Where(c => BinAnd(c.StatusValue, 3) > 0);
This works, but I am searching for a more generic way wizh the '&' or '|' operator...
Update:
# Fédéric:
I wrote my own Dialect class like this:
public class MyFirebirdDialect: FirebirdDialect {
public MyFirebirdDialect()
{
// Bitwise operations
RegisterFunction("band", new BitwiseFunctionOperation("bin_and"));
RegisterFunction("bor", new BitwiseFunctionOperation("bin_or"));
RegisterFunction("bxor", new BitwiseFunctionOperation("bin_xor"));
RegisterFunction("bnot", new BitwiseFunctionOperation("bin_not"));
}
}
I had to import the BitwiseFunctionOperation.cs too
If I debug the code I see that this class is used as Dialect, and I see that there is a custom function for the key 'band' that has a value 'bin_and' but a Query like this
var result = customers.Where(c => (c.StatusValue & 3) > 0);
ends up in an sql like this :
select * from customers where (StatusValue & 3) > 0
I think the linq parser does not its part...
Are you using the appropriate dialect? FirebirdDialect correctly defines bitwise and in HQL (RegisterFunction("band", new BitwiseFunctionOperation("bin_and")); and linq-to-nhibernate translate & (ExpressionType.And) to the appropriate HQL call.
If you are using an old NHibernate version, maybe you need to upgrade.
Firebird bitwise operators have been added with NH-3630 in NHibernate 4.1.
You may try to back-port them in your project by using a custom dialect deriving from FirebirdDialect and registering those additional functions as illustrated in the link above, within your custom dialect constructor.
But that will not work, because it requires some other changes in NHibernate internals, not available before NHibernate 4.1. Maybe by patching a local copy of NHibernate 3.4 sources may you succeed in doing that.

How to translate a QueryOver to DetachedCriteria?

I do not wish to know why it's better to use QueryOver and that it's newer.
How can I translate the following QueyOver to a DetachedCriteria:
QueryOver<Category>().Where(x => x.Properties.Any(y => y.Locales.Any(l => l.Value.Name == "propName")));
I don't know if the "Any" extension method is recognized by nhibernate but you can understand what I'm trying to accomplish.
var subquery = DetachedCriteria.For<Category>()
.CreateCriteria("Properties")
.CreateCriteria("Locales")
.Add(Expression.Eq("Name", "propName"));

Hibernate. Convert HQL to Criteria API

How to convert the following hql to Criteria API
var criteria = this.Session.CreateQuery("select m, m.Attachments.size from AdvanceMessage m");
?
Thanks
Your question is a little bit vague but it's something like this :
IList<AdvanceMessage> list = session.CreateCriteria(typeof(AdvanceMessage))
.List<AdvanceMessage>();

Linq to Nhiberate - Where clause

I have tried to find an answer to this, but could not find one in google. Probably not searching the correct terms, so thought I would ask here.
The following returns all my contacts, not the ones that equal the adjusterType sent in.
var contacts = from c in session.Linq<Contact>() select c;
contacts.Where(c => c.ContactAdjuster.AdjusterType == adjusterType);
The following does return the expected results. It does return only the contacts that meet the adjusterType. I believe it is my lack of understanding of LINQ.
var contacts = from c in session.Linq<Contact>() select c;
contacts = contacts.Where(c => c.ContactAdjuster.AdjusterType == adjusterType);
Thanks in advance.
the Where clause returns an IEnumerable in your case an IEnumerable. This is the standard LiNQ and C# behavior. Instead of modifying your collection it is returning a new collection based on your where clause.
I suppose NHibernate LiNQ should mimic this.
CatZ is absolutely right, you are not modifying the "contacts" collection/enumerable you are creating a new based on the existing, which is why your second statement works.
But instead of just repeating CatZ statement, here is a little add-on:
You can write this in one statement though
var contacts =
from c in session.Linq<Contact>()
where c.ContactAdjuster.AdjusterType == adjusterType
select c;
Or simply
var contacts = session.Linq<Contact>().Where(c => c.ContactAdjuster.AdjusterType == adjusterType);

Method 'Boolean Contains(System.String)' has no supported translation to SQL

"Method 'Boolean Contains(System.String)' has no supported translation to SQL."
query is IsQueryable but this stopped working:
foreach (string s in collection1)
{
if (s.Length > 0)
{
query = query.Where(m => m.collection2.Contains(s));
}
}
UPDATE: it works when i make query "ienumerable" instead of iqueryable. What would be the way to get same result using linq instead of iterating through loop?
Try this:
query = query.Where(m => m.collection2.ToList().Contains(s));
^^^^^^^^
Take a look at this answer from stackoverflow.
It looks like the resulting query would need access to something that the database
has no way of reaching, because the info is in memory.
Since m.collection2 is in the database, don't use Contains. Use Any
m.collection2.Any(x => x == s)
It looks like the error you are seeing is coming from the collection collection 2. Have you tried wrappering the m.collection2 in another function which returns true or false? Is this LINQ syntax?