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.
Related
Please help me to convert this SQL query to Linq
SELECT convert(varchar, data_acquisto, 101) as data , SUM(quantita)
FROM Acquisto
WHERE data_acquisto >= DATEADD(month,-1,GETDATE())
GROUP BY convert(varchar, data_acquisto, 101)
This is what I've tried:
var a = from acq in ctx.Acquisto
where acq.data_acquisto >= data
group acq.data_acquisto.ToString("dd/MM/yyyy")
by new { acq.data_acquisto, acq.quantita } into x
select new ListaGrafico()
{
data = x.Key.data_acquisto.ToString("dd/MM/yyyy"),
qta = Convert.ToInt32(x.Key.quantita)
};
This is the error I get:
LINQ to Entities not recognizes the method 'System.String ToString(System.String)'
The Grouping doesn't look correct - the Sql is only grouping by the Date part of the DateTime column. A Linq IGrouping will contain all values grouped by each grouping Key, so no need for the anonymous grouping class.
Convert() will be difficult to convert from Linq to Sql, so I've materialized the data into memory after applying the predicate and done the conversion in Linq to Objects.
I'm afraid I've used the Lambda syntax:
var result = ctx.Acquisto
.Where(acq => acq.data_acquisto >= DateTime.Now.AddMonths(-1))
.ToList()
.GroupBy(acq => acq.data_acquisto.Date)
.Select(x => new ListaGrafico
{
data = x.Key.Date.ToString("dd/MM/yyyy"),
qta = x.Sum(acq => acq.quantita)
});
Also, if possible, I would recommend retaining the Date in a DateTime struct in preference to a string - this would mean changing the data property of ListaGrafico from string to DateTime and then you can omit the .ToString("dd/MM/yyyy") in the final Select projection.
I need help to convert following ql query to Linq to Sql query.
select Name, Address
from Entity
group by Name, Address
having count(distinct LinkedTo) = 1
Idea is to find all unique Name, Address pairs who only have 1 distinct LinkedTo value. Remember that there are other columns in the table as well.
I would try something like this:
Entity.GroupBy(e => new { e.Name, e.Address})
.Where(g => g.Select(e => e.LinkedTo).Distinct().Count() == 1)
.Select(g => g.Key);
You should put a breakpoint after that line and check the SQL that is generated to find what is really going to the database.
You could use:
from ent in Entities
group ent by new { ent.Name, ent.Address } into grouped
where grouped.Select(g => g.LinkedTo).Distinct().Count() == 1
select new { grouped.Key.Name, grouped.Key.Address }
The generated SQL does not use a having clause. I'm not sure LINQ can generate that.
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'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))