Is there a way to set an SQL comment from an IQueryable? - nhibernate

ICriteria has SetComment(), but I see nothing comparable for IQueryable.

In NHibernate 5+ there is WithOptions extension method that allows to set some query specific options like timeouts, cache options, and comments.
var query = (
from e in session.Query<YourEntity>()
select e
).WithOptions(o => o.SetComment("Your comment"));
You might need to import NHibernate.Linq namespace.

Related

NHibernate - How to log Named Parameterised Query with parameter values?

I have a parameterised named Query like this :
Query moveOutQuery = session.createSQLQuery(moveOutQueryStr.toString())
.addEntity(MyClass.class)
.setParameter("assignmentStatus", Constants.CHECKED_OUT)
I want to see the actual SQL query with parameters filled in. However while debugging I only get the following query:
Select * from my_assignment WHERE assignment_status in ( :assignmentStatus )
Why isn't the assignmentStatus being substituted for its real value?
Why isn't the assignmentStatus being substituted for its real value?
This is because NHibernate use query parameters to input values. This is efficient in many cases and also helpful against SQL Injection attack. Parameters are sent separately. You can find them at the bottom if SQL is logged as explained below.
You may log each SQL to file as explained below.
This is implemented through log4net.dll; you need to add reference.
Add namespaces as below:
using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Layout;
using log4net.Repository.Hierarchy;
Configure log4net in NHibernate as below:
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.RemoveAllAppenders();
FileAppender fileAppender = new FileAppender();
fileAppender.Name = "NHFileAppender";
fileAppender.File = logFilePath;
fileAppender.AppendToFile = true;
fileAppender.LockingModel = new FileAppender.MinimalLock();
fileAppender.Layout = new PatternLayout("%d{yyyy-MM-dd HH:mm:ss}:%m%n%n");
fileAppender.ActivateOptions();
Logger logger = hierarchy.GetLogger("NHibernate.SQL") as Logger;
logger.Additivity = false;
logger.Level = Level.Debug;
logger.AddAppender(fileAppender);
hierarchy.Configured = true;
You also need to set ShowSql while configuration as below:
configuration.SetProperty(NHibernate.Cfg.Environment.ShowSql, "true");
configuration.SetProperty(NHibernate.Cfg.Environment.FormatSql, "true");
You need to call this code once at startup of your application. Output log includes values of parameters as well.
Following is the code:
session.CreateSQLQuery("SELECT * FROM MyEntity WHERE MyProperty = :MyProperty")
.AddEntity(typeof(MyEntity))
.SetParameter("MyProperty", "filterValue")
.UniqueResult<MyEntity>();
Following is the logged query:
2020-01-09 14:25:39:
SELECT
*
FROM
MyEntity
WHERE
MyProperty = #p0;
#p0 = 'filterValue' [Type: String (4000:0:0)]
As you can see, parameter value filterValue is listed at the bottom.
This works for all query APIs like IQueryOver, IQuery, ISQLQuery etc.
This logs both success and failed statements. You can play with FileAppender and Logger class to meet your additional requirements.
Also refer PatternLayout from documentation. More details can also be found here, here and here. This Q/A discusses the same.
Following Q/A may also help:
Get executed SQL from nHibernate
Using log4net to write to different loggers
How to log SQL calls with NHibernate to the console of Visual Studio?
As you see, this logs the parameter values at bottom of the query. If you want those logged embedded in the query, please refer to this article.

From within a grails HQL, how would I use a (non-aggregate) Oracle function?

