Skip to content

Commit 881af0f

Browse files
Support evaluation of DateTime.Now on db side
And of all similar properties: UtcNow, Today, and DateTimeOffset's ones. Part of #959
1 parent a58a56c commit 881af0f

33 files changed

+750
-30
lines changed

doc/reference/modules/configuration.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,28 @@ var session = sessions.OpenSession(conn);
717717
</para>
718718
</entry>
719719
</row>
720+
<row>
721+
<entry>
722+
<literal>linqtohql.legacy_preevaluation</literal>
723+
</entry>
724+
<entry>
725+
Whether to use the legacy pre-evaluation or not in Linq queries. Defaults to <literal>false</literal>.
726+
<para>
727+
<emphasis role="strong">eg.</emphasis>
728+
<literal>true</literal> | <literal>false</literal>
729+
</para>
730+
<para>
731+
Legacy pre-evaluation is causing special properties or functions like DateTime.Now or Guid.NewGuid()
732+
to be always evaluated with the .Net runtime and replaced in the query by parameter values.
733+
</para>
734+
<para>
735+
The new pre-evaluation allows them to be converted to HQL function calls which will be run on the db
736+
side. This allows by example to retrieve the server time instead of the client time, or to generate
737+
GUIDs for each row instead of an unique one for all rows. (This does not happen if the dialect does
738+
not support the required HQL function.)
739+
</para>
740+
</entry>
741+
</row>
720742
<row>
721743
<entry>
722744
<literal>sql_exception_converter</literal>

