Skip to content
Browse files

Merge branch '3.3.x'

  • Loading branch information...
2 parents 7e32107 + 5979442 commit a70af4ed387fa8a5490f4a5826c2734511224153 @hazzik hazzik committed
Showing with 945 additions and 68 deletions.
  1. +7 −0 ReleaseProcedure.txt
  2. BIN Tools/NuGet.exe
  3. +1 −1 doc/reference/modules/performance.xml
  4. +1 −1 doc/reference/modules/quickstart.xml
  5. +57 −1 releasenotes.txt
  6. +146 −0 src/NHibernate.Test/DialectTest/LockHintAppenderFixture.cs
  7. +7 −0 src/NHibernate.Test/Linq/ProjectionsTests.cs
  8. +31 −0 src/NHibernate.Test/Linq/WhereTests.cs
  9. +2 −2 src/NHibernate.Test/MappingByCode/IntegrationTests/NH3105/Fixture.cs
  10. +20 −0 src/NHibernate.Test/MappingTest/ForeignKeyFixture.cs
  11. +10 −0 src/NHibernate.Test/NHSpecificTest/NH2297/CustomCompositeUserType.cs
  12. +11 −0 src/NHibernate.Test/NHSpecificTest/NH2297/Entity.cs
  13. +42 −0 src/NHibernate.Test/NHSpecificTest/NH2297/Fixture.cs
  14. +107 −0 src/NHibernate.Test/NHSpecificTest/NH2297/InvalidCustomCompositeUserTypeBase.cs
  15. +13 −0 src/NHibernate.Test/NHSpecificTest/NH2297/MappingsNames.hbm.xml
  16. +13 −0 src/NHibernate.Test/NHSpecificTest/NH2297/MappingsTypes.hbm.xml
  17. +26 −0 src/NHibernate.Test/NHSpecificTest/NH2408/Fixture.cs
  18. +20 −0 src/NHibernate.Test/NHSpecificTest/NH2408/Mappings.hbm.xml
  19. +17 −0 src/NHibernate.Test/NHSpecificTest/NH2408/Model.cs
  20. +13 −0 src/NHibernate.Test/NHSpecificTest/NH3324/ChildEntity.cs
  21. +17 −0 src/NHibernate.Test/NHSpecificTest/NH3324/Entity.cs
  22. +111 −0 src/NHibernate.Test/NHSpecificTest/NH3324/FixtureByCode.cs
  23. +53 −0 src/NHibernate.Test/NHSpecificTest/NH3408/Fixture.cs
  24. +19 −0 src/NHibernate.Test/NHSpecificTest/NH3408/Mappings.hbm.xml
  25. +15 −0 src/NHibernate.Test/NHSpecificTest/NH3408/Model.cs
  26. +16 −0 src/NHibernate.Test/NHibernate.Test.csproj
  27. +74 −40 src/NHibernate/Dialect/MsSql2000Dialect.cs
  28. +6 −4 src/NHibernate/Dialect/MySQL5Dialect.cs
  29. +18 −5 src/NHibernate/Dialect/MySQLDialect.cs
  30. +14 −0 src/NHibernate/Engine/Query/QueryPlanCache.cs
  31. +3 −3 src/NHibernate/Engine/QueryParameters.cs
  32. +2 −1 src/NHibernate/Impl/ExpressionQueryImpl.cs
  33. +6 −2 src/NHibernate/Impl/SessionFactoryObjectFactory.cs
  34. +16 −2 src/NHibernate/Linq/NestedSelects/NestedSelectDetector.cs
  35. +21 −2 src/NHibernate/Linq/NestedSelects/NestedSelectRewriter.cs
  36. +2 −2 src/NHibernate/Linq/NhLinqExpression.cs
  37. +2 −2 src/NHibernate/Mapping/ForeignKey.cs
  38. +6 −0 src/NHibernate/Type/CompositeCustomType.cs
