Skip to content

Commit 9c73f04

Browse files
OnurGumushazzik
authored andcommitted
NH-2285: Support for LockMode in linq provider
1 parent fa978cf commit 9c73f04

File tree

9 files changed

+140
-3
lines changed

9 files changed

+140
-3
lines changed

src/NHibernate.Test/Linq/QueryLock.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System.Linq;
2+
using NHibernate.AdoNet;
3+
using NHibernate.Cfg;
4+
using NHibernate.Engine;
5+
using NHibernate.Linq;
6+
using NUnit.Framework;
7+
8+
namespace NHibernate.Test.Linq
9+
{
10+
public class QueryLock : LinqTestCase
11+
{
12+
13+
[Test]
14+
public void CanSetLockLinqQueries()
15+
{
16+
var result = (from e in db.Customers
17+
where e.CompanyName == "Corp"
18+
select e).SetLockMode(LockMode.Upgrade).ToList();
19+
20+
}
21+
22+
23+
[Test]
24+
public void CanSetLockOnLinqPagingQuery()
25+
{
26+
var result = (from e in db.Customers
27+
where e.CompanyName == "Corp"
28+
select e).Skip(5).Take(5).SetLockMode(LockMode.Upgrade).ToList();
29+
}
30+
31+
32+
[Test]
33+
public void CanLockBeforeSkipOnLinqOrderedPageQuery()
34+
{
35+
var result = (from e in db.Customers
36+
orderby e.CompanyName
37+
select e)
38+
.SetLockMode(LockMode.Upgrade).Skip(5).Take(5).ToList();
39+
40+
41+
}
42+
43+
44+
}
45+
46+
}
47+

