Skip to content

Commit 8219bd2

Browse files
Support evaluation of Guid.NewGuid() on db side
Part of #959
1 parent eae465d commit 8219bd2

17 files changed

+189
-11
lines changed

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,40 @@ public async Task CanSelectDateTimeOffsetUtcNowAsync()
324324
Assert.Fail("The test should have thrown a QueryException, but has not thrown anything");
325325
}
326326

327+
[Test]
328+
public async Task CanQueryByNewGuidAsync()
329+
{
330+
if (!TestDialect.SupportsSqlType(SqlTypeFactory.Guid))
331+
Assert.Ignore("Guid are not supported by the target database");
332+
333+
using (var spy = new SqlLogSpy())
334+
{
335+
var guid = Guid.NewGuid();
336+
var x = await (db.Orders.CountAsync(o => guid != Guid.NewGuid()));
337+
338+
Assert.That(x, Is.GreaterThan(0));
339+
AssertFunctionInSql("new_uuid", spy);
340+
}
341+
}
342+
343+
[Test]
344+
public async Task CanSelectNewGuidAsync()
345+
{
346+
if (!TestDialect.SupportsSqlType(SqlTypeFactory.Guid))
347+
Assert.Ignore("Guid are not supported by the target database");
348+
349+
using (var spy = new SqlLogSpy())
350+
{
351+
var x =
352+
await (db
353+
.Orders.Select(o => new { id = o.OrderId, g = Guid.NewGuid() })
354+
.OrderBy(o => o.id).Take(1).ToListAsync());
355+
356+
Assert.That(x, Has.Count.GreaterThan(0));
357+
AssertFunctionInSql("new_uuid", spy);
358+
}
359+
}
360+
327361
private void AssertFunctionInSql(string functionName, SqlLogSpy spy)
328362
{
329363
if (!IsFunctionSupported(functionName))

src/NHibernate.Test/Linq/PreEvaluationTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,40 @@ public void CanSelectDateTimeOffsetUtcNow()
312312
Assert.Fail("The test should have thrown a QueryException, but has not thrown anything");
313313
}
314314

315+
[Test]
316+
public void CanQueryByNewGuid()
317+
{
318+
if (!TestDialect.SupportsSqlType(SqlTypeFactory.Guid))
319+
Assert.Ignore("Guid are not supported by the target database");
320+
321+
using (var spy = new SqlLogSpy())
322+
{
323+
var guid = Guid.NewGuid();
324+
var x = db.Orders.Count(o => guid != Guid.NewGuid());
325+
326+
Assert.That(x, Is.GreaterThan(0));
327+
AssertFunctionInSql("new_uuid", spy);
328+
}
329+
}
330+
331+
[Test]
332+
public void CanSelectNewGuid()
333+
{
334+
if (!TestDialect.SupportsSqlType(SqlTypeFactory.Guid))
335+
Assert.Ignore("Guid are not supported by the target database");
336+
337+
using (var spy = new SqlLogSpy())
338+
{
339+
var x =
340+
db
341+
.Orders.Select(o => new { id = o.OrderId, g = Guid.NewGuid() })
342+
.OrderBy(o => o.id).Take(1).ToList();
343+
344+
Assert.That(x, Has.Count.GreaterThan(0));
345+
AssertFunctionInSql("new_uuid", spy);
346+
}
347+
}
348+
315349
private void AssertFunctionInSql(string functionName, SqlLogSpy spy)
316350
{
317351
if (!IsFunctionSupported(functionName))

src/NHibernate/Dialect/FirebirdDialect.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ private void OverrideStandardHQLFunctions()
423423
RegisterFunction("strguid", new StandardSQLFunction("uuid_to_char", NHibernateUtil.String));
424424
RegisterFunction("sysdate", new CastedFunction("today", NHibernateUtil.Date));
425425
RegisterFunction("date", new SQLFunctionTemplate(NHibernateUtil.Date, "cast(?1 as date)"));
426+
RegisterFunction("new_uuid", new NoArgSQLFunction("gen_uuid", NHibernateUtil.Guid));
426427
// Bitwise operations
427428
RegisterFunction("band", new Function.BitwiseFunctionOperation("bin_and"));
428429
RegisterFunction("bor", new Function.BitwiseFunctionOperation("bin_or"));

src/NHibernate/Dialect/HanaDialectBase.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ protected virtual void RegisterNHibernateFunctions()
395395
RegisterFunction("iif", new SQLFunctionTemplate(null, "case when ?1 then ?2 else ?3 end"));
396396
RegisterFunction("sysdate", new NoArgSQLFunction("current_timestamp", NHibernateUtil.DateTime, false));
397397
RegisterFunction("truncate", new SQLFunctionTemplateWithRequiredParameters(null, "floor(?1 * power(10, ?2)) / power(10, ?2)", new object[] { null, "0" }));
398+
RegisterFunction("new_uuid", new NoArgSQLFunction("sysuuid", NHibernateUtil.Guid, false));
398399
}
399400