View
7 ReleaseProcedure.txt
@@ -15,6 +15,13 @@ These are the tasks typically needed to create an official NHibernate release.
* Perform the release build including running all tests (GaRelease.bat or
ShowBuildMenu.bat).
+ NOTE: If you prefer to keep your source code in a path like e.g.:
+ C:\Users\Something\Long\Projects\nhibernate-core
+ you may want to issue a command like:
+ subst P: C:\Users\Something\Long\Projects
+ And then change to P:\nhibernate-core before building. This will avoid
+ displaying a long user-specific path in public symbol files.
+
* If no error or other issue requiring further changes occured, tag the
current git HEAD with a tag according to version number. Don't forget to
push the tag to github.
View
BIN Tools/NuGet.exe
Binary file not shown.
View
2 doc/reference/modules/performance.xml
@@ -276,7 +276,7 @@ int accessLevel = (int) permissions["accounts"]; // Error!]]></programlisting>
of persistent collections. However, a different mechanism is needed for lazy
behavior in single-ended associations. The target entity of the association must
be proxied. NHibernate implements lazy initializing proxies for persistent objects
- using runtime bytecode enhancement (via the excellent Castle.DynamicProxy library).
+ using runtime bytecode enhancement.
</para>
<para>
View
2 doc/reference/modules/quickstart.xml
@@ -165,7 +165,7 @@
No special interface has to be implemented for persistent classes nor do we have
to subclass from a special root persistent class. NHibernate also doesn't use any
build time processing, such as IL manipulation, it relies solely on
- .NET reflection and runtime class enhancement (through Castle.DynamicProxy library).
+ .NET reflection and runtime class enhancement.
So, without any dependency in the POCO class on NHibernate, we can map it to
a database table.
</para>
View
58 releasenotes.txt
@@ -1,7 +1,7 @@
Build vNext
=============================
-** Known BREAKING CHANGES from NH3.3.2.GA to vNext
+** Known BREAKING CHANGES from NH3.3.3.CR1 to vNext
NHibernate now targets .Net 4.0. Many uses of set types from Iesi.Collections have
now been changed to use corresponding types from the BCL. The API for these types
@@ -26,6 +26,62 @@ Build vNext
* Oracle: The atan2 and power functions now return double (instead of single) for consistency with other dialects.
* Removed FirebirdDriver. It was the same as FirebirdClientDriver since 3.2, and the latter have been the default since then.
+Build 3.3.3.CR1
+=============================
+
+** Fix
+ * [NH-3148] - ComponentAsId properties do not maintain the Column specified using property mapper when component is from base class
+
+** Sub-task
+ * [NH-3052] - Projection of one-to-many generates invalid SQL
+ * [NH-3385] - Add ability to expand many subcollections with WCF Data Services
+
+** Bug
+ * [NH-2042] - Table per subclass, using a discriminator mappings with formula in child class error
+ * [NH-2539] - Contains/StartsWith fails when invoked via WCF Data Service.
+ * [NH-2566] - NotSupportedException when using Skip/Take/First/Single/Any on GroupBy
+ * [NH-2588] - NotSupportedException when using Skip/Take with Where clause
+ * [NH-2860] - Lazy property throwing casting exception
+ * [NH-2979] - MsSqlCe dialect doesn't give the correct SQL type for Decimal with Scale defined
+ * [NH-3039] - IndexOutOfRangeException thrown when web server is processing multiple sessionfactory creation requests
+ * [NH-3057] - Collection subquery constraint on joined-subclass inherited properties causes invalid sql (base classes are not joined in).
+ * [NH-3105] - ComponentAsId does not find property that belongs to a parent class
+ * [NH-3108] - OrderBy with Select throws exception
+ * [NH-3129] - Linq Provider doesn't recognize CompareTo method
+ * [NH-3241] - Linq: Mixing Fetch/FetchMany with Any() throws: ArgumentException: Expression of type 'System.Collections.IList' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable`1[System.Object]'
+ * [NH-3261] - Linq Query throws when there is a conditional operator
+ * [NH-3305] - SybaseSQLAnywhere10Dialect defaults a numeric datatype to (19,255) precision, which is not compatible with the DB
+ * [NH-3318] - Composite-id does not allow superclass properties
+ * [NH-3320] - Exception in LINQ projection with OrderBy/Take - block using WCF Data Services projection's
+ * [NH-3326] - Exception in LINQ with pagination - block using WCF Data Services
+ * [NH-3330] - Exception in LINQ for nullable strings in Oracle - blocks using WCF Data Services
+ * [NH-3332] - The NH linq driver generates sql code that doesn't match the semantics of the original linq query
+ * [NH-3337] - Exception in LINQ for complex nullable conditionals - blocks using WCF Data Services
+ * [NH-3357] - System.NotSupportedException : Don't currently support idents of type DateTimeOffset
+ * [NH-3366] - LINQ query with various Compare() and CompareTo() fails (WCF Data Services)
+ * [NH-3369] - ToFuture/ToFutureValue should fall-back on dialects without MultiQuery support
+ * [NH-3378] - MySQLDialect incorrect handle DbType.Currency as MONEY
+ * [NH-3379] - Oracle8iDialect and FirebirdDialect incorrect handle DbType.Currency type
+
+** Improvement
+ * [NH-2297] - Configuration.BuildSessionFactory throws a NullReferenceException when loading an invalid ICompositeUserType
+ * [NH-3301] - Support SqlMethods.Like() in LINQ queries.
+ * [NH-3360] - Allow setting timeout on a LINQ query
+ * [NH-3367] - Support string.Equals()
+ * [NH-3368] - Add support for Equals method of sbyte, DateTimeOffset and unsigned numerics
+ * [NH-3371] - NHibernate should log LINQ expression trees to ease debugging
+
+** New Feature
+ * [NH-2986] - Add ability to include collections into projections
+ * [NH-3092] - Nhibernate Linq provider does not support Math functions like Math.Cos, Math.Sin, etc
+ * [NH-3180] - Could not select first element of the group
+ * [NH-3184] - Add ability to use ToFutureValue with aggregating queries
+ * [NH-3283] - New driver: Devart.Data.MySql
+ * [NH-3333] - Add ability to expand subcollections with WCF Data Services
+
+** Patch
+ * [NH-3255] - The IDbCommand that performs the cleanup of data in AbstractStatementExecutor.DropTemporaryTableIfNecessary does not have a connection.
+
Build 3.3.2.GA
=============================
View
146 src/NHibernate.Test/DialectTest/LockHintAppenderFixture.cs
@@ -0,0 +1,146 @@
+using System.Collections.Generic;
+using NHibernate.Dialect;
+using NHibernate.SqlCommand;
+using NUnit.Framework;
+
+namespace NHibernate.Test.DialectTest
+{
+ [TestFixture]
+ public class LockHintAppenderFixture
+ {
+ private const string MsSql2000LockHint = " with (updlock, rowlock)";
+ private MsSql2000Dialect.LockHintAppender _appender;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _appender = new MsSql2000Dialect.LockHintAppender(new MsSql2000Dialect(), new Dictionary<string, LockMode> { {"person", LockMode.Upgrade} });
+ }
+
+ [Test]
+ public void AppendHintToSingleTableAlias()
+ {
+ const string expectedQuery1 = "select * from Person person with (updlock, rowlock)";
+ const string expectedQuery2 = "select * from Person as person with (updlock, rowlock)";
+
+ var result1 = _appender.AppendLockHint(new SqlString(expectedQuery1.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result1.ToString(), Is.EqualTo(expectedQuery1));
+
+ var result2 = _appender.AppendLockHint(new SqlString(expectedQuery2.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result2.ToString(), Is.EqualTo(expectedQuery2));
+ }
+
+ [Test]
+ public void AppendHintToJoinedTableAlias()
+ {
+ const string expectedQuery =
+ "select * from Person person with (updlock, rowlock) inner join Country country on person.Id = country.Id";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void AppendHintToUnionTableAlias()
+ {
+ const string expectedQuery =
+ "select Id, Name from (select Id, CONCAT(FirstName, LastName) from Employee with (updlock, rowlock) union all select Id, CONCAT(FirstName, LastName) from Manager with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldIgnoreCasing()
+ {
+ const string expectedQuery =
+ "select Id, Name FROM (select Id, Name FROM Employee with (updlock, rowlock) union all select Id, Name from Manager with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldHandleExplicitSchemas()
+ {
+ const string expectedQuery =
+ "select Id, Name from (select Id, Name FROM dbo.Employee with (updlock, rowlock) union all select Id, Name from Manager with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldHandleExplicitSchemasAndDbNames()
+ {
+ const string expectedQuery =
+ "select Id, Name from (select Id, Name FROM nhibernate.dbo.Employee with (updlock, rowlock) union all select Id, Name from Manager with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldHandleExplicitDbNameWithoutSchemaName()
+ {
+ const string expectedQuery =
+ "select Id, Name from (select Id, Name FROM nhibernate..Employee with (updlock, rowlock) union all select Id, Name from Manager with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldHandleExplicitSchemasAndDbNamesWithSpacesBetweenNameParts()
+ {
+ const string expectedQuery =
+ "select Id, Name from (select Id, Name FROM nhibernate .dbo. Employee with (updlock, rowlock) union all select Id, Name from Manager with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldHandleEscapingInSubselect()
+ {
+ const string expectedQuery =
+ "select Id, Name from (select Id, Name from [Employee] with (updlock, rowlock) union all select Id, Name from [Manager] with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldHandleEscapingWithWhitespacesInSubselect()
+ {
+ const string expectedQuery =
+ "select Id, Name from (select Id, Name from [Empl oyee] with (updlock, rowlock) union all select Id, Name from [Man ager] with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldHandleEscapingWithSquareBracketsInSubselect()
+ {
+ const string expectedQuery =
+ "select Id, Name from (select Id, Name from [Empl ]]oyee] with (updlock, rowlock) union all select Id, Name from [Manager] with (updlock, rowlock)) as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+
+ [Test]
+ public void ShouldHandleMultilineQuery()
+ {
+ const string expectedQuery = @"
+select Id, Name from
+ (select Id, Name from Employee with (updlock, rowlock) union all
+ select Id, Name from Manager with (updlock, rowlock))
+as person";
+
+ var result = _appender.AppendLockHint(new SqlString(expectedQuery.Replace(MsSql2000LockHint, string.Empty)));
+ Assert.That(result.ToString(), Is.EqualTo(expectedQuery));
+ }
+ }
+}
View
7 src/NHibernate.Test/Linq/ProjectionsTests.cs
@@ -438,6 +438,10 @@ private string FormatName(string name, DateTime? lastLoginDate)
return string.Format("User {0} logged in at {1}", name, lastLoginDate);
}
+
+ /// <summary>
+ /// This mimic classes in System.Data.Services.Internal.
+ /// </summary>
class ExpandedWrapper<TExpandedElement>
{
public TExpandedElement ExpandedElement { get; set; }
@@ -445,6 +449,9 @@ class ExpandedWrapper<TExpandedElement>
public string ReferenceDescription { get; set; }
}
+ /// <summary>
+ /// This mimic classes in System.Data.Services.Internal.
+ /// </summary>
class ExpandedWrapper<TExpandedElement, TProperty0> : ExpandedWrapper<TExpandedElement>
{
public TProperty0 ProjectedProperty0 { get; set; }
View
31 src/NHibernate.Test/Linq/WhereTests.cs
@@ -1,7 +1,10 @@
using System;
+using System.Collections;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
+using NHibernate.Engine.Query;
using NHibernate.Linq;
using NHibernate.DomainModel.Northwind.Entities;
using NUnit.Framework;
@@ -440,6 +443,34 @@ where names.Contains(user.Name)
Assert.That(query.Count, Is.EqualTo(2));
}
+ [Test, Description("NH-3413")]
+ public void UsersWithListContains_MutatingListDoesNotBreakOtherSessions()
+ {
+ {
+ var names = new List<string> { "ayende", "rahien" };
+
+ var query = (from user in db.Users
+ where names.Contains(user.Name)
+ select user).ToList();
+
+ Assert.AreEqual(2, query.Count);
+
+ names.Clear();
+ }
+
+ {
+ var names = new List<string> { "ayende" };
+
+ var query = (from user in db.Users
+ where names.Contains(user.Name)
+ select user).ToList();
+
+ // This line fails with Expected: 1 But was: 0
+ // The SQL in NHProf shows that the where clause was executed as WHERE 1 = 0 as if names were empty
+ Assert.AreEqual(1, query.Count);
+ }
+ }
+
[Test]
public void UsersWithEmptyList_NH2400()
{
View
4 src/NHibernate.Test/MappingByCode/IntegrationTests/NH3105/Fixture.cs
@@ -9,7 +9,7 @@ namespace NHibernate.Test.MappingByCode.IntegrationTests.NH3105
public class Fixture
{
[Test]
- public void CanMapComponentAsIdWhenComnponentIsDeclaredInBaseClass()
+ public void CanMapComponentAsIdWhenComponentIsDeclaredInBaseClass()
{
var mapper = new ModelMapper();
mapper.Class<Entity>(rc =>
@@ -48,7 +48,7 @@ public void CanMapIdWhenIdIsDeclaredInBaseClass()
}
[Test]
- public void CanMapComponentAsIdWhenComnponentIsDeclaredInClass()
+ public void CanMapComponentAsIdWhenComponentIsDeclaredInClass()
{
var mapper = new ModelMapper();
mapper.Class<EntityBase>(rc =>
View
20 src/NHibernate.Test/MappingTest/ForeignKeyFixture.cs
@@ -39,5 +39,25 @@ public void UnmatchingColumns()
fk.ReferencedTable = primaryTable;
Assert.Throws<FKUnmatchingColumnsException>(() => fk.AlignColumns());
}
+
+ [Test]
+ public void ToStringDoesNotThrow()
+ {
+ var key = new ForeignKey
+ {
+ Table = new Table("TestTable"),
+ Name = "TestForeignKey"
+ };
+ key.AddColumn(new Column("TestColumn"));
+ key.AddReferencedColumns(new[] { new Column("ReferencedColumn") });
+
+ string toString = null;
+ Assert.DoesNotThrow(() =>
+ {
+ toString = key.ToString();
+ });
+
+ Assert.That(toString, Is.EqualTo("NHibernate.Mapping.ForeignKey(TestTableNHibernate.Mapping.Column(TestColumn) ref-columns:(NHibernate.Mapping.Column(ReferencedColumn)) as TestForeignKey"));
+ }
}
}
View
10 src/NHibernate.Test/NHSpecificTest/NH2297/CustomCompositeUserType.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace NHibernate.Test.NHSpecificTest.NH2297
+{
+ public class CustomCompositeUserType
+ {
+ public virtual String Value1 { get; set; }
+ public virtual String Value2 { get; set; }
+ }
+}
View
11 src/NHibernate.Test/NHSpecificTest/NH2297/Entity.cs
@@ -0,0 +1,11 @@
+using System.Collections;
+
+namespace NHibernate.Test.NHSpecificTest.NH2297
+{
+ public class EntityNH2297
+ {
+ public virtual int Id { get; set; }
+
+ public virtual CustomCompositeUserType CustomTypeValue { get; set; }
+ }
+}
View
42 src/NHibernate.Test/NHSpecificTest/NH2297/Fixture.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections;
+using System.Reflection;
+using NHibernate.Cfg;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.NH2297
+{
+ [TestFixture]
+ public class Fixture // Purposefully doesn't inherit from BugTestCase
+ {
+ [TestCase(".MappingsNames.hbm.xml",
+ ExpectedException = typeof (InvalidOperationException),
+ ExpectedMessage =
+ "ICompositeUserType NHibernate.Test.NHSpecificTest.NH2297.InvalidNamesCustomCompositeUserType returned a null value for 'PropertyNames'."
+ )]
+ [TestCase(".MappingsTypes.hbm.xml",
+ ExpectedException = typeof (InvalidOperationException),
+ ExpectedMessage =
+ "ICompositeUserType NHibernate.Test.NHSpecificTest.NH2297.InvalidTypesCustomCompositeUserType returned a null value for 'PropertyTypes'."
+ )]
+ public void InvalidCustomCompositeUserTypeThrowsMeaningfulException(string mappingFile)
+ {
+ var cfg = new Configuration();
+
+ if (TestConfigurationHelper.hibernateConfigFile != null)
+ cfg.Configure(TestConfigurationHelper.hibernateConfigFile);
+
+ const string MappingsAssembly = "NHibernate.Test";
+
+ Assembly assembly = Assembly.Load(MappingsAssembly);
+
+ string ns = GetType().Namespace;
+ string bugNumber = ns.Substring(ns.LastIndexOf('.') + 1);
+
+ cfg.AddResource(MappingsAssembly + "." + "NHSpecificTest." + bugNumber + mappingFile, assembly);
+
+ // build session factory creates the invalid custom type mapper, and throws the exception
+ cfg.BuildSessionFactory();
+ }
+ }
+}
View
107 src/NHibernate.Test/NHSpecificTest/NH2297/InvalidCustomCompositeUserTypeBase.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Data;
+using NHibernate.Engine;
+using NHibernate.Type;
+using NHibernate.UserTypes;
+
+namespace NHibernate.Test.NHSpecificTest.NH2297
+{
+ public class InvalidNamesCustomCompositeUserType : InvalidCustomCompositeUserTypeBase
+ {
+ public override string[] PropertyNames
+ {
+ // This is an invalid return value
+ get { return null; }
+ }
+ }
+
+
+ public class InvalidTypesCustomCompositeUserType : InvalidCustomCompositeUserTypeBase
+ {
+ public override Type.IType[] PropertyTypes
+ {
+ // This is an invalid return value
+ get { return null; }
+ }
+ }
+
+
+ /// <summary>
+ /// An invalid custom user type mapper.
+ /// </summary>
+ [Serializable]
+ public abstract class InvalidCustomCompositeUserTypeBase : ICompositeUserType
+ {
+ public System.Type ReturnedClass
+ {
+ get { return typeof (CustomCompositeUserType); }
+ }
+
+ public bool IsMutable
+ {
+ get { return true; }
+ }
+
+ public virtual String[] PropertyNames
+ {
+ get { return new[] {"Value1", "Value2"}; }
+ }
+
+ public virtual Type.IType[] PropertyTypes
+ {
+ get { return new IType[] {NHibernateUtil.String, NHibernateUtil.String}; }
+ }
+
+ public object Assemble(object cached, ISessionImplementor session, object owner)
+ {
+ return DeepCopy(cached);
+ }
+
+ public object Disassemble(Object value, ISessionImplementor session)
+ {
+ return DeepCopy(value);
+ }
+
+ public Object DeepCopy(Object a)
+ {
+ return a;
+ }
+
+ public new bool Equals(object x, object y)
+ {
+ return (x == y) || (x != null && y != null && (x.Equals(y)));
+ }
+
+ public object NullSafeGet(System.Data.IDataReader rs, String[] names, NHibernate.Engine.ISessionImplementor session,
+ Object owner)
+ {
+ return NHibernateUtil.String.NullSafeGet(rs, names[0], session, owner);
+ }
+
+ public void NullSafeSet(System.Data.IDbCommand st, Object value, int index,
+ bool[] settable, NHibernate.Engine.ISessionImplementor session)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Object GetPropertyValue(Object component, int property)
+ {
+ return null;
+ }
+
+ public void SetPropertyValue(Object object1, int i, Object object2)
+ {
+
+ }
+
+ public int GetHashCode(object x)
+ {
+ return x == null ? typeof (string).GetHashCode() : x.GetHashCode();
+ }
+
+ public object Replace(object original, object target, ISessionImplementor session, object owner)
+ {
+ return DeepCopy(original);
+ }
+ }
+}
View
13 src/NHibernate.Test/NHSpecificTest/NH2297/MappingsNames.hbm.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ namespace="NHibernate.Test.NHSpecificTest.NH2297"
+ assembly="NHibernate.Test">
+
+ <class name="EntityNH2297" schema="test">
+ <id name="Id">
+ <generator class="increment"/>
+ </id>
+ <property name="CustomTypeValue" type="NHibernate.Test.NHSpecificTest.NH2297.InvalidNamesCustomCompositeUserType, NHibernate.Test"/>
+ </class>
+
+</hibernate-mapping>
View
13 src/NHibernate.Test/NHSpecificTest/NH2297/MappingsTypes.hbm.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ namespace="NHibernate.Test.NHSpecificTest.NH2297"
+ assembly="NHibernate.Test">
+
+ <class name="EntityNH2297" schema="test">
+ <id name="Id">
+ <generator class="increment"/>
+ </id>
+ <property name="CustomTypeValue" type="NHibernate.Test.NHSpecificTest.NH2297.InvalidTypesCustomCompositeUserType, NHibernate.Test"/>
+ </class>
+
+</hibernate-mapping>
View
26 src/NHibernate.Test/NHSpecificTest/NH2408/Fixture.cs
@@ -0,0 +1,26 @@
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.NH2408
+{
+ public class Fixture : BugTestCase
+ {
+ protected override bool AppliesTo(Dialect.Dialect dialect)
+ {
+ return dialect is Dialect.MsSql2000Dialect;
+ }
+
+ [Test]
+ public void ShouldGenerateCorrectSqlStatement()
+ {
+ using (var session = OpenSession())
+ {
+ var query = session.CreateQuery("from Animal a where a.Name = ?");
+ query.SetParameter(0, "Prince");
+
+ query.SetLockMode("a", LockMode.Upgrade);
+
+ Assert.DoesNotThrow(() => query.List());
+ }
+ }
+ }
+}
View
20 src/NHibernate.Test/NHSpecificTest/NH2408/Mappings.hbm.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ namespace="NHibernate.Test.NHSpecificTest.NH2408"
+ assembly="NHibernate.Test"
+>
+ <class name="Animal">
+ <id name="Id">
+ <generator class="increment"/>
+ </id>
+ <property name="Name"/>
+
+ <union-subclass name="Dog" table="`Dog`">
+ </union-subclass>
+
+ <union-subclass name="Cat">
+ </union-subclass>
+
+ </class>
+
+</hibernate-mapping>
View
17 src/NHibernate.Test/NHSpecificTest/NH2408/Model.cs
@@ -0,0 +1,17 @@
+namespace NHibernate.Test.NHSpecificTest.NH2408
+{
+ public class Animal
+ {
+ public virtual int Id { get; set; }
+
+ public virtual string Name { get; set; }
+ }
+
+ public class Dog : Animal
+ {
+ }
+
+ public class Cat : Animal
+ {
+ }
+}
View
13 src/NHibernate.Test/NHSpecificTest/NH3324/ChildEntity.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace NHibernate.Test.NHSpecificTest.NH3324
+{
+ internal class ChildEntity
+ {
+ public virtual int? Id { get; set; }
+ public virtual string Name { get; set; }
+ }
+}
View
17 src/NHibernate.Test/NHSpecificTest/NH3324/Entity.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+
+namespace NHibernate.Test.NHSpecificTest.NH3324
+{
+ internal class Entity
+ {
+ public Entity()
+ {
+ Children = new List<ChildEntity>();
+ }
+
+ public virtual int? Id { get; set; }
+ public virtual string Name { get; set; }
+ public virtual IList<ChildEntity> Children { get; set; }
+ }
+}
View
111 src/NHibernate.Test/NHSpecificTest/NH3324/FixtureByCode.cs
@@ -0,0 +1,111 @@
+using NHibernate.Cfg.MappingSchema;
+using NHibernate.Mapping.ByCode;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.NH3324
+{
+ public class FixtureByCode : TestCaseMappingByCode
+ {
+ [Test]
+ public void LeftOuterJoin()
+ {
+ using (var session = OpenSession())
+ using (session.BeginTransaction())
+ {
+ const string hql = "FROM Entity e LEFT OUTER JOIN FETCH e.Children";
+
+ var query = session.CreateQuery(hql);
+ var result = query.List(); // does work
+ Assert.That(result, Has.Count.GreaterThan(0));
+ }
+ }
+
+ [Test]
+ public void LeftOuterJoinSetMaxResults()
+ {
+ using (var session = OpenSession())
+ using (session.BeginTransaction())
+ {
+ const string hql = "FROM Entity e LEFT OUTER JOIN FETCH e.Children";
+
+ var query = session.CreateQuery(hql);
+ query.SetMaxResults(5);
+ var result = query.List(); // does not work
+ Assert.That(result, Has.Count.GreaterThan(0));
+ }
+ }
+
+ protected override HbmMapping GetMappings()
+ {
+ var mapper = new ModelMapper();
+
+ mapper.Class<Entity>(rc =>
+ {
+ rc.Id(x => x.Id,
+ m =>
+ {
+ m.Generator(Generators.Identity);
+ m.Length(4);
+ });
+ rc.Property(x => x.Name);
+ rc.Bag(x => x.Children,
+ c =>
+ {
+ c.Key(k =>
+ {
+ k.Column("EntityId");
+ k.NotNullable(false);
+ k.ForeignKey("Id");
+ });
+ c.Cascade(Mapping.ByCode.Cascade.All);
+ c.Table("ChildEntity");
+ c.Inverse(true);
+ },
+ t => t.OneToMany());
+ });
+
+ mapper.Class<ChildEntity>(rc =>
+ {
+ rc.Id(x => x.Id,
+ m =>
+ {
+ m.Generator(Generators.Identity);
+ m.Length(4);
+ });
+ rc.Property(x => x.Name);
+ });
+
+ return mapper.CompileMappingForAllExplicitlyAddedEntities();
+ }
+
+ protected override void OnSetUp()
+ {
+ using (var session = OpenSession())
+ using (var transaction = session.BeginTransaction())
+ {
+ var e1 = new Entity { Name = "Bob" };
+ e1.Children.Add(new ChildEntity { Name = "Bob's Child" });
+ session.Save(e1);
+
+ var e2 = new Entity { Name = "Sally" };
+ e2.Children.Add(new ChildEntity { Name = "Sally's Child" });
+ session.Save(e2);
+
+ session.Flush();
+ transaction.Commit();
+ }
+ }
+
+ protected override void OnTearDown()
+ {
+ using (var session = OpenSession())
+ using (var transaction = session.BeginTransaction())
+ {
+ session.Delete("from System.Object");
+
+ session.Flush();
+ transaction.Commit();
+ }
+ }
+ }
+}
View
53 src/NHibernate.Test/NHSpecificTest/NH3408/Fixture.cs
@@ -0,0 +1,53 @@
+using System.Collections.Generic;
+using System.Linq;
+using NHibernate.Linq;
+using NUnit.Framework;
+
+namespace NHibernate.Test.NHSpecificTest.NH3408
+{
+ public class Fixture : BugTestCase
+ {
+ [Test]
+ public void ProjectAnonymousTypeWithArrayProperty()
+ {
+ using (var session = OpenSession())
+ using (session.BeginTransaction())
+ {
+ var query = from c in session.Query<Country>()
+ select new { c.Picture, c.NationalHolidays };
+
+ Assert.DoesNotThrow(() => { query.ToList(); });
+ }
+ }
+
+ [Test]
+ public void ProjectAnonymousTypeWithArrayPropertyWhenByteArrayContains()
+ {
+ using (var session = OpenSession())
+ using (session.BeginTransaction())
+ {
+ var pictures = new List<byte[]>();
+ var query = from c in session.Query<Country>()
+ where pictures.Contains(c.Picture)
+ select new { c.Picture, c.NationalHolidays };
+
+ Assert.DoesNotThrow(() => { query.ToList(); });
+ }
+ }
+
+ [Test]
+ public void SelectBytePropertyWithArrayPropertyWhenByteArrayContains()
+ {
+ using (var session = OpenSession())
+ using (session.BeginTransaction())
+ {
+ var pictures = new List<byte[]>();
+ var query = from c in session.Query<Country>()
+ where pictures.Contains(c.Picture)
+ select c.Picture;
+
+ Assert.DoesNotThrow(() => { query.ToList(); });
+ }
+ }
+ }
+}
View
19 src/NHibernate.Test/NHSpecificTest/NH3408/Mappings.hbm.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+ namespace="NHibernate.Test.NHSpecificTest.NH3408"
+ assembly="NHibernate.Test">
+ <class name="Country">
+ <id name="Id">
+ <generator class="increment"/>
+ </id>
+ <property name="Name"/>
+ <property name="Picture"/>
+ <set name="NationalHolidays" table="Holiday">
+ <key column="CalendarID" />
+ <element type="System.DateTime">
+ <column name="Holiday" />
+ </element>
+ </set>
+ </class>
+
+</hibernate-mapping>
View
15 src/NHibernate.Test/NHSpecificTest/NH3408/Model.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace NHibernate.Test.NHSpecificTest.NH3408
+{
+ public class Country
+ {
+ public virtual int Id { get; set; }
+
+ public virtual string Name { get; set; }
+
+ public virtual byte[] Picture { get; set; }
+
+ public virtual DateTime[] NationalHolidays { get; set; }
+ }
+}
View
16 src/NHibernate.Test/NHibernate.Test.csproj
@@ -214,6 +214,7 @@
<Compile Include="DialectTest\FunctionTests\SequenceSupportFixture.cs" />
<Compile Include="DialectTest\Ingres9DialectFixture.cs" />
<Compile Include="DialectTest\MsSql2012DialectFixture.cs" />
+ <Compile Include="DialectTest\LockHintAppenderFixture.cs" />
<Compile Include="DialectTest\MsSqlCe40DialectFixture.cs" />
<Compile Include="DialectTest\SchemaTests\ColumnMetaDataFixture.cs" />
<Compile Include="DriverTest\DbProviderFactoryDriveConnectionCommandProviderTest.cs" />
@@ -676,6 +677,17 @@
<Compile Include="NHSpecificTest\NH3058\SampleTest.cs" />
<Compile Include="NHSpecificTest\NH1818\DomainClass.cs" />
<Compile Include="NHSpecificTest\NH1818\Fixture1818.cs" />
+ <Compile Include="NHSpecificTest\NH3408\Fixture.cs" />
+ <Compile Include="NHSpecificTest\NH3408\Model.cs" />
+ <Compile Include="NHSpecificTest\NH2297\CustomCompositeUserType.cs" />
+ <Compile Include="NHSpecificTest\NH2297\Entity.cs" />
+ <Compile Include="NHSpecificTest\NH2297\Fixture.cs" />
+ <Compile Include="NHSpecificTest\NH2297\InvalidCustomCompositeUserTypeBase.cs" />
+ <Compile Include="NHSpecificTest\NH2408\Fixture.cs" />
+ <Compile Include="NHSpecificTest\NH2408\Model.cs" />
+ <Compile Include="NHSpecificTest\NH3324\ChildEntity.cs" />
+ <Compile Include="NHSpecificTest\NH3324\Entity.cs" />
+ <Compile Include="NHSpecificTest\NH3324\FixtureByCode.cs" />
<Compile Include="NHSpecificTest\NH3374\Document.cs" />
<Compile Include="NHSpecificTest\NH3374\FixtureByCode.cs" />
<Compile Include="NHSpecificTest\NH2042\Model.cs" />
@@ -2944,6 +2956,10 @@
<EmbeddedResource Include="NHSpecificTest\NH3058\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH2985\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH1818\Mappings.hbm.xml" />
+ <EmbeddedResource Include="NHSpecificTest\NH3408\Mappings.hbm.xml" />
+ <EmbeddedResource Include="NHSpecificTest\NH2408\Mappings.hbm.xml" />
+ <EmbeddedResource Include="NHSpecificTest\NH2297\MappingsNames.hbm.xml" />
+ <EmbeddedResource Include="NHSpecificTest\NH2297\MappingsTypes.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH2042\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH2860\Mappings.hbm.xml" />
<EmbeddedResource Include="NHSpecificTest\NH3332\Mappings.hbm.xml">
View
114 src/NHibernate/Dialect/MsSql2000Dialect.cs
@@ -410,25 +410,6 @@ public override string AppendLockHint(LockMode lockMode, string tableName)
return tableName;
}
- private struct LockHintAppender
- {
- private readonly MsSql2000Dialect dialect;
- private readonly IDictionary<string, LockMode> aliasedLockModes;
-
- public LockHintAppender(MsSql2000Dialect dialect, IDictionary<string, LockMode> aliasedLockModes)
- {
- this.dialect = dialect;
- this.aliasedLockModes = aliasedLockModes;
- }
-
- public string ReplaceMatch(Match match)
- {
- string alias = match.Groups[1].Value;
- string lockHint = dialect.AppendLockHint(aliasedLockModes[alias], alias);
- return string.Concat(" ", lockHint, match.Groups[2].Value);
- }
- }
-
public override SqlString ApplyLocksToSql(SqlString sql, IDictionary<string, LockMode> aliasedLockModes, IDictionary<string, string[]> keyColumnNames)
{
bool doWork = false;
@@ -447,27 +428,7 @@ public override SqlString ApplyLocksToSql(SqlString sql, IDictionary<string, Loc
return sql;
}
- // Regex matching any alias out of those given. Aliases should contain
- // no dangerous characters (they are identifiers) so they are not escaped.
- string aliasesPattern = StringHelper.Join("|", aliasedLockModes.Keys);
-
- // Match < alias >, < alias,>, or < alias$>, the intent is to capture alias names
- // in various kinds of "FROM table1 alias1, table2 alias2".
- Regex matchRegex = new Regex(" (" + aliasesPattern + ")([, ]|$)");
-
- SqlStringBuilder result = new SqlStringBuilder();
- MatchEvaluator evaluator = new LockHintAppender(this, aliasedLockModes).ReplaceMatch;
-
- foreach (object part in sql)
- {
- var parameter = part as Parameter;
- if (parameter != null)
- result.Add(parameter);
- else
- result.Add(matchRegex.Replace((string)part, evaluator));
- }
-
- return result.ToSqlString();
+ return new LockHintAppender(this, aliasedLockModes).AppendLockHint(sql);
}
public override long TimestampResolutionInTicks
@@ -539,5 +500,78 @@ public override bool IsKnownToken(string currentToken, string nextToken)
{
return currentToken == "n" && nextToken == "'"; // unicode character
}
+
+ public struct LockHintAppender
+ {
+ private const string UnescapedNameRegex = @"\w+";
+ private const string EscapedNameRegex = @"\[([^\]]|\]\])+\]";
+ private const string NameRegex = "(" + UnescapedNameRegex + "|" + EscapedNameRegex + ")";
+ private const string NameSeparatorRegex = @"\s*\.\s*";
+ private const string FromTableNameRegex = @"from\s+(" + NameRegex + "?" + NameSeparatorRegex + "){0,2}" + NameRegex;
+
+ private static readonly Regex FromClauseTableNameRegex = new Regex(FromTableNameRegex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
+
+ private readonly MsSql2000Dialect _dialect;
+ private readonly IDictionary<string, LockMode> _aliasedLockModes;
+
+ private readonly Regex _matchRegex;
+ private readonly Regex _unionSubclassRegex;
+
+ public LockHintAppender(MsSql2000Dialect dialect, IDictionary<string, LockMode> aliasedLockModes)
+ {
+ _dialect = dialect;
+ _aliasedLockModes = aliasedLockModes;
+
+ // Regex matching any alias out of those given. Aliases should contain
+ // no dangerous characters (they are identifiers) so they are not escaped.
+ var aliasesPattern = StringHelper.Join("|", aliasedLockModes.Keys);
+
+ // Match < alias >, < alias,>, or < alias$>, the intent is to capture alias names
+ // in various kinds of "FROM table1 alias1, table2 alias2".
+ _matchRegex = new Regex(" (" + aliasesPattern + ")([, ]|$)");
+ _unionSubclassRegex = new Regex(@"from\s+\(((?:.|\r|\n)*)\)(?:\s+as)?\s+(?<alias>" + aliasesPattern + ")", RegexOptions.IgnoreCase | RegexOptions.Multiline);
+ }
+
+ public SqlString AppendLockHint(SqlString sql)
+ {
+ var result = new SqlStringBuilder();
+
+ foreach (object part in sql)
+ {
+ if (part == Parameter.Placeholder)
+ {
+ result.Add((Parameter)part);
+ continue;
+}
+
+ result.Add(ProcessUnionSubclassCase((string)part) ?? _matchRegex.Replace((string)part, ReplaceMatch));
+ }
+
+ return result.ToSqlString();
+ }
+
+ private string ProcessUnionSubclassCase(string part)
+ {
+ var unionMatch = _unionSubclassRegex.Match(part);
+ if (!unionMatch.Success)
+ {
+ return null;
+ }
+
+ var alias = unionMatch.Groups["alias"].Value;
+ var lockMode = _aliasedLockModes[alias];
+ var @this = this;
+ var replacement = FromClauseTableNameRegex.Replace(unionMatch.Value, m => @this._dialect.AppendLockHint(lockMode, m.Value));
+
+ return _unionSubclassRegex.Replace(part, replacement);
+ }
+
+ private string ReplaceMatch(Match match)
+ {
+ string alias = match.Groups[1].Value;
+ string lockHint = _dialect.AppendLockHint(_aliasedLockModes[alias], alias);
+ return string.Concat(" ", lockHint, match.Groups[2].Value); // TODO: seems like this line is redundant
+ }
+ }
}
}
View
10 src/NHibernate/Dialect/MySQL5Dialect.cs
@@ -15,10 +15,12 @@ public MySQL5Dialect()
protected override void RegisterCastTypes() {
base.RegisterCastTypes();
// MySql 5 also supports DECIMAL as a cast type target
- // http://dev.mysql.com/doc/refman/5.5/en/cast-functions.html
- RegisterCastType(DbType.Decimal, "DECIMAL");
- RegisterCastType(DbType.Double, "DECIMAL");
- RegisterCastType(DbType.Single, "DECIMAL");
+ // http://dev.mysql.com/doc/refman/5.0/en/cast-functions.html
+ RegisterCastType(DbType.Decimal, "DECIMAL(19,5)");
+ RegisterCastType(DbType.Decimal, 19, "DECIMAL($p, $s)");
+ RegisterCastType(DbType.Double, "DECIMAL(19,5)");
+ RegisterCastType(DbType.Single, "DECIMAL(19,5)");
+ RegisterCastType(DbType.Guid, "BINARY(16)");
}
//Reference 5.x
View
23 src/NHibernate/Dialect/MySQLDialect.cs
@@ -3,7 +3,8 @@
using System.Data.Common;
using System.Text;
using NHibernate.Dialect.Function;
-using NHibernate.Dialect.Schema;
+using NHibernate.Dialect.Schema;
+using NHibernate.Mapping;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using NHibernate.Util;
@@ -272,7 +273,7 @@ protected virtual void RegisterCastTypes()
}
/// <summary>
- /// Suclasses register a typename for the given type code, to be used in CAST()
+ /// Subclasses register a typename for the given type code, to be used in CAST()
/// statements.
/// </summary>
/// <param name="code">The typecode</param>
@@ -280,7 +281,19 @@ protected virtual void RegisterCastTypes()
protected void RegisterCastType(DbType code, string name)
{
castTypeNames.Put(code, name);
- }
+ }
+
+ /// <summary>
+ /// Subclasses register a typename for the given type code, to be used in CAST()
+ /// statements.
+ /// </summary>
+ /// <param name="code">The typecode</param>
+ /// <param name="capacity"></param>
+ /// <param name="name">The database type name</param>
+ protected void RegisterCastType(DbType code, int capacity, string name)
+ {
+ castTypeNames.Put(code, capacity, name);
+ }
/// <summary>
/// Get the name of the database type appropriate for casting operations
@@ -289,8 +302,8 @@ protected void RegisterCastType(DbType code, string name)
/// <param name="sqlType">The <see cref="SqlType"/> typecode </param>
/// <returns> The database type name </returns>
public override string GetCastTypeName(SqlType sqlType)
- {
- string result = castTypeNames.Get(sqlType.DbType);
+ {
+ string result = castTypeNames.Get(sqlType.DbType, Column.DefaultLength, Column.DefaultPrecision, Column.DefaultScale);
if (result == null)
{
throw new HibernateException(string.Format("No CAST() type mapping for SqlType {0}", sqlType));
View
14 src/NHibernate/Engine/Query/QueryPlanCache.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using NHibernate.Engine.Query.Sql;
using NHibernate.Hql;
+using NHibernate.Linq;
using NHibernate.Util;
namespace NHibernate.Engine.Query
@@ -72,6 +73,19 @@ public IQueryExpressionPlan GetHQLQueryPlan(IQueryExpression queryExpression, bo
{
log.Debug("located HQL query plan in cache (" + queryExpression.Key + ")");
}
+ var planExpression = plan.QueryExpression as NhLinqExpression;
+ var expression = queryExpression as NhLinqExpression;
+ if (planExpression != null && expression != null)
+ {
+ //NH-3413
+ //Here we have to use original expression.
+ //In most cases NH do not translate expression in second time, but
+ // for cases when we have list parameters in query, like @p1.Contains(...),
+ // it does, and then it uses parameters from first try.
+ //TODO: cache only required parts of QueryExpression
+ planExpression._expression = expression._expression;
+ planExpression._constantToParameterMap = expression._constantToParameterMap;
+ }
}
return plan;
View
6 src/NHibernate/Engine/QueryParameters.cs
@@ -205,8 +205,8 @@ public QueryParameters CreateCopyUsing(RowSelection selection)
selection, IsReadOnlyInitialized, readOnly, Cacheable, CacheRegion, Comment, CollectionKeys,
OptionalObject, OptionalEntityName, OptionalId, ResultTransformer)
{
- ProcessedSql = ProcessedSql,
- ProcessedSqlParameters = ProcessedSqlParameters.ToList()
+ ProcessedSql = ProcessedSql,
+ ProcessedSqlParameters = ProcessedSqlParameters != null ? ProcessedSqlParameters.ToList() : null
};
return copy;
}
@@ -216,4 +216,4 @@ public bool IsReadOnly(ISessionImplementor session)
return IsReadOnlyInitialized ? ReadOnly : session.PersistenceContext.DefaultReadOnly;
}
}
-}
+}
View
3 src/NHibernate/Impl/ExpressionQueryImpl.cs
@@ -65,11 +65,12 @@ protected override IQueryExpression ExpandParameters(IDictionary<string, TypedVa
map.Add(name, aliases);
}
+ //TODO: Do we need to translate expression one more time here?
var newTree = ParameterExpander.Expand(QueryExpression.Translate(Session.Factory, false), map);
var key = new StringBuilder(QueryExpression.Key);
foreach (var pair in map)
- {
+ {
key.Append(' ');
key.Append(pair.Key);
key.Append(':');
View
8 src/NHibernate/Impl/SessionFactoryObjectFactory.cs
@@ -1,7 +1,7 @@
-using System.Collections;
-
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
namespace NHibernate.Impl
{
/// <summary>
@@ -39,6 +39,7 @@ static SessionFactoryObjectFactory()
/// <param name="name">The name of the ISessionFactory.</param>
/// <param name="instance">The ISessionFactory.</param>
/// <param name="properties">The configured properties for the ISessionFactory.</param>
+ [MethodImpl(MethodImplOptions.Synchronized)]
public static void AddInstance(string uid, string name, ISessionFactory instance, IDictionary<string, string> properties)
{
if (log.IsDebugEnabled)
@@ -66,6 +67,7 @@ public static void AddInstance(string uid, string name, ISessionFactory instance
/// <param name="uid">The identifier of the ISessionFactory.</param>
/// <param name="name">The name of the ISessionFactory.</param>
/// <param name="properties">The configured properties for the ISessionFactory.</param>
+ [MethodImpl(MethodImplOptions.Synchronized)]
public static void RemoveInstance(string uid, string name, IDictionary<string, string> properties)
{
if (!string.IsNullOrEmpty(name))
@@ -81,6 +83,7 @@ public static void RemoveInstance(string uid, string name, IDictionary<string, s
/// </summary>
/// <param name="name">The name of the ISessionFactory.</param>
/// <returns>An instantiated ISessionFactory.</returns>
+ [MethodImpl(MethodImplOptions.Synchronized)]
public static ISessionFactory GetNamedInstance(string name)
{
log.Debug("lookup: name=" + name);
@@ -98,6 +101,7 @@ public static ISessionFactory GetNamedInstance(string name)
/// </summary>
/// <param name="uid">The identifier of the ISessionFactory.</param>
/// <returns>An instantiated ISessionFactory.</returns>
+ [MethodImpl(MethodImplOptions.Synchronized)]
public static ISessionFactory GetInstance(string uid)
{
log.Debug("lookup: uid=" + uid);
View
18 src/NHibernate/Linq/NestedSelects/NestedSelectDetector.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
+using NHibernate.Linq.Visitors;
using NHibernate.Util;
using Remotion.Linq.Clauses.Expressions;
using Remotion.Linq.Parsing;
@@ -10,8 +11,14 @@ namespace NHibernate.Linq.NestedSelects
{
internal class NestedSelectDetector : ExpressionTreeVisitor
{
+ private readonly ISessionFactory sessionFactory;
private readonly ICollection<Expression> _expressions = new List<Expression>();
+ public NestedSelectDetector(ISessionFactory sessionFactory)
+ {
+ this.sessionFactory = sessionFactory;
+ }
+
public ICollection<Expression> Expressions
{
get { return _expressions; }
@@ -36,7 +43,7 @@ protected override Expression VisitMemberExpression(MemberExpression expression)
{
var memberType = expression.Member.GetPropertyOrFieldType();
- if (memberType != null && memberType.IsCollectionType())
+ if (memberType != null && memberType.IsCollectionType() && IsMappedCollection(expression.Member))
{
Expressions.Add(expression);
}
@@ -44,5 +51,12 @@ protected override Expression VisitMemberExpression(MemberExpression expression)
return base.VisitMemberExpression(expression);
}
+
+ private bool IsMappedCollection(MemberInfo memberInfo)
+ {
+ var collectionRole = memberInfo.DeclaringType.FullName + "." + memberInfo.Name;
+
+ return sessionFactory.GetCollectionMetadata(collectionRole) != null;
+ }
}
-}
+}
View
23 src/NHibernate/Linq/NestedSelects/NestedSelectRewriter.cs
@@ -7,6 +7,7 @@
using NHibernate.Linq.Clauses;
using NHibernate.Linq.GroupBy;
using NHibernate.Linq.Visitors;
+using NHibernate.Util;
using Remotion.Linq;
using Remotion.Linq.Clauses;
using Remotion.Linq.Clauses.Expressions;
@@ -19,7 +20,7 @@ static class NestedSelectRewriter
public static void ReWrite(QueryModel queryModel, ISessionFactory sessionFactory)
{
- var nsqmv = new NestedSelectDetector();
+ var nsqmv = new NestedSelectDetector(sessionFactory);
nsqmv.VisitExpression(queryModel.SelectClause.Selector);
if (!nsqmv.HasSubqueries)
return;
@@ -118,7 +119,7 @@ private static Expression ProcessSubquery(ISessionFactory sessionFactory, IColle
private static Expression ProcessMemberExpression(ISessionFactory sessionFactory, ICollection<ExpressionHolder> elementExpression, QueryModel queryModel, Expression @group, Expression memberExpression)
{
var join = new NhJoinClause(new NameGenerator(queryModel).GetNewName(),
- memberExpression.Type.GetGenericArguments()[0],
+ GetElementType(memberExpression.Type),
memberExpression);
queryModel.BodyClauses.Add(@join);
@@ -166,6 +167,16 @@ private static Expression SubCollectionQuery(System.Type collectionType, System.
Expression.Call(whereMethod, source, predicate),
selector);
+ if (collectionType.IsArray)
+ {
+ var toArrayMethod = EnumerableHelper.GetMethod("ToArray",
+ new[] { typeof(IEnumerable<>) },
+ new[] { elementType });
+
+ var array = Expression.Call(toArrayMethod, @select);
+ return array;
+ }
+
var constructor = GetCollectionConstructor(collectionType, elementType);
if (constructor != null)
return Expression.New(constructor, (Expression) @select);
@@ -240,5 +251,13 @@ private static Expression ConvertToObject(Expression expression)
{
return Expression.Convert(expression, typeof (object));
}
+
+ private static System.Type GetElementType(System.Type type)
+ {
+ var elementType = ReflectHelper.GetCollectionElementType(type);
+ if (elementType == null)
+ throw new NotSupportedException("Unknown collection type " + type.FullName);
+ return elementType;
+ }
}
}
View
4 src/NHibernate/Linq/NhLinqExpression.cs
@@ -25,8 +25,8 @@ public class NhLinqExpression : IQueryExpression
public ExpressionToHqlTranslationResults ExpressionToHqlTranslationResults { get; private set; }
- private readonly Expression _expression;
- private readonly IDictionary<ConstantExpression, NamedParameter> _constantToParameterMap;
+ internal Expression _expression;
+ internal IDictionary<ConstantExpression, NamedParameter> _constantToParameterMap;
public NhLinqExpression(Expression expression, ISessionFactoryImplementor sessionFactory)
{
View
4 src/NHibernate/Mapping/ForeignKey.cs
@@ -178,10 +178,10 @@ public override string ToString()
result.Append(GetType().FullName)
.Append('(')
.Append(Table.Name)
- .Append(ArrayHelper.ToStringArray((ICollection)Columns))
+ .Append(StringHelper.Join(", " , Columns))
.Append(" ref-columns:")
.Append('(')
- .Append(ArrayHelper.ToStringArray((ICollection)ReferencedColumns))
+ .Append(StringHelper.Join(", ", ReferencedColumns))
.Append(") as ")
.Append(Name);
return result.ToString();
View
6 src/NHibernate/Type/CompositeCustomType.cs
@@ -53,6 +53,12 @@ public CompositeCustomType(System.Type userTypeClass, IDictionary<string, string
{
LoggerProvider.LoggerFor(typeof(CustomType)).WarnFormat("the custom composite class '{0}' handled by '{1}' is not Serializable: ", userType.ReturnedClass, userTypeClass);
}
+
+ // This is to be nice to an application developer.
+ if (userType.PropertyTypes == null)
+ throw new InvalidOperationException(String.Format("ICompositeUserType {0} returned a null value for 'PropertyTypes'.", userType.GetType()));
+ if (userType.PropertyNames == null)
+ throw new InvalidOperationException(String.Format("ICompositeUserType {0} returned a null value for 'PropertyNames'.", userType.GetType()));
}
public virtual IType[] Subtypes

0 comments on commit a70af4e

Please sign in to comment.
Something went wrong with that request. Please try again.