diff --git a/.gitignore b/.gitignore index 846284a0fd1..9a9926b3127 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,16 @@ current-test-configuration # This will be copied from the build directory to the lib directory in order # to satisfy later build steps. But it should not be committed. NHibernate.dll +src/packages/Antlr4.StringTemplate.4.0.6.9004/Antlr4.StringTemplate.4.0.6.9004.nupkg +src/packages/Iesi.Collections.4.0.1.4000/Iesi.Collections.4.0.1.4000.nupkg +src/packages/Iesi.Collections.4.0.1.4000/lib/net40/Iesi.Collections.xml +src/packages/Remotion.Linq.1.15.9.0/Remotion.Linq.1.15.9.0.nupkg +src/packages/Remotion.Linq.1.15.9.0/lib/net45/Remotion.Linq.xml +src/packages/log4net.2.0.3/lib/net10-full/log4net.xml +src/packages/log4net.2.0.3/lib/net11-full/log4net.xml +src/packages/log4net.2.0.3/lib/net20-full/log4net.xml +src/packages/log4net.2.0.3/lib/net35-client/log4net.xml +src/packages/log4net.2.0.3/lib/net35-full/log4net.xml +src/packages/log4net.2.0.3/lib/net40-client/log4net.xml +src/packages/log4net.2.0.3/lib/net40-full/log4net.xml +src/packages/log4net.2.0.3/log4net.2.0.3.nupkg diff --git a/Tools/nant/bin/NDoc.Documenter.NAnt.dll b/Tools/nant/bin/NDoc.Documenter.NAnt.dll deleted file mode 100644 index d9dcccb470c..00000000000 Binary files a/Tools/nant/bin/NDoc.Documenter.NAnt.dll and /dev/null differ diff --git a/src/NHibernate.Test/Linq/QueryLock.cs b/src/NHibernate.Test/Linq/QueryLock.cs new file mode 100644 index 00000000000..cb9308da0d2 --- /dev/null +++ b/src/NHibernate.Test/Linq/QueryLock.cs @@ -0,0 +1,46 @@ +using System.Linq; +using NHibernate.AdoNet; +using NHibernate.Cfg; +using NHibernate.Engine; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + public class QueryLock : LinqTestCase + { + + [Test] + public void CanSetLockLinqQueries() + { + var result = (from e in db.Customers + where e.CompanyName == "Corp" + select e).SetLockMode(LockMode.Upgrade).ToList(); + + } + + + [Test] + public void CanSetLockOnLinqPagingQuery() + { + var result = (from e in db.Customers + where e.CompanyName == "Corp" + select e).Skip(5).Take(5).SetLockMode(LockMode.Upgrade).ToList(); + } + + + [Test] + public void CanLockBeforeSkipOnLinqOrderedPageQuery() + { + var result = (from e in db.Customers + orderby e.CompanyName + select e) + .SetLockMode(LockMode.Upgrade).Skip(5).Take(5).ToList(); + + + } + + + } + +} diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 465ef870a14..27949e04d8a 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -518,6 +518,7 @@ + diff --git a/src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs b/src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs index e7b3acd7654..8fec9d2c3f3 100644 --- a/src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs +++ b/src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs @@ -38,6 +38,7 @@ public static class AggregatingGroupByRewriter typeof (AnyResultOperator), typeof (AllResultOperator), typeof (TimeoutResultOperator), + typeof (LockResultOperator), }; public static void ReWrite(QueryModel queryModel) diff --git a/src/NHibernate/Linq/LinqExtensionMethods.cs b/src/NHibernate/Linq/LinqExtensionMethods.cs index c8b9acb2c0b..fe546d764f7 100755 --- a/src/NHibernate/Linq/LinqExtensionMethods.cs +++ b/src/NHibernate/Linq/LinqExtensionMethods.cs @@ -22,7 +22,7 @@ public static IQueryable Query(this IStatelessSession session) public static IQueryable Cacheable(this IQueryable query) { - var method = ReflectionHelper.GetMethodDefinition(() => Cacheable(null)).MakeGenericMethod(typeof (T)); + var method = ReflectionHelper.GetMethodDefinition(() => Cacheable(null)).MakeGenericMethod(typeof(T)); var callExpression = Expression.Call(method, query.Expression); @@ -31,7 +31,7 @@ public static IQueryable Cacheable(this IQueryable query) public static IQueryable CacheMode(this IQueryable query, CacheMode cacheMode) { - var method = ReflectionHelper.GetMethodDefinition(() => CacheMode(null, NHibernate.CacheMode.Normal)).MakeGenericMethod(typeof (T)); + var method = ReflectionHelper.GetMethodDefinition(() => CacheMode(null, NHibernate.CacheMode.Normal)).MakeGenericMethod(typeof(T)); var callExpression = Expression.Call(method, query.Expression, Expression.Constant(cacheMode)); @@ -40,7 +40,7 @@ public static IQueryable CacheMode(this IQueryable query, CacheMode cac public static IQueryable CacheRegion(this IQueryable query, string region) { - var method = ReflectionHelper.GetMethodDefinition(() => CacheRegion(null, null)).MakeGenericMethod(typeof (T)); + var method = ReflectionHelper.GetMethodDefinition(() => CacheRegion(null, null)).MakeGenericMethod(typeof(T)); var callExpression = Expression.Call(method, query.Expression, Expression.Constant(region)); @@ -57,15 +57,24 @@ public static IQueryable Timeout(this IQueryable query, int timeout) return new NhQueryable(query.Provider, callExpression); } + public static IQueryable SetLockMode(this IQueryable query, LockMode lockMode) + { + var method = ReflectionHelper.GetMethodDefinition(() => SetLockMode(null, LockMode.Read)).MakeGenericMethod(typeof(T)); + + var callExpression = Expression.Call(method, query.Expression, Expression.Constant(lockMode)); + + return new NhQueryable(query.Provider, callExpression); + } + public static IEnumerable ToFuture(this IQueryable query) { var nhQueryable = query as QueryableBase; if (nhQueryable == null) throw new NotSupportedException("Query needs to be of type QueryableBase"); - var provider = (INhQueryProvider) nhQueryable.Provider; + var provider = (INhQueryProvider)nhQueryable.Provider; var future = provider.ExecuteFuture(nhQueryable.Expression); - return (IEnumerable) future; + return (IEnumerable)future; } public static IFutureValue ToFutureValue(this IQueryable query) @@ -74,14 +83,14 @@ public static IFutureValue ToFutureValue(this IQueryable query) if (nhQueryable == null) throw new NotSupportedException("Query needs to be of type QueryableBase"); - var provider = (INhQueryProvider) nhQueryable.Provider; + var provider = (INhQueryProvider)nhQueryable.Provider; var future = provider.ExecuteFuture(nhQueryable.Expression); if (future is IEnumerable) { - return new FutureValue(() => ((IEnumerable) future)); + return new FutureValue(() => ((IEnumerable)future)); } - return (IFutureValue) future; + return (IFutureValue)future; } public static IFutureValue ToFutureValue(this IQueryable query, Expression, TResult>> selector) @@ -90,13 +99,13 @@ public static IFutureValue ToFutureValue(this IQueryable if (nhQueryable == null) throw new NotSupportedException("Query needs to be of type QueryableBase"); - var provider = (INhQueryProvider) query.Provider; + var provider = (INhQueryProvider)query.Provider; var expression = ReplacingExpressionTreeVisitor.Replace(selector.Parameters.Single(), query.Expression, selector.Body); - return (IFutureValue) provider.ExecuteFuture(expression); + return (IFutureValue)provider.ExecuteFuture(expression); } } } diff --git a/src/NHibernate/Linq/NhRelinqQueryParser.cs b/src/NHibernate/Linq/NhRelinqQueryParser.cs index 4ef1f85ac29..35f44d9e38e 100644 --- a/src/NHibernate/Linq/NhRelinqQueryParser.cs +++ b/src/NHibernate/Linq/NhRelinqQueryParser.cs @@ -75,9 +75,15 @@ public NHibernateNodeTypeProvider() new[] { ReflectionHelper.GetMethodDefinition(() => LinqExtensionMethods.Timeout(null, 0)), - }, typeof (TimeoutExpressionNode) + }, typeof(TimeoutExpressionNode) ); + methodInfoRegistry.Register( + new[] + { + ReflectionHelper.GetMethodDefinition(() => LinqExtensionMethods.SetLockMode(null, LockMode.Read)), + }, typeof(LockExpressionNode) + ); var nodeTypeProvider = ExpressionTreeParser.CreateDefaultNodeTypeProvider(); nodeTypeProvider.InnerProviders.Add(methodInfoRegistry); defaultNodeTypeProvider = nodeTypeProvider; @@ -100,7 +106,8 @@ public System.Type GetNodeType(MethodInfo method) public class AsQueryableExpressionNode : MethodCallExpressionNodeBase { - public AsQueryableExpressionNode(MethodCallExpressionParseInfo parseInfo) : base(parseInfo) + public AsQueryableExpressionNode(MethodCallExpressionParseInfo parseInfo) + : base(parseInfo) { } @@ -120,7 +127,8 @@ public class CacheableExpressionNode : ResultOperatorExpressionNodeBase private readonly MethodCallExpressionParseInfo _parseInfo; private readonly ConstantExpression _data; - public CacheableExpressionNode(MethodCallExpressionParseInfo parseInfo, ConstantExpression data) : base(parseInfo, null, null) + public CacheableExpressionNode(MethodCallExpressionParseInfo parseInfo, ConstantExpression data) + : base(parseInfo, null, null) { _parseInfo = parseInfo; _data = data; @@ -192,6 +200,29 @@ protected override ResultOperatorBase CreateResultOperator(ClauseGenerationConte } } + internal class LockExpressionNode : ResultOperatorExpressionNodeBase + { + private readonly MethodCallExpressionParseInfo _parseInfo; + private readonly ConstantExpression _lockMode; + + public LockExpressionNode(MethodCallExpressionParseInfo parseInfo, ConstantExpression lockMode) + : base(parseInfo, null, null) + { + _parseInfo = parseInfo; + _lockMode = lockMode; + } + + public override Expression Resolve(ParameterExpression inputParameter, Expression expressionToBeResolved, ClauseGenerationContext clauseGenerationContext) + { + return Source.Resolve(inputParameter, expressionToBeResolved, clauseGenerationContext); + } + + protected override ResultOperatorBase CreateResultOperator(ClauseGenerationContext clauseGenerationContext) + { + return new LockResultOperator(_parseInfo, _lockMode); + } + } + internal class TimeoutResultOperator : ResultOperatorBase { public MethodCallExpressionParseInfo ParseInfo { get; private set; } @@ -222,4 +253,36 @@ public override void TransformExpressions(Func transform { } } + internal class LockResultOperator : ResultOperatorBase + { + public MethodCallExpressionParseInfo ParseInfo { get; private set; } + public ConstantExpression LockMode { get; private set; } + + public LockResultOperator(MethodCallExpressionParseInfo parseInfo, ConstantExpression lockMode) + { + ParseInfo = parseInfo; + LockMode = lockMode; + } + + public override IStreamedData ExecuteInMemory(IStreamedData input) + { + throw new NotImplementedException(); + } + + public override IStreamedDataInfo GetOutputDataInfo(IStreamedDataInfo inputInfo) + { + return inputInfo; + } + + public override ResultOperatorBase Clone(CloneContext cloneContext) + { + throw new NotImplementedException(); + } + + public override void TransformExpressions(Func transformation) + { + } + } + + } \ No newline at end of file diff --git a/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs b/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs index 00da7152879..914725100c2 100644 --- a/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs +++ b/src/NHibernate/Linq/ReWriters/QueryReferenceExpressionFlattener.cs @@ -16,6 +16,7 @@ public class QueryReferenceExpressionFlattener : ExpressionTreeVisitor { typeof(CacheableResultOperator), typeof (TimeoutResultOperator), + typeof (LockResultOperator), }; private QueryReferenceExpressionFlattener(QueryModel model) @@ -33,7 +34,7 @@ protected override Expression VisitSubQueryExpression(SubQueryExpression subQuer { var subQueryModel = subQuery.QueryModel; var hasBodyClauses = subQueryModel.BodyClauses.Count > 0; - if(hasBodyClauses) + if (hasBodyClauses) { return base.VisitSubQueryExpression(subQuery); } diff --git a/src/NHibernate/Linq/ReWriters/ResultOperatorRewriter.cs b/src/NHibernate/Linq/ReWriters/ResultOperatorRewriter.cs index 553f9ff27e1..30316ff4902 100644 --- a/src/NHibernate/Linq/ReWriters/ResultOperatorRewriter.cs +++ b/src/NHibernate/Linq/ReWriters/ResultOperatorRewriter.cs @@ -67,6 +67,7 @@ private class ResultOperatorExpressionRewriter : ExpressionTreeVisitor typeof(OfTypeResultOperator), typeof(CacheableResultOperator), typeof(TimeoutResultOperator), + typeof (LockResultOperator), typeof(CastResultOperator), // see ProcessCast class }; diff --git a/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs b/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs index 0257395aa63..8eccdd4f9ed 100644 --- a/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs +++ b/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs @@ -106,6 +106,7 @@ static QueryModelVisitor() ResultOperatorMap.Add(); ResultOperatorMap.Add(); ResultOperatorMap.Add(); + ResultOperatorMap.Add(); ResultOperatorMap.Add(); ResultOperatorMap.Add(); } diff --git a/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessLock.cs b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessLock.cs new file mode 100644 index 00000000000..deb079e351f --- /dev/null +++ b/src/NHibernate/Linq/Visitors/ResultOperatorProcessors/ProcessLock.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NHibernate.Linq.Visitors.ResultOperatorProcessors +{ + internal class ProcessLock : IResultOperatorProcessor + { + public void Process(LockResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree) + { + tree.AddAdditionalCriteria((q, p) => q.SetLockMode(queryModelVisitor.Model.MainFromClause.ItemName, (LockMode)resultOperator.LockMode.Value)); + } + } +} diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 953e58468d1..7e6b1c550b5 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -313,6 +313,7 @@ +