Skip to content

Commit 3d92bf4

Browse files
authored
Call generic query.List from Linq queries (#2238)
1 parent d99a382 commit 3d92bf4

File tree

5 files changed

+51
-3
lines changed

5 files changed

+51
-3
lines changed

src/NHibernate.Test/Linq/ByMethod/WithOptionsTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public void AppliesOptionsToQuery()
2323
var query = Substitute.For<IQuery>();
2424

2525
query.List().Returns(new List<Order>());
26+
query.List<Order>().Returns(new List<Order>());
2627

2728
session.CreateQuery(Arg.Any<IQueryExpression>()).Returns(query);
2829

@@ -56,6 +57,7 @@ public void DoNotContaminateQueryWithOptions()
5657
var query = Substitute.For<IQuery>();
5758

5859
query.List().Returns(new List<Order>());
60+
query.List<Order>().Returns(new List<Order>());
5961

6062
session.CreateQuery(Arg.Any<IQueryExpression>()).Returns(query);
6163

src/NHibernate/Async/Linq/DefaultQueryProvider.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ public partial interface INhQueryProvider : IQueryProvider
3232
public partial class DefaultQueryProvider : INhQueryProvider, IQueryProviderWithOptions, ISupportFutureBatchNhQueryProvider
3333
{
3434

35+
//TODO 6.0: Add to INhQueryProvider interface
36+
public virtual async Task<IList<TResult>> ExecuteListAsync<TResult>(Expression expression, CancellationToken cancellationToken)
37+
{
38+
cancellationToken.ThrowIfCancellationRequested();
39+
var linqExpression = PrepareQuery(expression, out var query);
40+
var resultTransformer = linqExpression.ExpressionToHqlTranslationResults?.PostExecuteTransformer;
41+
if (resultTransformer == null)
42+
{
43+
return await (query.ListAsync<TResult>(cancellationToken)).ConfigureAwait(false);
44+
}
45+
46+
return new List<TResult>
47+
{
48+
(TResult) resultTransformer.DynamicInvoke((await (query.ListAsync(cancellationToken)).ConfigureAwait(false)).AsQueryable())
49+
};
50+
}
51+
3552
// Since v5.1
3653
[Obsolete("Use ExecuteQuery(NhLinqExpression nhLinqExpression, IQuery query) instead")]
3754
protected virtual async Task<object> ExecuteQueryAsync(NhLinqExpression nhLinqExpression, IQuery query, NhLinqExpression nhQuery, CancellationToken cancellationToken)

src/NHibernate/Linq/DefaultQueryProvider.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,22 @@ public TResult Execute<TResult>(Expression expression)
100100
return (TResult)Execute(expression);
101101
}
102102

103+
//TODO 6.0: Add to INhQueryProvider interface
104+
public virtual IList<TResult> ExecuteList<TResult>(Expression expression)
105+
{
106+
var linqExpression = PrepareQuery(expression, out var query);
107+
var resultTransformer = linqExpression.ExpressionToHqlTranslationResults?.PostExecuteTransformer;
108+
if (resultTransformer == null)
109+
{
110+
return query.List<TResult>();
111+
}
112+
113+
return new List<TResult>
114+
{
115+
(TResult) resultTransformer.DynamicInvoke(query.List().AsQueryable())
116+
};
117+
}
118+
103119
public IQueryProvider WithOptions(Action<NhQueryableOptions> setOptions)
104120
{
105121
if (setOptions == null) throw new ArgumentNullException(nameof(setOptions));

src/NHibernate/Linq/LinqExtensionMethods.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,8 +2389,11 @@ public static class LinqExtensionMethods
23892389

23902390
async Task<List<TSource>> InternalToListAsync()
23912391
{
2392-
var result = await provider.ExecuteAsync<IEnumerable<TSource>>(source.Expression, cancellationToken).ConfigureAwait(false);
2393-
return result.ToList();
2392+
//TODO 6.0: Replace with provider.ExecuteListAsync
2393+
var result = provider is DefaultQueryProvider nhQueryProvider
2394+
? await nhQueryProvider.ExecuteListAsync<TSource>(source.Expression, cancellationToken).ConfigureAwait(false)
2395+
: await provider.ExecuteAsync<IEnumerable<TSource>>(source.Expression, cancellationToken).ConfigureAwait(false);
2396+
return (result as List<TSource>) ?? result.ToList();
23942397
}
23952398
}
23962399

src/NHibernate/Linq/NhQueryable.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Linq.Expressions;
45
using NHibernate.Engine;
@@ -17,7 +18,7 @@ interface IEntityNameProvider
1718
/// <summary>
1819
/// Provides the main entry point to a LINQ query.
1920
/// </summary>
20-
public class NhQueryable<T> : QueryableBase<T>, IEntityNameProvider
21+
public class NhQueryable<T> : QueryableBase<T>, IEntityNameProvider, IEnumerable<T>
2122
{
2223
// This constructor is called by our users, create a new IQueryExecutor.
2324
public NhQueryable(ISessionImplementor session)
@@ -57,5 +58,14 @@ public override string ToString()
5758
{
5859
return "NHibernate.Linq.NhQueryable`1[" + EntityName + "]";
5960
}
61+
62+
IEnumerator<T> IEnumerable<T>.GetEnumerator()
63+
{
64+
//TODO 6.0: Cast to INhQueryProvider
65+
return
66+
Provider is DefaultQueryProvider nhProvider
67+
? nhProvider.ExecuteList<T>(Expression).GetEnumerator()
68+
: base.GetEnumerator();
69+
}
6070
}
6171
}

0 commit comments

Comments
 (0)