|
6 | 6 | using NHibernate.Impl;
|
7 | 7 | using NHibernate.Type;
|
8 | 8 | using NHibernate.Util;
|
9 |
| -using Remotion.Linq; |
10 | 9 | using Remotion.Linq.Parsing.ExpressionTreeVisitors;
|
11 | 10 |
|
12 | 11 | namespace NHibernate.Linq
|
13 | 12 | {
|
| 13 | + /// <summary> |
| 14 | + /// NHibernate LINQ extension methods. They are meant to work with <see cref="NhQueryable{T}"/>. Supplied <see cref="IQueryable{T}"/> parameters |
| 15 | + /// should at least have an <see cref="INhQueryProvider"/> <see cref="IQueryable.Provider"/>. <see cref="LinqExtensionMethods.Query{T}(ISession)"/> and |
| 16 | + /// its overloads supply such queryables. |
| 17 | + /// </summary> |
14 | 18 | public static class LinqExtensionMethods
|
15 | 19 | {
|
16 | 20 | public static IQueryable<T> Query<T>(this ISession session)
|
@@ -77,51 +81,87 @@ public static IQueryable<T> Timeout<T>(this IQueryable<T> query, int timeout)
|
77 | 81 | return new NhQueryable<T>(query.Provider, callExpression);
|
78 | 82 | }
|
79 | 83 |
|
80 |
| - public static IEnumerable<T> ToFuture<T>(this IQueryable<T> query) |
| 84 | + /// <summary> |
| 85 | + /// Wraps the query in a deferred <see cref="IEnumerable{T}"/> which enumeration will trigger a batch of all pending future queries. |
| 86 | + /// </summary> |
| 87 | + /// <param name="source">An <see cref="T:System.Linq.IQueryable`1" /> to convert to a future query.</param> |
| 88 | + /// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam> |
| 89 | + /// <returns>A <see cref="IEnumerable{T}"/>.</returns> |
| 90 | + /// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception> |
| 91 | + /// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception> |
| 92 | + public static IEnumerable<TSource> ToFuture<TSource>(this IQueryable<TSource> source) |
81 | 93 | {
|
82 |
| - var nhQueryable = query as QueryableBase<T>; |
83 |
| - if (nhQueryable == null) |
84 |
| - throw new NotSupportedException("Query needs to be of type QueryableBase<T>"); |
85 |
| - |
86 |
| - var provider = (INhQueryProvider) nhQueryable.Provider; |
87 |
| - var future = provider.ExecuteFuture(nhQueryable.Expression); |
88 |
| - return (IEnumerable<T>) future; |
| 94 | + if (source == null) |
| 95 | + { |
| 96 | + throw new ArgumentNullException(nameof(source)); |
| 97 | + } |
| 98 | + if (!(source.Provider is INhQueryProvider provider)) |
| 99 | + { |
| 100 | + throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}"); |
| 101 | + } |
| 102 | + var future = provider.ExecuteFuture(source.Expression); |
| 103 | + return (IEnumerable<TSource>)future; |
89 | 104 | }
|
90 | 105 |
|
91 |
| - public static IFutureValue<T> ToFutureValue<T>(this IQueryable<T> query) |
| 106 | + /// <summary> |
| 107 | + /// Wraps the query in a deferred <see cref="IFutureValue{T}"/> which will trigger a batch of all pending future queries |
| 108 | + /// when its <see cref="IFutureValue{T}.Value"/> is read. |
| 109 | + /// </summary> |
| 110 | + /// <param name="source">An <see cref="T:System.Linq.IQueryable`1" /> to convert to a future query.</param> |
| 111 | + /// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam> |
| 112 | + /// <returns>A <see cref="IFutureValue{T}"/>.</returns> |
| 113 | + /// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception> |
| 114 | + /// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception> |
| 115 | + public static IFutureValue<TSource> ToFutureValue<TSource>(this IQueryable<TSource> source) |
92 | 116 | {
|
93 |
| - var nhQueryable = query as QueryableBase<T>; |
94 |
| - if (nhQueryable == null) |
95 |
| - throw new NotSupportedException("Query needs to be of type QueryableBase<T>"); |
96 |
| - |
97 |
| - var provider = (INhQueryProvider) nhQueryable.Provider; |
98 |
| - var future = provider.ExecuteFuture(nhQueryable.Expression); |
99 |
| - if (future is IEnumerable<T>) |
| 117 | + if (source == null) |
100 | 118 | {
|
101 |
| - return new FutureValue<T>(() => ((IEnumerable<T>) future)); |
| 119 | + throw new ArgumentNullException(nameof(source)); |
| 120 | + } |
| 121 | + if (!(source.Provider is INhQueryProvider provider)) |
| 122 | + { |
| 123 | + throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}"); |
| 124 | + } |
| 125 | + var future = provider.ExecuteFuture(source.Expression); |
| 126 | + if (future is IEnumerable<TSource> enumerable) |
| 127 | + { |
| 128 | + return new FutureValue<TSource>(() => enumerable); |
102 | 129 | }
|
103 | 130 |
|
104 |
| - return (IFutureValue<T>) future; |
| 131 | + return (IFutureValue<TSource>)future; |
105 | 132 | }
|
106 | 133 |
|
107 |
| - public static T MappedAs<T>(this T parameter, IType type) |
| 134 | + /// <summary> |
| 135 | + /// Wraps the query in a deferred <see cref="IFutureValue{T}"/> which will trigger a batch of all pending future queries |
| 136 | + /// when its <see cref="IFutureValue{T}.Value"/> is read. |
| 137 | + /// </summary> |
| 138 | + /// <param name="source">An <see cref="T:System.Linq.IQueryable`1" /> to convert to a future query.</param> |
| 139 | + /// <param name="selector">An aggregation function to apply to <paramref name="source"/>.</param> |
| 140 | + /// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam> |
| 141 | + /// <typeparam name="TResult">The type of the value returned by the function represented by <paramref name="selector"/>.</typeparam> |
| 142 | + /// <returns>A <see cref="IFutureValue{T}"/>.</returns> |
| 143 | + /// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception> |
| 144 | + /// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception> |
| 145 | + public static IFutureValue<TResult> ToFutureValue<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<IQueryable<TSource>, TResult>> selector) |
108 | 146 | {
|
109 |
| - throw new InvalidOperationException("The method should be used inside Linq to indicate a type of a parameter"); |
110 |
| - } |
111 |
| - |
112 |
| - public static IFutureValue<TResult> ToFutureValue<T, TResult>(this IQueryable<T> query, Expression<Func<IQueryable<T>, TResult>> selector) |
113 |
| - { |
114 |
| - var nhQueryable = query as QueryableBase<T>; |
115 |
| - if (nhQueryable == null) |
116 |
| - throw new NotSupportedException("Query needs to be of type QueryableBase<T>"); |
| 147 | + if (source == null) |
| 148 | + { |
| 149 | + throw new ArgumentNullException(nameof(source)); |
| 150 | + } |
| 151 | + if (!(source.Provider is INhQueryProvider provider)) |
| 152 | + { |
| 153 | + throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}"); |
| 154 | + } |
117 | 155 |
|
118 |
| - var provider = (INhQueryProvider) query.Provider; |
| 156 | + var expression = ReplacingExpressionTreeVisitor |
| 157 | + .Replace(selector.Parameters.Single(), source.Expression, selector.Body); |
119 | 158 |
|
120 |
| - var expression = ReplacingExpressionTreeVisitor.Replace(selector.Parameters.Single(), |
121 |
| - query.Expression, |
122 |
| - selector.Body); |
| 159 | + return (IFutureValue<TResult>)provider.ExecuteFuture(expression); |
| 160 | + } |
123 | 161 |
|
124 |
| - return (IFutureValue<TResult>) provider.ExecuteFuture(expression); |
| 162 | + public static T MappedAs<T>(this T parameter, IType type) |
| 163 | + { |
| 164 | + throw new InvalidOperationException("The method should be used inside Linq to indicate a type of a parameter"); |
125 | 165 | }
|
126 | 166 | }
|
127 | 167 | }
|
0 commit comments