400401
protected virtual void RegisterHANAFunctions()

src/NHibernate/Dialect/MsSql2000Dialect.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,8 @@ protected virtual void RegisterFunctions()
359359

360360
RegisterFunction("bit_length", new SQLFunctionTemplate(NHibernateUtil.Int32, "datalength(?1) * 8"));
361361
RegisterFunction("extract", new SQLFunctionTemplate(NHibernateUtil.Int32, "datepart(?1, ?3)"));
362+
363+
RegisterFunction("new_uuid", new NoArgSQLFunction("newid", NHibernateUtil.Guid));
362364
}
363365

364366
protected virtual void RegisterGuidTypeMapping()

src/NHibernate/Dialect/MsSqlCeDialect.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ protected virtual void RegisterFunctions()
200200

201201
RegisterFunction("bit_length", new SQLFunctionTemplate(NHibernateUtil.Int32, "datalength(?1) * 8"));
202202
RegisterFunction("extract", new SQLFunctionTemplate(NHibernateUtil.Int32, "datepart(?1, ?3)"));
203+
204+
RegisterFunction("new_uuid", new NoArgSQLFunction("newid", NHibernateUtil.Guid));
203205
}
204206

205207
protected virtual void RegisterDefaultProperties()

src/NHibernate/Dialect/MySQL5Dialect.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@ public MySQL5Dialect()
1212
// My SQL supports precision up to 65, but .Net is limited to 28-29.
1313
RegisterColumnType(DbType.Decimal, 29, "DECIMAL($p, $s)");
1414
RegisterColumnType(DbType.Guid, "BINARY(16)");
15+
}
16+
17+
protected override void RegisterFunctions()
18+
{
19+
base.RegisterFunctions();
1520

1621
RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "concat(hex(reverse(substr(?1, 1, 4))), '-', hex(reverse(substring(?1, 5, 2))), '-', hex(reverse(substr(?1, 7, 2))), '-', hex(substr(?1, 9, 2)), '-', hex(substr(?1, 11)))"));
22+
RegisterFunction("new_uuid", new NoArgSQLFunction("uuid", NHibernateUtil.Guid));
1723
}
1824

1925
protected override void RegisterCastTypes()

src/NHibernate/Dialect/Oracle8iDialect.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ protected virtual void RegisterFunctions()
310310
RegisterFunction("bor", new SQLFunctionTemplate(null, "?1 + ?2 - BITAND(?1, ?2)"));
311311
RegisterFunction("bxor", new SQLFunctionTemplate(null, "?1 + ?2 - BITAND(?1, ?2) * 2"));
312312
RegisterFunction("bnot", new SQLFunctionTemplate(null, "(-1 - ?1)"));
313+
314+
RegisterFunction("new_uuid", new NoArgSQLFunction("sys_guid", NHibernateUtil.Guid));
313315
}
314316

315317
protected internal virtual void RegisterDefaultProperties()

src/NHibernate/Dialect/PostgreSQLDialect.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ public PostgreSQLDialect()
9898

9999
RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "?1::TEXT"));
100100

101+
// The uuid_generate_v4 is not native and must be installed, but SelectGUIDString property already uses it,
102+
// and NHibernate.TestDatabaseSetup does install it.
103+
RegisterFunction("new_uuid", new NoArgSQLFunction("uuid_generate_v4", NHibernateUtil.Guid));
104+
101105
RegisterKeywords();
102106
}
103107

src/NHibernate/Dialect/SQLiteDialect.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ protected virtual void RegisterColumnTypes()
5454
RegisterColumnType(DbType.DateTime, "DATETIME");
5555
RegisterColumnType(DbType.Time, "TIME");
5656
RegisterColumnType(DbType.Boolean, "BOOL");
57+
// UNIQUEIDENTIFIER is not a SQLite type, but SQLite does not care much, see
58+
// https://www.sqlite.org/datatype3.html
5759
RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER");
5860
}
5961

@@ -101,6 +103,11 @@ protected virtual void RegisterFunctions()
101103
RegisterFunction("transparentcast", new CastFunction());
102104

103105
RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "substr(hex(?1), 7, 2) || substr(hex(?1), 5, 2) || substr(hex(?1), 3, 2) || substr(hex(?1), 1, 2) || '-' || substr(hex(?1), 11, 2) || substr(hex(?1), 9, 2) || '-' || substr(hex(?1), 15, 2) || substr(hex(?1), 13, 2) || '-' || substr(hex(?1), 17, 4) || '-' || substr(hex(?1), 21) "));
106+
// This does not generate a valid uuid, but SelectGUIDString property already uses this.
107+
// See https://www.ietf.org/rfc/rfc4122.txt
108+
// System.Guid does not seem to care about the uuid validity, but this may still cause
109+
// other issues.
110+
RegisterFunction("new_uuid", new SQLFunctionTemplate(NHibernateUtil.Guid, "randomblob(16)"));
104111
}
105112

106113
#region private static readonly string[] DialectKeywords = { ... }

0 commit comments

Comments
 (0)