src/NHibernate.Test/Async/Linq/MiscellaneousTextFixture.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ public class MiscellaneousTextFixtureAsync : LinqTestCase
2727
[Test(Description = "This sample uses Count to find the number of Orders placed before yesterday in the database.")]
2828
public async Task CountWithWhereClauseAsync()
2929
{
30-
var q = from o in db.Orders where o.OrderDate <= DateTime.Today.AddDays(-1) select o;
30+
var yesterday = DateTime.Today.AddDays(-1);
31+
var q = from o in db.Orders where o.OrderDate <= yesterday select o;
3132

3233
var count = await (q.CountAsync());
3334

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System;
12+
using System.Collections.Generic;
13+
using System.Linq;
14+
using NHibernate.Cfg;
15+
using NHibernate.SqlTypes;
16+
using NUnit.Framework;
17+
using Environment = NHibernate.Cfg.Environment;
18+
using NHibernate.Linq;
19+
20+
namespace NHibernate.Test.Linq
21+
{
22+
using System.Threading.Tasks;
23+
[TestFixture]
24+
public class PreEvaluationTestsAsync : LinqTestCase
25+
{
26+
protected virtual bool LegacyPreEvaluation => false;
27+
28+
protected override void Configure(Configuration configuration)
29+
{
30+
base.Configure(configuration);
31+
32+
configuration.SetProperty(Environment.FormatSql, "false");
33+
if (LegacyPreEvaluation)
34+
configuration.SetProperty(Environment.LinqToHqlLegacyPreEvaluation, "true");
35+
}
36+
37+
[Test]
38+
public async Task CanQueryByDateTimeNowAsync()
39+
{
40+
using (var spy = new SqlLogSpy())
41+
{
42+
var x = await (db.Orders.Where(o => o.OrderDate.Value < DateTime.Now).ToListAsync());
43+
44+
Assert.That(x, Has.Count.GreaterThan(0));
45+
AssertFunctionInSql("current_timestamp", spy);
46+
}
47+
}
48+
49+
[Test]
50+
public async Task CanSelectDateTimeNowAsync()
51+
{
52+
using (var spy = new SqlLogSpy())
53+
{
54+
var x = await (db.Orders.Select(o => new { id = o.OrderId, d = DateTime.Now }).ToListAsync());
55+
56+
Assert.That(x, Has.Count.GreaterThan(0));
57+
AssertFunctionInSql("current_timestamp", spy);
58+
}
59+
}
60+
61+
[Test]
62+
public async Task CanQueryByDateTimeUtcNowAsync()
63+
{
64+
using (var spy = new SqlLogSpy())
65+
{
66+
var x = await (db.Orders.Where(o => o.OrderDate.Value < DateTime.UtcNow).ToListAsync());
67+
68+
Assert.That(x, Has.Count.GreaterThan(0));
69+
AssertFunctionInSql("current_utctimestamp", spy);
70+
}
71+
}
72+
73+
[Test]
74+
public async Task CanSelectDateTimeUtcNowAsync()
75+
{
76+
using (var spy = new SqlLogSpy())
77+
{
78+
var x = await (db.Orders.Select(o => new { id = o.OrderId, d = DateTime.UtcNow }).ToListAsync());
79+
80+
Assert.That(x, Has.Count.GreaterThan(0));
81+
AssertFunctionInSql("current_utctimestamp", spy);
82+
}
83+
}
84+
85+
[Test]
86+
public async Task CanQueryByDateTimeTodayAsync()
87+
{
88+
using (var spy = new SqlLogSpy())
89+
{
90+
var x = await (db.Orders.Where(o => o.OrderDate.Value < DateTime.Today).ToListAsync());
91+
92+
Assert.That(x, Has.Count.GreaterThan(0));
93+
AssertFunctionInSql("current_date", spy);
94+
}
95+
}
96+
97+
[Test]
98+
public async Task CanSelectDateTimeTodayAsync()
99+
{
100+
using (var spy = new SqlLogSpy())
101+
{
102+
var x = await (db.Orders.Select(o => new { id = o.OrderId, d = DateTime.Today }).ToListAsync());
103+
104+
Assert.That(x, Has.Count.GreaterThan(0));
105+
AssertFunctionInSql("current_date", spy);
106+
}
107+
}
108+
109+
[Test]
110+
public async Task CanQueryByDateTimeOffsetTimeNowAsync()
111+
{
112+
if (!TestDialect.SupportsSqlType(SqlTypeFactory.DateTimeOffSet))
113+
Assert.Ignore("Dialect does not support DateTimeOffSet");
114+
115+
using (var spy = new SqlLogSpy())
116+
{
117+
var testDate = DateTimeOffset.Now.AddDays(-1);
118+
var x = await (db.Orders.Where(o => testDate < DateTimeOffset.Now).ToListAsync());
119+
120+
Assert.That(x, Has.Count.GreaterThan(0));
121+
AssertFunctionInSql("current_timestamp_offset", spy);
122+
}
123+
}
124+
125+
[Test]
126+
public async Task CanSelectDateTimeOffsetNowAsync()
127+
{
128+
if (!TestDialect.SupportsSqlType(SqlTypeFactory.DateTimeOffSet))
129+
Assert.Ignore("Dialect does not support DateTimeOffSet");
130+
131+
using (var spy = new SqlLogSpy())
132+
{
133+
var x = await (db.Orders.Select(o => new { id = o.OrderId, d = DateTimeOffset.Now }).ToListAsync());
134+
135+
Assert.That(x, Has.Count.GreaterThan(0));
136+
AssertFunctionInSql("current_timestamp_offset", spy);
137+
}
138+
}
139+
140+
[Test]
141+
public async Task CanQueryByDateTimeOffsetUtcNowAsync()
142+
{
143+
if (!TestDialect.SupportsSqlType(SqlTypeFactory.DateTimeOffSet))
144+
Assert.Ignore("Dialect does not support DateTimeOffSet");
145+
146+
using (var spy = new SqlLogSpy())
147+
{
148+
var testDate = DateTimeOffset.UtcNow.AddDays(-1);
149+
var x = await (db.Orders.Where(o => testDate < DateTimeOffset.UtcNow).ToListAsync());
150+
151+
Assert.That(x, Has.Count.GreaterThan(0));
152+
AssertFunctionInSql("current_utctimestamp_offset", spy);
153+
}
154+
}
155+
156+
[Test]
157+
public async Task CanSelectDateTimeOffsetUtcNowAsync()
158+
{
159+
if (!TestDialect.SupportsSqlType(SqlTypeFactory.DateTimeOffSet))
160+
Assert.Ignore("Dialect does not support DateTimeOffSet");
161+
162+
using (var spy = new SqlLogSpy())
163+
{
164+
var x = await (db.Orders.Select(o => new { id = o.OrderId, d = DateTimeOffset.UtcNow }).ToListAsync());
165+
166+
Assert.That(x, Has.Count.GreaterThan(0));
167+
AssertFunctionInSql("current_utctimestamp_offset", spy);
168+
}
169+
}
170+
171+
private void AssertFunctionInSql(string functionName, SqlLogSpy spy)
172+
{
173+
if (!IsFunctionSupported(functionName))
174+
Assert.Inconclusive($"{functionName} is not supported by the dialect");
175+
176+
var function = Dialect.Functions[functionName].Render(new List<object>(), Sfi).ToString();
177+
178+
if (LegacyPreEvaluation)
179+
Assert.That(spy.GetWholeLog(), Does.Not.Contain(function));
180+
else
181+
Assert.That(spy.GetWholeLog(), Does.Contain(function));
182+
}
183+
}
184+
185+
[TestFixture]
186+
public class PreEvaluationLegacyTestsAsync : PreEvaluationTestsAsync
187+
{
188+
protected override bool LegacyPreEvaluation => true;
189+
}
190+
}

src/NHibernate.Test/Linq/MiscellaneousTextFixture.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ from s in db.Shippers
2727
[Test(Description = "This sample uses Count to find the number of Orders placed before yesterday in the database.")]
2828
public void CountWithWhereClause()
2929
{
30-
var q = from o in db.Orders where o.OrderDate <= DateTime.Today.AddDays(-1) select o;
30+
var yesterday = DateTime.Today.AddDays(-1);
31+
var q = from o in db.Orders where o.OrderDate <= yesterday select o;
3132

3233
var count = q.Count();
3334

0 commit comments

Comments
 (0)