diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs new file mode 100644 index 00000000000..a762cbef796 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.NH3426 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : TestCaseMappingByCode + { + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id); + rc.Property(x => x.Name); + }); + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + private const string id = "9FF2D288-56E6-F349-9CFC-48902132D65B"; + + protected override void OnSetUp() + { + using (var session = OpenSession()) + { + session.Save(new Entity { Id = Guid.Parse(id), Name = "Name 1" }); + + session.Flush(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + { + using (var transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + + session.Flush(); + transaction.Commit(); + } + } + } + + [Test] + public async Task SelectGuidToStringAsync() + { + using (var session = OpenSession()) + { + var list = await (session.Query() + .Select(x => new { Id = x.Id.ToString() }) + .ToListAsync()); + + Assert.AreEqual(id.ToUpper(), list[0].Id.ToUpper()); + } + } + + [Test] + public async Task WhereGuidToStringAsync() + { + using (var session = OpenSession()) + { + var list = await (session.Query() + .Where(x => x.Id.ToString().ToUpper() == id) + .ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH3426/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH3426/Entity.cs new file mode 100644 index 00000000000..7edf9b83318 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3426/Entity.cs @@ -0,0 +1,10 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.NH3426 +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs new file mode 100644 index 00000000000..06ac532dea1 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH3426 +{ + [TestFixture] + public class Fixture : TestCaseMappingByCode + { + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id); + rc.Property(x => x.Name); + }); + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + private const string id = "9FF2D288-56E6-F349-9CFC-48902132D65B"; + + protected override void OnSetUp() + { + using (var session = OpenSession()) + { + session.Save(new Entity { Id = Guid.Parse(id), Name = "Name 1" }); + + session.Flush(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + { + using (var transaction = session.BeginTransaction()) + { + session.Delete("from System.Object"); + + session.Flush(); + transaction.Commit(); + } + } + } + + [Test] + public void SelectGuidToString() + { + using (var session = OpenSession()) + { + var list = session.Query() + .Select(x => new { Id = x.Id.ToString() }) + .ToList(); + + Assert.AreEqual(id.ToUpper(), list[0].Id.ToUpper()); + } + } + + [Test] + public void WhereGuidToString() + { + using (var session = OpenSession()) + { + var list = session.Query() + .Where(x => x.Id.ToString().ToUpper() == id) + .ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + } + } + } +} diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 39642f1886f..f2ff3fce6d8 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -55,7 +55,7 @@ - + diff --git a/src/NHibernate/Dialect/Dialect.cs b/src/NHibernate/Dialect/Dialect.cs index f6f37c69280..0733a9dd518 100644 --- a/src/NHibernate/Dialect/Dialect.cs +++ b/src/NHibernate/Dialect/Dialect.cs @@ -123,6 +123,7 @@ protected Dialect() RegisterFunction("bnot", new Function.BitwiseNativeOperation("~", true)); RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as char)")); + RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "?1")); // register hibernate types for default use in scalar sqlquery type auto detection RegisterHibernateType(DbType.Int64, NHibernateUtil.Int64.Name); diff --git a/src/NHibernate/Dialect/FirebirdDialect.cs b/src/NHibernate/Dialect/FirebirdDialect.cs index f79e29eb23e..af32c3e09d5 100644 --- a/src/NHibernate/Dialect/FirebirdDialect.cs +++ b/src/NHibernate/Dialect/FirebirdDialect.cs @@ -419,6 +419,7 @@ private void OverrideStandardHQLFunctions() RegisterFunction("upper", new StandardSafeSQLFunction("upper", NHibernateUtil.String, 1)); RegisterFunction("mod", new StandardSafeSQLFunction("mod", NHibernateUtil.Double, 2)); RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as VARCHAR(255))")); + RegisterFunction("strguid", new StandardSQLFunction("uuid_to_char", NHibernateUtil.String)); RegisterFunction("sysdate", new CastedFunction("today", NHibernateUtil.Date)); RegisterFunction("date", new SQLFunctionTemplate(NHibernateUtil.Date, "cast(?1 as date)")); // Bitwise operations diff --git a/src/NHibernate/Dialect/MySQL55Dialect.cs b/src/NHibernate/Dialect/MySQL55Dialect.cs index fb5de2aa78b..9c47c111221 100644 --- a/src/NHibernate/Dialect/MySQL55Dialect.cs +++ b/src/NHibernate/Dialect/MySQL55Dialect.cs @@ -1,5 +1,6 @@ using System.Data; +using NHibernate.Dialect.Function; namespace NHibernate.Dialect { @@ -8,6 +9,7 @@ public class MySQL55Dialect : MySQL5Dialect public MySQL55Dialect() { RegisterColumnType(DbType.Guid, "CHAR(36)"); + RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "?1")); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Dialect/MySQL5Dialect.cs b/src/NHibernate/Dialect/MySQL5Dialect.cs index 38de3759df3..1dfac2f6f46 100644 --- a/src/NHibernate/Dialect/MySQL5Dialect.cs +++ b/src/NHibernate/Dialect/MySQL5Dialect.cs @@ -1,4 +1,5 @@ using System.Data; +using NHibernate.Dialect.Function; using NHibernate.SqlCommand; namespace NHibernate.Dialect @@ -11,9 +12,12 @@ public MySQL5Dialect() // My SQL supports precision up to 65, but .Net is limited to 28-29. RegisterColumnType(DbType.Decimal, 29, "DECIMAL($p, $s)"); RegisterColumnType(DbType.Guid, "BINARY(16)"); + + 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)))")); } - protected override void RegisterCastTypes() { + protected override void RegisterCastTypes() + { base.RegisterCastTypes(); // MySql 5 also supports DECIMAL as a cast type target // http://dev.mysql.com/doc/refman/5.0/en/cast-functions.html diff --git a/src/NHibernate/Dialect/Oracle8iDialect.cs b/src/NHibernate/Dialect/Oracle8iDialect.cs index c95ed7955bb..4d5d155e02c 100644 --- a/src/NHibernate/Dialect/Oracle8iDialect.cs +++ b/src/NHibernate/Dialect/Oracle8iDialect.cs @@ -302,6 +302,7 @@ protected virtual void RegisterFunctions() RegisterFunction("next_day", new StandardSQLFunction("next_day", NHibernateUtil.Date)); RegisterFunction("str", new StandardSQLFunction("to_char", NHibernateUtil.String)); + RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "substr(rawtohex(?1), 7, 2) || substr(rawtohex(?1), 5, 2) || substr(rawtohex(?1), 3, 2) || substr(rawtohex(?1), 1, 2) || '-' || substr(rawtohex(?1), 11, 2) || substr(rawtohex(?1), 9, 2) || '-' || substr(rawtohex(?1), 15, 2) || substr(rawtohex(?1), 13, 2) || '-' || substr(rawtohex(?1), 17, 4) || '-' || substr(rawtohex(?1), 21) ")); RegisterFunction("iif", new SQLFunctionTemplate(null, "case when ?1 then ?2 else ?3 end")); diff --git a/src/NHibernate/Dialect/PostgreSQLDialect.cs b/src/NHibernate/Dialect/PostgreSQLDialect.cs index a491862cab7..6eebc1a3679 100644 --- a/src/NHibernate/Dialect/PostgreSQLDialect.cs +++ b/src/NHibernate/Dialect/PostgreSQLDialect.cs @@ -94,6 +94,8 @@ public PostgreSQLDialect() // Register the date function, since when used in LINQ select clauses, NH must know the data type. RegisterFunction("date", new SQLFunctionTemplate(NHibernateUtil.Date, "cast(?1 as date)")); + + RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "?1::TEXT")); RegisterKeywords(); } diff --git a/src/NHibernate/Dialect/SQLiteDialect.cs b/src/NHibernate/Dialect/SQLiteDialect.cs index e9724cc0dee..dd72bdf5d8a 100644 --- a/src/NHibernate/Dialect/SQLiteDialect.cs +++ b/src/NHibernate/Dialect/SQLiteDialect.cs @@ -94,6 +94,8 @@ protected virtual void RegisterFunctions() // NH-3787: SQLite requires the cast in SQL too for not defaulting to string. RegisterFunction("transparentcast", new CastFunction()); + + 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) ")); } #region private static readonly string[] DialectKeywords = { ... } diff --git a/src/NHibernate/Dialect/SybaseASE15Dialect.cs b/src/NHibernate/Dialect/SybaseASE15Dialect.cs index bd83454f7f9..1b33b672cdf 100644 --- a/src/NHibernate/Dialect/SybaseASE15Dialect.cs +++ b/src/NHibernate/Dialect/SybaseASE15Dialect.cs @@ -104,6 +104,7 @@ public SybaseASE15Dialect() RegisterFunction("sqrt", new StandardSQLFunction("sqrt", NHibernateUtil.Double)); RegisterFunction("square", new StandardSQLFunction("square")); RegisterFunction("str", new StandardSQLFunction("str", NHibernateUtil.String)); + RegisterFunction("strguid", new StandardSQLFunction("str", NHibernateUtil.String)); RegisterFunction("tan", new StandardSQLFunction("tan", NHibernateUtil.Double)); RegisterFunction("trim", new AnsiTrimEmulationFunction("str_replace")); RegisterFunction("upper", new StandardSQLFunction("upper")); diff --git a/src/NHibernate/Linq/Functions/StringGenerator.cs b/src/NHibernate/Linq/Functions/StringGenerator.cs index 149d635c3fe..02cf535951f 100644 --- a/src/NHibernate/Linq/Functions/StringGenerator.cs +++ b/src/NHibernate/Linq/Functions/StringGenerator.cs @@ -317,6 +317,8 @@ public IHqlGeneratorForMethod GetMethodGenerator(MethodInfo method) public class ToStringHqlGeneratorForMethod : IHqlGeneratorForMethod { + private static readonly System.Type _guidType = typeof(Guid); + public IEnumerable SupportedMethods { get { throw new NotSupportedException(); } @@ -324,6 +326,11 @@ public IEnumerable SupportedMethods public HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) { + if (targetObject.Type == _guidType) + { + return treeBuilder.MethodCall("strguid", visitor.Visit(targetObject).AsExpression()); + } + return treeBuilder.MethodCall("str", visitor.Visit(targetObject).AsExpression()); } }