If I have these models mapped in NHibernate:
public class TagActions {
public Tag Tag { get; set; }
public DateTime ChangeTime { get; set; }
}
public class Tag {
public string Label { get; set; }
}
And do the following:
// repo.TagActions is IQueryable<TagAction> from session.Query<TagAction>()
var stake = DateTime.UtcNow - TimeSpan.FromDays(120);
repo.TagActions.Where(ta => ta.ChangeTime > stake)
.OrderByDescending(ta => ta.ChangeTime)
.Select(ta => ta.Tag).Distinct().Take(10);
It produces (in the MsSql2012Dialect
dialect):
select
distinct tag1_.Label as label1_12_,
tag1_.Color as color2_12_
from
TagAction tagaction0_
left outer join
Tag tag1_
on tagaction0_.Tag=tag1_.Label
where
tagaction0_.ChangeTime>@p0
order by
tagaction0_.ChangeTime desc OFFSET 0 ROWS FETCH FIRST @p1 ROWS ONLY;
@p0 = 2020-04-02T10:40:54.0038780Z [Type: DateTime2 (8:0:0)],
@p1 = 10 [Type: Int32 (0:0:0)]
Which is great except for the problem that ChangeTime
does not appear in the SELECT
clause, so MSSQL fails and rejects the query. The SQLiteDialect
produces SQL with the same problem, but SQLite processes the query regardless. I am pretty sure that technically MSSQL's response is correct per the SQL spec.
Question part 1:
This has to be a bug in NHibernate, correct? I did find this:
MSSql2012Dialect generates invalid order by clause for paging distinct query
but it only shows there as applying to 4.0 (alpha) and I'm on 5.2.7. Anyone else have a known bug report on this?
Question part 2:
Any proposed workaround with session.Query<TagAction>
/Linq? I am loath to inject .ToList()
after OrderByDescending(...)
, which works, but there may be a large number of TagAction
s and only a small number of Tag
s to return. Any way to trick it into including the ChangeTime
column in the SELECT
clause and still do the DISTINCT
? I could potentially drop down to HQL or ICriteria
or something but have no experience with those yet.