I'm trying to write a query to select using the DateTime. Year as a where parameter, but I'm receiving this error from nunit:
NHibernate.QueryException : could not resolve property: Register.Year of: Estudantino.Domain.Events
In class Events I've a property named Register as a DateTime type.
public virtual DateTime Registada { get; set; }
This is the method that is returning the error:
using (ISession session = NHibernateHelper.OpenSession())
{
return session.QueryOver<Evento>()
.Where(x => x.Register.Year == year)
.List();
}
The variable year is of type int, that is been passed to the method.
Does anyone have an idea of what i'm doing wrong? My database server is SQL Server 2005 Express.
QueryOver does not resolve things like DateTime.Year.
Use LINQ instead:
return session.Query<Evento>()
.Where(x => x.Register.Year == year)
.ToList();
In QueryOver, you can just say:
dateTimeColumn.YearPart() == 1999
There is also other extension methods: MonthPart(), DayPart(), etc.
You may need to use HQL here instead. Basically NHibernate does not know really what to do with year. I suspect you need to use the RegisterFunction to register a YEAR function.
Please read this article in its entirety to fully understand what it is you are trying to do.
Create a custom dialect in code
Create a function in SQL server called MyYearFunction that returns a year for a date
Then use HQL (not sure if QueryOver can do this) to get the date where dbo.MyYearFunction(:date) = 12" ...
.Where(x => x.Register >= new DateTime(year, 1, 1) && x.Register <
new DateTime(year + 1, 1, 1))
Related
I need to conditionally add a filter to particular dates in a query. There are common preconditions and the filter will be the same. Therefore I would like the common code to be in a method which can perform these checks and then have the consumer pass in the property which the filter should be applied to (could be applied to multiple).
Here is a simplified version of my code.
var query = dbContext.Documents.AsQueryable();
query = FilterDocumentsByDate(query, x => x.CreatedDate);
query = FilterDocumentsByDate(query, x => x.SubmittedDate);
private IQueryable<Document> FilterDocumentsByDate(IQueryable<Document> query, Func<Document, DateTime> propertyToSearch)
{
query = query.Where(x => propertyToSearch(x).Year > 2000);
return query;
}
When I look at the query in SQL profiler, I can see that the query is missing the WHERE clause (so all documents are being retrieved and the filter is being done in memory). If I copy/paste the code inline for both dates (instead of calling the method twice) then the WHERE clause for the both dates are included in the query.
Is there no way to add a WHERE condition to an IQueryable by passing a property in a Func which can be properly translated to SQL by Entity Framework?
EF is unable to understand your query, so it breaks and executes WHERE clause in memory.
The solution is creating dynamic expressions.
var query = dbContext.Documents.AsQueryable();
query = FilterDocumentsByDate(query, x => x.CreatedDate.Year);
query = FilterDocumentsByDate(query, x => x.SubmittedDate.Year);
private IQueryable<Document> FilterDocumentsByDate(IQueryable<Document> query, Expression<Func<Document, int>> expression)
{
var parameter = expression.Parameters.FirstOrDefault();
Expression comparisonExpression = Expression.Equal(expression.Body, Expression.Constant(2000));
Expression<Func<Document, bool>> exp = Expression.Lambda<Func<Document, bool>>(comparisonExpression, parameter);
query = query.Where(exp);
return query;
}
I am sorry, I haven't run this myself, but this should create WHERE statement. Let me know how it goes.
I have query:
var query = this.session.QueryOver<Products>()
.Where(uic => uic.PageNumber == nextPage[0])
.SingleOrDefault(uic => uic.ProductNumber)
But this query result is type Products. It is possible that result will be only integer type of column ProductNumber ?
Try something like this:
var query = this.session.QueryOver<Products>()
.Where(uic => uic.PageNumber == nextPage[0])
.Select(uic => uic.ProductNumber)
.SingleOrDefault<int>();
Since you need a single primitive type value, you can do .Select to define the result column, and then do .SingleOrDefault to get the only result. For complex types, you'd need to use transformers.
You can find more info about QueryOver in this blog post on nhibernate.info: http://nhibernate.info/blog/2009/12/17/queryover-in-nh-3-0.html
You can use Miroslav's answer for QueryOver, but this would look cleaner with LINQ:
var productNumber = session.Query<Products>()
.Where(uic => uic.PageNumber == nextPage[0])
.Select(uic => uic.ProductNumber)
.SingleOrDefault();
Notice you don't need a cast, as the Select operator changes the expression type to the return type of its parameter (which is the type of ProductNumber).
I'm converting an MSSQL query to NHibernate. In essence, this is my SQL:
SELECT * FROM MyTable as T
WHERE (T.Value1 - T.Value2 > 0.01)
And this is my C# code:
var query = QueryOver.Of<MyType> ()
.Where(r => (r.Value1 - r.Value2 > 0.01));
and it's giving me an exception:
Could not determine member from (r.Value1 - r.Value2)
I'm sure there's a way to let the database do the calculation. Does anyone know?
Predicates within QueryOver.Where() can generally only be very simple comparison expressions. QueryOver dos not support arithmetic operations within delegates (r.Value1 - r.Value2). As #Rippo has pointed out You need to fallback to ICriterion.
.QueryOver<MyType>()
.Where(
Expression.Gt(
Projections.SqlProjection("{{alias}}.rValue1 - {{alias}}.rValue2", null, null),
0.01
)
)
In sql query you use "MyTable" but in QueryOver: "MyType"
reading back on this, I wanted to share the solution that ended up in production: mapping a readonly formula in FluentNHibernate.
the model needs to have a Property like this:
public virtual decimal Difference { get { return Value2 - Value1; } protected set; }
and this property should be mapped as follows:
Map(x => x.Difference).Formula("(Value2 - Value1)").Readonly();
the string parameter of the Formula method ends up in the SQL Select query, similar to this :
Select Id, Value1, Value2, (Value2 - Value1) from MyTable...
Note that the calculated property needs to have a protected setter or NHibernate will throw an exception saying that no setter is available.
I have a fairly run-of-the-mill QueryOver query containing the following,
.SelectList(list => list
.SelectGroup(() => txn.GroupField)
.SelectGroup(() => txn.Date))
.List<object[]>()
This query works as expected however I now have a requirement to group by the truncated Date as some of the Date's for these objects may contain a time component. This seems like it should be a trivial change but I can't find a way that is supported by NHibernate.
The obvious solution would be the change below but is not supported.
.SelectGroup(() => txn.Date.Date))
Any ideas?
Thanks
Your QueryOver could look like this:
Status alias = null;
var query = QueryOver.Of(() => alias)
.Select(Projections.GroupProperty(
Projections.SqlFunction("date", NHibernateUtil.Date, Projections.Property(() => alias.Date))));
Output (pseudo sql):
SELECT
...
FROM [Status] this_
GROUP BY dateadd(dd, 0, datediff(dd, 0, this_.Date))
Hope this helps, cheers!
You might want to add a helper property to your map, using the Formula command, to be able to use the date (instead of datetime) in queries.
here's an example from my code; it uses a decimal value, but this works fine with any subquery:
model class has this property, to be mapped to a formula:
public virtual decimal Profit
{
get { return this.SellPrice - this.Cost; }
set { return; }
}
fluentNHibernate map:
//SellPrice and Cost are columns in the object's table
Map(v => v.Profit).Formula("(SellPrice - Cost)"); // this field is calculated, not read
be sure to put the formula between () brackets though.
If you'd make your formula a select query that trunks the datetime into a date, you could then group by that property in your query.
the title says pretty much what I'm trying to do. I have nhibernate hql with select case
select application.SubmissionDate, count(candidates)
from Application as application group by application.SubmissionDate
I would like to have the return values from this query into an object (which is not in nhibernate mapping file) called 'CountPerDay' object
class CountPerDay {
public DateTime Date,
public int Count
}
does nHibernate has sort of build in feature /methods to do this?
You should take a look at Ad-hoc mapping for NHibernate:
string hql = #"select application.SubmissionDate as Date, count(candidates) as Count
from Application as application
group by application.SubmissionDate";
var count = session.CreateQuery(hql)
.SetResultTransformer(Transformers.AliasToBean(typeof(CountPerDay)))
.List<CountPerDay>();