From: <ric...@us...> - 2010-02-16 22:50:26
|
Revision: 4944 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4944&view=rev Author: ricbrown Date: 2010-02-16 22:50:19 +0000 (Tue, 16 Feb 2010) Log Message: ----------- Fix NH-1981 (Multiple SQL parameters generated for same HQL parameter) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs trunk/nhibernate/src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs trunk/nhibernate/src/NHibernate/Loader/Loader.cs trunk/nhibernate/src/NHibernate/SqlCommand/Parameter.cs trunk/nhibernate/src/NHibernate.Test/Linq/RegresstionTests.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj trunk/nhibernate/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Model.cs Modified: trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/Dialect/MsSql2005Dialect.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -50,19 +50,6 @@ { return base.GetLimitString(querySqlString, offset, last); } - // we have to do this in order to support parameters in order clause, the foramt - // that sql 2005 uses for paging means that we move the parameters around, which means, - // that positions are lost, so we record them before making any changes. - // NH-1528 - int parameterPositon = 0; - foreach (var part in querySqlString.Parts) - { - Parameter param = part as Parameter; - if (param == null) - continue; - param.OriginalPositionInQuery = parameterPositon; - parameterPositon += 1; - } int fromIndex = GetFromIndex(querySqlString); SqlString select = querySqlString.Substring(0, fromIndex); Modified: trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/Driver/SqlStringFormatter.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -56,27 +56,8 @@ return; } - string name; + string name = formatter.GetParameterName(parameter.ParameterPosition ?? parameterIndex); - if (queryIndexToNumberOfPreceedingParameters.Count == 0) - { - // there's only one query... no need to worry about indexes of parameters of previous queries - name = formatter.GetParameterName(parameter.OriginalPositionInQuery ?? parameterIndex); - } - else - { - // multiple queries... in case the parameters were switched around (for SQL paging for instance) we need - // to keep the number of preceeding parameters (in previous queries of the batch) into account - if (parameter.OriginalPositionInQuery != null) - { - name = formatter.GetParameterName(GetNumberOfPreceedingParameters() + parameter.OriginalPositionInQuery.Value); - } - else - { - name = formatter.GetParameterName(parameterIndex); - } - } - parameterIndex++; result.Append(name); } Modified: trunk/nhibernate/src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/Engine/Query/NativeSQLQueryPlan.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -86,7 +86,7 @@ { queryParameters.ProcessFilters(customQuery.SQL, session); SqlString sql = queryParameters.FilteredSQL; - SqlType[] sqlTypes = GetParameterTypes(queryParameters, session); + SqlType[] sqlTypes = queryParameters.PrepareParameterTypes(sql, session.Factory, GetNamedParameterLocs, 0, false, false); IDbCommand ps = session.Batcher.PrepareCommand(CommandType.Text, sql, sqlTypes); @@ -102,7 +102,7 @@ // The responsibility of parameter binding was entirely moved to QueryParameters // to deal with positionslParameter+NamedParameter+ParameterOfFilters - queryParameters.BindParameters(ps, GetNamedParameterLocs, 0, session); + queryParameters.BindParameters(ps, 0, session); result = session.Batcher.ExecuteNonQuery(ps); } finally @@ -125,52 +125,5 @@ return result; } - - private SqlType[] GetParameterTypes(QueryParameters parameters, ISessionImplementor session) - { - List<IType> paramTypeList = new List<IType>(); - int span = 0; - - foreach (IType type in parameters.PositionalParameterTypes) - { - paramTypeList.Add(type); - span += type.GetColumnSpan(session.Factory); - } - - if (parameters.NamedParameters != null && parameters.NamedParameters.Count > 0) - { - int offset = paramTypeList.Count; - - // convert the named parameters to an array of types - foreach (KeyValuePair<string, TypedValue> e in parameters.NamedParameters) - { - string name = e.Key; - TypedValue typedval = e.Value; - int[] locs = GetNamedParameterLocs(name); - span += typedval.Type.GetColumnSpan(session.Factory) * locs.Length; - - for (int i = 0; i < locs.Length; i++) - { - ArrayHelper.SafeSetValue(paramTypeList, locs[i] + offset, typedval.Type); - } - } - } - return ConvertITypesToSqlTypes(paramTypeList, span, session); - } - - private static SqlType[] ConvertITypesToSqlTypes(IList<IType> nhTypes, int totalSpan, ISessionImplementor session) - { - SqlType[] result = new SqlType[totalSpan]; - - int index = 0; - foreach (IType type in nhTypes) - { - int span = type.SqlTypes(session.Factory).Length; - Array.Copy(type.SqlTypes(session.Factory), 0, result, index, span); - index += span; - } - - return result; - } } } Modified: trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/Engine/QueryParameters.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -6,6 +6,7 @@ using NHibernate.Hql.Classic; using NHibernate.Impl; using NHibernate.SqlCommand; +using NHibernate.SqlTypes; using NHibernate.Transform; using NHibernate.Type; using NHibernate.Util; @@ -392,31 +393,162 @@ processedSQL = result.ToSqlString(); } - public int BindParameters(IDbCommand command, GetNamedParameterLocations getNamedParameterLocations, int start, - ISessionImplementor session) + private IList<Parameter> ResetParameterLocations(SqlString sqlString) { + IList<Parameter> sqlParameters = new List<Parameter>(); + + foreach (object sqlParameter in sqlString.Parts) + { + if (sqlParameter is Parameter) + { + Parameter parameter = (Parameter)sqlParameter; + parameter.ParameterPosition = null; + sqlParameters.Add(parameter); + } + } + + return sqlParameters; + } + + private void SetParameterLocation(IList<Parameter> sqlParameters, int parameterIndex, int sqlLocation, int span) + { + int i = 0; + while (i < span) + { + sqlParameters[sqlLocation + i].ParameterPosition = parameterIndex + i; + i++; + } + } + + private SqlType[] ConvertITypesToSqlTypes(List<IType> nhTypes, ISessionFactoryImplementor factory, int totalSpan) + { + SqlType[] result = new SqlType[totalSpan]; + + int index = 0; + foreach (IType type in nhTypes) + { + int span = type.SqlTypes(factory).Length; + Array.Copy(type.SqlTypes(factory), 0, result, index, span); + index += span; + } + + return result; + } + + public SqlType[] PrepareParameterTypes(SqlString sqlString, ISessionFactoryImplementor factory, GetNamedParameterLocations getNamedParameterLocations, int startParameterIndex, bool addLimit, bool addOffset) + { + List<IType> paramTypeList = new List<IType>(); + int parameterIndex = 0; + int totalSpan = 0; + + IList<Parameter> sqlParameters = ResetParameterLocations(sqlString); + + for (int index = 0; index < PositionalParameterTypes.Length; index++) + { + IType type = PositionalParameterTypes[index]; + ArrayHelper.SafeSetValue(paramTypeList, parameterIndex, type); + + int location = PositionalParameterLocations[index]; + location = FindAdjustedParameterLocation(location); + int span = type.GetColumnSpan(factory); + SetParameterLocation(sqlParameters, startParameterIndex + parameterIndex, location, span); + + totalSpan += span; + parameterIndex++; + } + + for (int index = 0; index < FilteredParameterTypes.Count; index++) + { + IType type = FilteredParameterTypes[index]; + ArrayHelper.SafeSetValue(paramTypeList, parameterIndex, type); + + int location = FilteredParameterLocations[index]; + int span = type.GetColumnSpan(factory); + SetParameterLocation(sqlParameters, startParameterIndex + parameterIndex, location, span); + + totalSpan += span; + parameterIndex++; + } + + if (NamedParameters != null && NamedParameters.Count > 0) + { + // convert the named parameters to an array of types + foreach (KeyValuePair<string, TypedValue> namedParameter in NamedParameters) + { + TypedValue typedval = namedParameter.Value; + ArrayHelper.SafeSetValue(paramTypeList, parameterIndex, typedval.Type); + + int span = typedval.Type.GetColumnSpan(factory); + string name = namedParameter.Key; + int[] locs = getNamedParameterLocations(name); + for (int i = 0; i < locs.Length; i++) + { + int location = locs[i]; + location = FindAdjustedParameterLocation(location); + + // can still clash with positional parameters + // could consider throwing an exception to locate problem (NH-1098) + while ((location < sqlParameters.Count) && (sqlParameters[location].ParameterPosition != null)) + location++; + + SetParameterLocation(sqlParameters, startParameterIndex + parameterIndex, location, span); + } + + totalSpan += span; + parameterIndex++; + } + } + + if (addLimit && factory.Dialect.SupportsVariableLimit) + { + if (factory.Dialect.BindLimitParametersFirst) + { + paramTypeList.Insert(0, NHibernateUtil.Int32); + if (addOffset) + { + paramTypeList.Insert(0, NHibernateUtil.Int32); + } + } + else + { + paramTypeList.Add(NHibernateUtil.Int32); + if (addOffset) + { + paramTypeList.Add(NHibernateUtil.Int32); + } + } + + totalSpan += addOffset ? 2 : 1; + } + + return ConvertITypesToSqlTypes(paramTypeList, factory, totalSpan); + } + + public int BindParameters(IDbCommand command, int start, ISessionImplementor session) + { + int location = 0; var values = new List<object>(); var types = new List<IType>(); var sources = new List<string>(); for (int i = 0; i < _positionalParameterLocations.Length; i++) { - int location = FindAdjustedParameterLocation(_positionalParameterLocations[i]); object value = _positionalParameterValues[i]; IType type = _positionalParameterTypes[i]; ArrayHelper.SafeSetValue(values, location, value); ArrayHelper.SafeSetValue(types, location, type); ArrayHelper.SafeSetValue(sources, location, "Positional" + i); + location++; } for (int i = 0; i < filteredParameterLocations.Count; i++) { - int location = filteredParameterLocations[i]; object value = filteredParameterValues[i]; IType type = filteredParameterTypes[i]; ArrayHelper.SafeSetValue(values, location, value); ArrayHelper.SafeSetValue(types, location, type); ArrayHelper.SafeSetValue(sources, location, "Filter" + i); + location++; } if ((_namedParameters != null) && (_namedParameters.Count > 0)) @@ -425,22 +557,10 @@ { string name = namedParameter.Key; TypedValue typedval = namedParameter.Value; - int[] locations = getNamedParameterLocations(name); - for (int i = 0; i < locations.Length; i++) - { - int location = FindAdjustedParameterLocation(locations[i]); - - // can still clash with positional parameters - // could consider throwing an exception to locate problem (NH-1098) - while ((location < types.Count) && (types[location] != null)) - { - location++; - } - - ArrayHelper.SafeSetValue(values, location, typedval.Value); - ArrayHelper.SafeSetValue(types, location, typedval.Type); - ArrayHelper.SafeSetValue(sources, location, "name" + i); - } + ArrayHelper.SafeSetValue(values, location, typedval.Value); + ArrayHelper.SafeSetValue(types, location, typedval.Type); + ArrayHelper.SafeSetValue(sources, location, "name_" + name); + location++; } } Modified: trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/Impl/MultiCriteriaImpl.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -180,7 +180,7 @@ translators.Add(translator); QueryParameters queryParameters = translator.GetQueryParameters(); parameters.Add(queryParameters); - SqlCommandInfo commandInfo = loader.GetQueryStringAndTypes(session, queryParameters); + SqlCommandInfo commandInfo = loader.GetQueryStringAndTypes(session, queryParameters, types.Count); sqlString = sqlString.Append(commandInfo.Text) .Append(session.Factory.ConnectionProvider.Driver.MultipleQueriesSeparator) .Append(Environment.NewLine); @@ -339,7 +339,7 @@ for (int i = 0; i < loaders.Count; i++) { QueryParameters parameter = parameters[i]; - colIndex += parameter.BindParameters(command, loaders[i].GetNamedParameterLocs, colIndex, session); + colIndex += parameter.BindParameters(command, colIndex, session); } return colIndex; } Modified: trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/Impl/MultiQueryImpl.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -616,7 +616,7 @@ translators.Add(translator); parameters.Add(queryParameters); queryParameters = GetFilteredQueryParameters(queryParameters, translator); - SqlCommandInfo commandInfo = translator.Loader.GetQueryStringAndTypes(session, queryParameters); + SqlCommandInfo commandInfo = translator.Loader.GetQueryStringAndTypes(session, queryParameters, types.Count); sqlString = sqlString.Append(commandInfo.Text).Append(session.Factory.ConnectionProvider.Driver.MultipleQueriesSeparator).Append(Environment.NewLine); types.AddRange(commandInfo.ParameterTypes); } @@ -668,7 +668,7 @@ { IQueryTranslator translator = Translators[i]; QueryParameters parameter = Parameters[i]; - colIndex += parameter.BindParameters(command, translator.Loader.GetNamedParameterLocs, colIndex, session); + colIndex += parameter.BindParameters(command, colIndex, session); } return colIndex; } Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Remotion.Data.Linq.Parsing; @@ -23,12 +24,17 @@ protected override Expression VisitConstantExpression(ConstantExpression expression) { - if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) + if (!typeof(IQueryable).IsAssignableFrom(expression.Type) && !IsNullObject(expression)) { _parameters.Add(expression, new NamedParameter("p" + (_parameters.Count + 1), expression.Value, NHibernateUtil.GuessType(expression.Type))); } return base.VisitConstantExpression(expression); } + + private bool IsNullObject(ConstantExpression expression) + { + return expression.Type == typeof(Object) && expression.Value == null; + } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Loader/Loader.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/Loader/Loader.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -1106,6 +1106,8 @@ bool useOffset = hasFirstRow && useLimit && dialect.SupportsLimitOffset; // TODO NH bool callable = queryParameters.Callable; + SqlType[] parameterTypes = queryParameters.PrepareParameterTypes(sqlString, Factory, GetNamedParameterLocs, 0, useLimit, useOffset); + if (useLimit) { sqlString = @@ -1116,8 +1118,7 @@ // TODO NH: Callable for SP -> PrepareCallableQueryCommand IDbCommand command = - session.Batcher.PrepareQueryCommand(CommandType.Text, sqlString, - GetParameterTypes(queryParameters, useLimit, useOffset)); + session.Batcher.PrepareQueryCommand(CommandType.Text, sqlString, parameterTypes); try { @@ -1263,7 +1264,7 @@ // NH Different behavior: // The responsibility of parameter binding was entirely moved to QueryParameters // to deal with positionslParameter+NamedParameter+ParameterOfFilters - return queryParameters.BindParameters(statement, GetNamedParameterLocs, 0, session); + return queryParameters.BindParameters(statement, 0, session); } public virtual int[] GetNamedParameterLocs(string name) @@ -1683,7 +1684,7 @@ #region NHibernate specific - public virtual SqlCommandInfo GetQueryStringAndTypes(ISessionImplementor session, QueryParameters parameters) + public virtual SqlCommandInfo GetQueryStringAndTypes(ISessionImplementor session, QueryParameters parameters, int startParameterIndex) { SqlString sqlString = ProcessFilters(parameters, session); Dialect.Dialect dialect = session.Factory.Dialect; @@ -1693,6 +1694,8 @@ bool hasFirstRow = GetFirstRow(selection) > 0; bool useOffset = hasFirstRow && useLimit && dialect.SupportsLimitOffset; + SqlType[] sqlTypes = parameters.PrepareParameterTypes(sqlString, Factory, GetNamedParameterLocs, startParameterIndex, useLimit, useOffset); + if (useLimit) { sqlString = @@ -1700,97 +1703,9 @@ } sqlString = PreprocessSQL(sqlString, parameters, dialect); - return new SqlCommandInfo(sqlString, GetParameterTypes(parameters, useLimit, useOffset)); + return new SqlCommandInfo(sqlString, sqlTypes); } - protected SqlType[] ConvertITypesToSqlTypes(List<IType> nhTypes, int totalSpan) - { - SqlType[] result = new SqlType[totalSpan]; - - int index = 0; - foreach (IType type in nhTypes) - { - int span = type.SqlTypes(Factory).Length; - Array.Copy(type.SqlTypes(Factory), 0, result, index, span); - index += span; - } - - return result; - } - - /// <returns><see cref="IList" /> of <see cref="IType" /></returns> - protected SqlType[] GetParameterTypes(QueryParameters parameters, bool addLimit, bool addOffset) - { - List<IType> paramTypeList = new List<IType>(); - int span = 0; - - for (int index = 0; index < parameters.PositionalParameterTypes.Length; index++) - { - int location = parameters.PositionalParameterLocations[index]; - location = parameters.FindAdjustedParameterLocation(location); - IType type = parameters.PositionalParameterTypes[index]; - ArrayHelper.SafeSetValue(paramTypeList, location, type); - span += type.GetColumnSpan(Factory); - } - - for (int index = 0; index < parameters.FilteredParameterTypes.Count; index++) - { - int location = parameters.FilteredParameterLocations[index]; - IType type = parameters.FilteredParameterTypes[index]; - ArrayHelper.SafeSetValue(paramTypeList, location, type); - span += type.GetColumnSpan(Factory); - } - - if (parameters.NamedParameters != null && parameters.NamedParameters.Count > 0) - { - // convert the named parameters to an array of types - foreach (KeyValuePair<string, TypedValue> namedParameter in parameters.NamedParameters) - { - string name = namedParameter.Key; - TypedValue typedval = namedParameter.Value; - int[] locs = GetNamedParameterLocs(name); - span += typedval.Type.GetColumnSpan(Factory) * locs.Length; - - for (int i = 0; i < locs.Length; i++) - { - int location = locs[i]; - location = parameters.FindAdjustedParameterLocation(location); - - // can still clash with positional parameters - // could consider throwing an exception to locate problem (NH-1098) - while ((location < paramTypeList.Count) && (paramTypeList[location] != null)) - location++; - - ArrayHelper.SafeSetValue(paramTypeList, location, typedval.Type); - } - } - } - - if (addLimit && Factory.Dialect.SupportsVariableLimit) - { - if (Factory.Dialect.BindLimitParametersFirst) - { - paramTypeList.Insert(0, NHibernateUtil.Int32); - if (addOffset) - { - paramTypeList.Insert(0, NHibernateUtil.Int32); - } - } - else - { - paramTypeList.Add(NHibernateUtil.Int32); - if (addOffset) - { - paramTypeList.Add(NHibernateUtil.Int32); - } - } - - span += addOffset ? 2 : 1; - } - - return ConvertITypesToSqlTypes(paramTypeList, span); - } - #endregion } } Modified: trunk/nhibernate/src/NHibernate/SqlCommand/Parameter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/SqlCommand/Parameter.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate/SqlCommand/Parameter.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -10,16 +10,13 @@ [Serializable] public class Parameter { - /// <summary> + /// <summary> /// We need to know what the position of the parameter was in a query /// before we rearranged the query. - /// This is used only by dialects that rearrange the query, unfortunately, - /// the MS SQL 2005 dialect have to re shuffle the query (and ruin positional parameter - /// support) because the SQL 2005 and 2008 SQL dialects have a completely broken - /// support for paging, which is just a tad less important than SELECT. - /// See NH-1528 - /// </summary> - public int? OriginalPositionInQuery; + /// This is the ADO parameter position that this SqlString parameter is + /// bound to. The SqlString can be safely rearranged once this is set. + /// </summary> + public int? ParameterPosition; /// <summary> /// Used as a placeholder when parsing HQL or SQL queries. Modified: trunk/nhibernate/src/NHibernate.Test/Linq/RegresstionTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/RegresstionTests.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate.Test/Linq/RegresstionTests.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -1,5 +1,6 @@ using System.Linq; using NUnit.Framework; +using NHibernate.Test.Linq.Entities; namespace NHibernate.Test.Linq { @@ -10,7 +11,7 @@ /// http://aspzone.com/tech/nhibernate-linq-troubles/ /// </summary> [Test] - public void HierarchicalQueries() + public void HierarchicalQueries_InlineConstant() { var children = from s in db.Role where s.ParentRole != null @@ -24,5 +25,32 @@ Assert.AreEqual(2, roots.Count()); } + + [Test] + public void HierarchicalQueries_Variable() + { + Role testRole = null; + var children = from s in db.Role + where s.ParentRole != testRole + select s; + + Assert.AreEqual(0, children.Count()); + + var roots = from s in db.Role + where s.ParentRole == testRole + select s; + + Assert.AreEqual(2, roots.Count()); + } + [Test] + public void CanUseNullConstantAndRestriction() + { + var roots = from s in db.Role + where s.ParentRole == null + && s.Name == "Admin" + select s; + + Assert.AreEqual(1, roots.Count()); + } } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Fixture.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using NHibernate.Cfg; +using NHibernate.Tool.hbm2ddl; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1981 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [Test] + public void CanGroupWithParameter() + { + using (ISession s = OpenSession()) + using (ITransaction tx = s.BeginTransaction()) + { + s.Save(new Article() { Longitude = 90 }); + s.Save(new Article() { Longitude = 90 }); + s.Save(new Article() { Longitude = 120 }); + + IList<double> quotients = + s.CreateQuery( + @"select (Longitude / :divisor) + from Article + group by (Longitude / :divisor)") + .SetDouble("divisor", 30) + .List<double>(); + + Assert.That(quotients.Count, Is.EqualTo(2)); + Assert.That(quotients[0], Is.EqualTo(3)); + Assert.That(quotients[1], Is.EqualTo(4)); + } + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Mappings.hbm.xml 2010-02-16 22:50:19 UTC (rev 4944) @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + namespace="NHibernate.Test.NHSpecificTest.NH1981" + assembly="NHibernate.Test"> + + <class name="Article"> + <id name="Id"> + <generator class="hilo" /> + </id> + <property name="Longitude" /> + </class> +</hibernate-mapping> + + Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Model.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1981/Model.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.NH1981 +{ + public class Article + { + public virtual int Id { get; set; } + public virtual double Longitude { get; set; } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-02-16 22:50:19 UTC (rev 4944) @@ -663,6 +663,8 @@ <Compile Include="NHSpecificTest\NH1978\AliasTest.cs" /> <Compile Include="NHSpecificTest\NH1978\Employee.cs" /> <Compile Include="NHSpecificTest\NH1978\_401k.cs" /> + <Compile Include="NHSpecificTest\NH1981\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH1981\Model.cs" /> <Compile Include="NHSpecificTest\NH1989\Fixture.cs" /> <Compile Include="NHSpecificTest\NH1989\Model.cs" /> <Compile Include="NHSpecificTest\NH2009\Fixture.cs" /> @@ -2121,6 +2123,7 @@ <EmbeddedResource Include="CfgTest\Loquacious\EntityToCache.hbm.xml" /> <EmbeddedResource Include="DriverTest\SqlServerCeEntity.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="NHSpecificTest\NH1981\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2074\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2077\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2020\Mappings.hbm.xml" /> Modified: trunk/nhibernate/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs 2010-02-07 12:15:51 UTC (rev 4943) +++ trunk/nhibernate/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs 2010-02-16 22:50:19 UTC (rev 4944) @@ -375,8 +375,8 @@ Assert.AreEqual(parameterString1, parameterString2); Assert.AreNotSame(parameterString1, parameterString2); - parameters1[0].OriginalPositionInQuery = 231; - Assert.IsNull(parameters2[0].OriginalPositionInQuery); + parameters1[0].ParameterPosition = 231; + Assert.IsNull(parameters2[0].ParameterPosition); } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |