Skip to content

Commit 450313b

Browse files
Merge pull request #1868 from fredericDelaporte/DbSideNowGuidRandom
Support DB side methods
2 parents 6c252ee + 3a8a1ba commit 450313b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1518
-56
lines changed

doc/reference/modules/configuration.xml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,57 @@ 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>true</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 <literal>DateTime.Now</literal>
732+
or <literal>Guid.NewGuid()</literal> to be always evaluated with the .Net runtime and replaced in the
733+
query by parameter values.
734+
</para>
735+
<para>
736+
The new pre-evaluation allows them to be converted to HQL function calls which will be run on the db
737+
side. This allows for example to retrieve the server time instead of the client time, or to generate
738+
UUIDs for each row instead of an unique one for all rows.
739+
</para>
740+
<para>
741+
The new pre-evaluation will likely be enabled by default in the next major version (6.0).
742+
</para>
743+
</entry>
744+
</row>
745+
<row>
746+
<entry>
747+
<literal>linqtohql.fallback_on_preevaluation</literal>
748+
</entry>
749+
<entry>
750+
When the new pre-evaluation is enabled, should methods which translation is not supported by the current
751+
dialect fallback to pre-evaluation? Defaults to <literal>false</literal>.
752+
<para>
753+
<emphasis role="strong">eg.</emphasis>
754+
<literal>true</literal> | <literal>false</literal>
755+
</para>
756+
<para>
757+
When this fallback option is enabled while legacy pre-evaluation is disabled, properties or functions
758+
like <literal>DateTime.Now</literal> or <literal>Guid.NewGuid()</literal> used in Linq expressions
759+
will not fail when the dialect does not support them, but will instead be pre-evaluated.
760+
</para>
761+
<para>
762+
When this fallback option is disabled while legacy pre-evaluation is disabled, properties or functions
763+
like <literal>DateTime.Now</literal> or <literal>Guid.NewGuid()</literal> used in Linq expressions
764+
will fail when the dialect does not support them.
765+
</para>
766+
<para>
767+
This option has no effect if the legacy pre-evaluation is enabled.
768+
</para>
769+
</entry>
770+
</row>
720771
<row>
721772
<entry>
722773
<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: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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(false, false)]
24+
[TestFixture(true, false)]
25+
[TestFixture(false, true)]
26+
public class PreEvaluationTestsAsync : LinqTestCase
27+
{
28+
private readonly bool LegacyPreEvaluation;
29+
private readonly bool FallbackOnPreEvaluation;
30+
31+
public PreEvaluationTestsAsync(bool legacy, bool fallback)
32+
{
33+
LegacyPreEvaluation = legacy;
34+
FallbackOnPreEvaluation = fallback;
35+
}
36+
37+
protected override void Configure(Configuration configuration)
38+
{
39+
base.Configure(configuration);
40+
41+
configuration.SetProperty(Environment.FormatSql, "false");
42+
configuration.SetProperty(Environment.LinqToHqlLegacyPreEvaluation, LegacyPreEvaluation.ToString());
43+
configuration.SetProperty(Environment.LinqToHqlFallbackOnPreEvaluation, FallbackOnPreEvaluation.ToString());
44+
}
45+
46+
private void RunTest(bool isSupported, Action<SqlLogSpy> test)
47+
{
48+
using (var spy = new SqlLogSpy())
49+
{
50+
try
51+
{
52+
test(spy);
53+
}
54+
catch (QueryException)
55+
{
56+
if (!isSupported && !FallbackOnPreEvaluation)
57+
// Expected failure
58+
return;
59+
throw;
60+
}
61+
}
62+
63+
if (!isSupported && !FallbackOnPreEvaluation)
64+
Assert.Fail("The test should have thrown a QueryException, but has not thrown anything");
65+
}
66+
67+
[Test]
68+
public async Task CanQueryByRandomIntAsync()
69+
{
70+
var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor");
71+
var idMin = await (db.Orders.MinAsync(o => o.OrderId));
72+
RunTest(
73+
isSupported,
74+
spy =>
75+
{
76+
var random = new Random();
77+
// Dodge a Firebird driver limitation by putting the constants before the order id.
78+
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
79+
// knowing the type of the condition. For some reasons the driver considers the casting should not be
80+
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
81+
// Firebird complain, so moving the constants on the left side have been put before the order id, in
82+
// order for these constants to be casted by the driver.
83+
var x = db.Orders.Count(o => -idMin - 1 + o.OrderId < random.Next());
84+
85+
Assert.That(x, Is.GreaterThan(0));
86+
// Next requires support of both floor and rand
87+
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
88+
});
89+
}
90+
91+
[Test]
92+
public async Task CanQueryByRandomIntWithMaxAsync()
93+
{
94+
var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor");
95+
var idMin = await (db.Orders.MinAsync(o => o.OrderId));
96+
RunTest(
97+
isSupported,
98+
spy =>
99+
{
100+
var random = new Random();
101+
// Dodge a Firebird driver limitation by putting the constants before the order id.
102+
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
103+
// knowing the type of the condition. For some reasons the driver considers the casting should not be
104+
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
105+
// Firebird complain, so moving the constants on the left side have been put before the order id, in
106+
// order for these constants to be casted by the driver.
107+
var x = db.Orders.Count(o => -idMin + o.OrderId <= random.Next(10));
108+
109+
Assert.That(x, Is.GreaterThan(0).And.LessThan(11));
110+
// Next requires support of both floor and rand
111+
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
112+
});
113+
}
114+
115+
[Test]
116+
public async Task CanQueryByRandomIntWithMinMaxAsync()
117+
{
118+
var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor");
119+
var idMin = await (db.Orders.MinAsync(o => o.OrderId));
120+
RunTest(
121+
isSupported,
122+
spy =>
123+
{
124+
var random = new Random();
125+
// Dodge a Firebird driver limitation by putting the constants before the order id.
126+
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
127+
// knowing the type of the condition. For some reasons the driver considers the casting should not be
128+
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
129+
// Firebird complain, so moving the constants on the left side have been put before the order id, in
130+
// order for these constants to be casted by the driver.
131+
var x = db.Orders.Count(o => -idMin + o.OrderId < random.Next(1, 10));
132+
133+
Assert.That(x, Is.GreaterThan(0).And.LessThan(10));
134+
// Next requires support of both floor and rand
135+
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
136+
});
137+
}
138+
139+
private void AssertFunctionInSql(string functionName, SqlLogSpy spy)
140+
{
141+
if (!IsFunctionSupported(functionName))
142+
Assert.Inconclusive($"{functionName} is not supported by the dialect");
143+
144+
var function = Dialect.Functions[functionName].Render(new List<object>(), Sfi).ToString();
145+
146+
if (LegacyPreEvaluation)
147+
Assert.That(spy.GetWholeLog(), Does.Not.Contain(function));
148+
else
149+
Assert.That(spy.GetWholeLog(), Does.Contain(function));
150+
}
151+
}
152+
}

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)