I want to translate following simple sql query into Linq to NHibernate:
SELECT NewsId
,sum(n.UserHits) as 'HitsNumber'
,sum(CASE WHEN n.UserHits > 0 THEN 1 ELSE 0 END) as 'VisitorsNumber'
FROM UserNews n
GROUP BY n.NewsId
My simplified UserNews class:
public class AktualnosciUzytkownik
{
public virtual int UserNewsId { get; set; }
public virtual int UserHits { get; set; }
public virtual User User { get; set; } // UserId key in db table
public virtual News News { get; set; } // NewsId key in db table
}
I've written following linq query:
var hitsPerNews = (from n in Session.Query<UserNews>()
group n by n.News.NewsId into g
select new { NewsId = g.Key, HitsNumber = g.Sum(x => x.UserHits),
VisitorsNumber = g.Count(x => x.UserHits > 0) }).ToList();
But generated sql just ignores my x => x.UserHits > 0
statement and makes unnecessary 'left outer join':
SELECT news1_.NewsId AS col_0_0_,
CAST(SUM(news0_.UserHits) AS INT) AS col_1_0_,
CAST(COUNT(*) AS INT) AS col_2_0_
FROM UserNews news0_
LEFT OUTER JOIN News news1_
ON news0_.NewsId=news1_.NewsId
GROUP BY news1_.NewsId
How Can I fix or workaround this issue? Maybe this can be done better with QueryOver syntax?
I finally found answer to my question, my solution is based on an answer to this question:
My QueryOver code (I still don't know how to do it in Linq to NHibernate):
UserHitsDto adDtoAlias = null;
var userHits = Session.QueryOver<UserNews>()
.Select(Projections.Group<UserNews>(c => c.News.NewsId)
.WithAlias(() => adDtoAlias.NewsId),
Projections.Sum<UserNews>(x => x.UserHits)
.WithAlias(() => adDtoAlias.HitsNumber),
Projections.Sum(Projections.Conditional(
Restrictions.Where<UserNews>(f => f.UserHits > 0),
Projections.Constant(1),
Projections.Constant(0)
)).WithAlias(() => adDtoAlias.VisitorsNumber)
)
.TransformUsing(Transformers.AliasToBean<UserHitsDto>())
.List<UserHitsDto>();
It produces following tsql:
SELECT this_.NewsId AS y0_,
SUM(this_.UserHits) AS y1_,
SUM((
CASE
WHEN this_.UserHits > @p0
THEN @p1
ELSE @p2
END)) AS y2_
FROM UserNews this_
GROUP BY this_.NewsId
where @p0 = 0, @p1 = 1, @p2 = 0