src/NHibernate/Linq/LinqExtensionMethods.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2514,6 +2514,15 @@ public static IQueryable<T> CacheRegion<T>(this IQueryable<T> query, string regi
25142514
public static IQueryable<T> Timeout<T>(this IQueryable<T> query, int timeout)
25152515
=> query.WithOptions(o => o.SetTimeout(timeout));
25162516

2517+
public static IQueryable<T> SetLockMode<T>(this IQueryable<T> query, LockMode lockMode)
2518+
{
2519+
var method = ReflectHelper.GetMethod(() => SetLockMode(query, lockMode));
2520+
2521+
var callExpression = Expression.Call(method, query.Expression, Expression.Constant(lockMode));
2522+
2523+
return new NhQueryable<T>(query.Provider, callExpression);
2524+
}
2525+
25172526
/// <summary>
25182527
/// Allows to specify the parameter NHibernate type to use for a literal in a queryable expression.
25192528
/// </summary>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System.Linq.Expressions;
2+
using Remotion.Linq.Clauses;
3+
using Remotion.Linq.Parsing.Structure.IntermediateModel;
4+
5+
namespace NHibernate.Linq
6+
{
7+
internal class LockExpressionNode : ResultOperatorExpressionNodeBase
8+
{
9+
private readonly MethodCallExpressionParseInfo _parseInfo;
10+
private readonly ConstantExpression _lockMode;
11+
12+
public LockExpressionNode(MethodCallExpressionParseInfo parseInfo, ConstantExpression lockMode)
13+
: base(parseInfo, null, null)
14+
{
15+
_parseInfo = parseInfo;
16+
_lockMode = lockMode;
17+
}
18+
19+
public override Expression Resolve(ParameterExpression inputParameter, Expression expressionToBeResolved, ClauseGenerationContext clauseGenerationContext)
20+
{
21+
return Source.Resolve(inputParameter, expressionToBeResolved, clauseGenerationContext);
22+
}
23+
24+
protected override ResultOperatorBase CreateResultOperator(ClauseGenerationContext clauseGenerationContext)
25+
{
26+
return new LockResultOperator(_parseInfo, _lockMode);
27+
}
28+
}
29+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Linq.Expressions;
3+
using Remotion.Linq.Clauses;
4+
using Remotion.Linq.Clauses.StreamedData;
5+
using Remotion.Linq.Parsing.Structure.IntermediateModel;
6+
7+
namespace NHibernate.Linq
8+
{
9+
internal class LockResultOperator : ResultOperatorBase
10+
{
11+
public MethodCallExpressionParseInfo ParseInfo { get; }
12+
public ConstantExpression LockMode { get; }
13+
14+
public LockResultOperator(MethodCallExpressionParseInfo parseInfo, ConstantExpression lockMode)
15+
{
16+
ParseInfo = parseInfo;
17+
LockMode = lockMode;
18+
}
19+
20+
public override IStreamedData ExecuteInMemory(IStreamedData input)
21+
{
22+
throw new NotImplementedException();
23+
}
24+
25+
public override IStreamedDataInfo GetOutputDataInfo(IStreamedDataInfo inputInfo)
26+
{
27+
return inputInfo;
28+
}
29+
30+
public override ResultOperatorBase Clone(CloneContext cloneContext)
31+
{
32+
throw new NotImplementedException();
33+
}
34+
35+
public override void TransformExpressions(Func<Expression, Expression> transformation)
36+
{
37+
}
38+
}
39+
}

src/NHibernate/Linq/NhRelinqQueryParser.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
using System.Collections;
2-
using System.Linq;
32
using System.Linq.Expressions;
43
using System.Reflection;
54
using NHibernate.Linq.ExpressionTransformers;
65
using NHibernate.Linq.Visitors;
76
using NHibernate.Util;
87
using Remotion.Linq;
98
using Remotion.Linq.EagerFetching.Parsing;
10-
using Remotion.Linq.Parsing.ExpressionVisitors;
119
using Remotion.Linq.Parsing.ExpressionVisitors.Transformation;
1210
using Remotion.Linq.Parsing.Structure;
1311
using Remotion.Linq.Parsing.Structure.ExpressionTreeProcessors;
14-
using Remotion.Linq.Parsing.Structure.IntermediateModel;
1512
using Remotion.Linq.Parsing.Structure.NodeTypeProviders;
1613

1714
namespace NHibernate.Linq
@@ -83,6 +80,9 @@ public NHibernateNodeTypeProvider()
8380
methodInfoRegistry.Register(
8481
new[] { ReflectHelper.GetMethodDefinition(() => EagerFetchingExtensionMethods.ThenFetchMany<object, object, object>(null, null)) },
8582
typeof(ThenFetchManyExpressionNode));
83+
methodInfoRegistry.Register(
84+
new[] { ReflectHelper.GetMethodDefinition(() => LinqExtensionMethods.SetLockMode<object>(null, LockMode.Read)) },
85+
typeof(LockExpressionNode));
8686

8787
var nodeTypeProvider = ExpressionTreeParser.CreateDefaultNodeTypeProvider();
8888
nodeTypeProvider.InnerProviders.Add(methodInfoRegistry);

src/NHibernate/Linq/ReWriters/ResultOperatorRewriter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ private class ResultOperatorExpressionRewriter : RelinqExpressionVisitor
6868
typeof(OfTypeResultOperator),
6969
typeof(CastResultOperator),
7070
typeof(AsQueryableResultOperator),
71+
typeof(LockResultOperator),
7172
};
7273

7374
private readonly List<ResultOperatorBase> resultOperators = new List<ResultOperatorBase>();

src/NHibernate/Linq/Visitors/QueryModelVisitor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ static QueryModelVisitor()
141141
ResultOperatorMap.Add<OfTypeResultOperator, ProcessOfType>();
142142
ResultOperatorMap.Add<CastResultOperator, ProcessCast>();
143143
ResultOperatorMap.Add<AsQueryableResultOperator, ProcessAsQueryable>();
144+
ResultOperatorMap.Add<LockResultOperator, ProcessLock>();
144145
}
145146

146147
private QueryModelVisitor(VisitorParameters visitorParameters, bool root, QueryModel queryModel,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace NHibernate.Linq.Visitors.ResultOperatorProcessors
2+
{
3+
internal class ProcessLock : IResultOperatorProcessor<LockResultOperator>
4+
{
5+
public void Process(LockResultOperator resultOperator, QueryModelVisitor queryModelVisitor, IntermediateHqlTree tree)
6+
{
7+
tree.AddAdditionalCriteria((q, p) => q.SetLockMode(queryModelVisitor.Model.MainFromClause.ItemName, (LockMode)resultOperator.LockMode.Value));
8+
}
9+
}
10+
}

src/NHibernate/Linq/Visitors/SubQueryFromClauseFlattener.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public class SubQueryFromClauseFlattener : NhQueryModelVisitorBase
1212
{
1313
private static readonly System.Type[] FlattenableResultOperators =
1414
{
15+
typeof (LockResultOperator),
1516
typeof (FetchOneRequest),
1617
typeof (FetchManyRequest)
1718
};

0 commit comments

Comments
 (0)