If I were retrieving the data I wanted from a plain sql query, the following would suffice:
select * from stvterm where stvterm_code > TT_STUDENT.STU_GENERAL.F_Get_Current_term()
I have a grails domain set up correctly for this table, and I can run the following code successfully:
def a = SaturnStvterm.findAll("from SaturnStvterm as s where id > 201797") as JSON
a.render(response)
return false
In other words, I can hardcode in the results from the Oracle function and have the HQL run correctly, but it chokes any way that I can figure to try it with the function. I have read through some of the documentation on Hibernate about using procs and functions, but I'm having trouble making much sense of it. Can anyone give me a hint as to the proper way to handle this?
Also, since I think it is probably relevant, there aren't any synonyms in place that would allow the function to be called without qualifying it as schema.package.function(). I'm sure that'll make things more difficult. This is all for Grails 1.3.7, though I could use a later version if needed.
To call a function in HQL, the SQL dialect must be aware of it. You can add your function at runtime in BootStrap.groovy like this:
import org.hibernate.dialect.function.SQLFunctionTemplate
import org.hibernate.Hibernate
def dialect = applicationContext.sessionFactory.dialect
def getCurrentTerm = new SQLFunctionTemplate(Hibernate.INTEGER, "TT_STUDENT.STU_GENERAL.F_Get_Current_term()")
dialect.registerFunction('F_Get_Current_term', getCurrentTerm)
Once registered, you should be able to call the function in your queries:
def a = SaturnStvterm.findAll("from SaturnStvterm as s where id > TT_STUDENT.STU_GENERAL.F_Get_Current_term()")

2nd level cache problem with join query

I want to use Second level Cache for my query with eager loading(query is below wrote in 3 different ways, i use query cache). I have standard one to many association. I set entity cache for parent, child, and association between parent and class. And the 2nd level cache doesn't work because i got exceptions.
I wrote my query in 3 different way:
Criteria:
session.CreateCriteria<DictionaryMaster>().SetFetchMode("DictionaryItems", FetchMode.Eager)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.SetCacheable(true).SetCacheMode(CacheMode.Normal)
.List<DictionaryMaster>().ToList();
When I invoked this query i got exception "Unable to perform find[SQL: SQL not available]"
I think that the problem exists because I use DistinctRootEntityResultTransformer transform. I will start create my custom transform class and I hope that will work.
Query over:
session.QueryOver<DictionaryMaster>().Fetch(x => x.DictionaryItems).Eager
.TransformUsing(new DistinctRootEntityResultTransformer())
.Cacheable().CacheMode(CacheMode.Normal)
.List<DictionaryMaster>().ToList();
Exception is the same as in Criteria.
Linq:
session.Query<DictionaryMaster>().Fetch(x => x.DictionaryItems).Cacheable().CacheMode(CacheMode.Normal).ToList();
Here error depends from the version of nhibernate in 3.1 a got this error https://nhibernate.jira.com/browse/NH-2587?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel
but in 3.2 version i got this: https://nhibernate.jira.com/browse/NH-2856
Thanks in advance
sJHony I have found solution, but for me is more like workaround. Therefore if you know any other solution give me sign.
I utilize QueryOver without any transformation, the fault of this solution is that the query return elements equal amount of childs. Next I retrieve not multiplied list in memory using distinct.
This solution is ok, but when we add one more Fetch for query, then collection in object also be multiplied, that is why i modified collection type from IList(Bag) to ISet(Set).
Code looks like:
var queryCacheResult =
session.QueryOver<DictionaryMaster>()
.Fetch(x => x.DictionaryItems).Eager
.Cacheable().CacheMode(CacheMode.Normal)
.List<DictionaryMaster>().ToList();
return queryCacheResult.Distinct(new KeyEqualityComparer<DictionaryMaster>(x => x.Code)).ToList();

Can I use SQL functions in NHibernate QueryOver?

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...

How should I use navigation properties while writing a query using eSQL?

I am trying to write a query using eSQL wherein my entity has got navigation properties. I am not able to include these navigation properties in the query, even though in Linq to SQL we have this (Include method).
How will it be possible in eSQL?
Like so:
string esql = "Select value e from EFEntities.MyDataEntity as e";
ObjectQuery<Data.MyDataEntity> query = c.
CreateQuery<Data.MyDataEntity>(esql).
Include("MyNavigationProperty");
List<Data.MyDataEntity> entities = query.ToList();