PageRenderTime 2ms CodeModel.GetById 27ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Data.Linq/src/DbLinq/Data/Linq/Implementation/QueryProvider.cs

https://github.com/ztfuqingvip/mono
C# | 239 lines | 114 code | 17 blank | 108 comment | 9 complexity | 0ab41400f16e8cb736a75e214f148930 MD5 | raw file
  1#region MIT license
  2// 
  3// MIT license
  4//
  5// Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
  6// 
  7// Permission is hereby granted, free of charge, to any person obtaining a copy
  8// of this software and associated documentation files (the "Software"), to deal
  9// in the Software without restriction, including without limitation the rights
 10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11// copies of the Software, and to permit persons to whom the Software is
 12// furnished to do so, subject to the following conditions:
 13// 
 14// The above copyright notice and this permission notice shall be included in
 15// all copies or substantial portions of the Software.
 16// 
 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23// THE SOFTWARE.
 24// 
 25#endregion
 26
 27using System;
 28using System.Collections;
 29using System.Collections.Generic;
 30using System.Linq;
 31using System.Linq.Expressions;
 32using DbLinq.Data.Linq.Sugar;
 33using DbLinq.Util;
 34
 35#if MONO_STRICT
 36using System.Data.Linq;
 37#else
 38using DbLinq.Data.Linq;
 39#endif
 40
 41namespace DbLinq.Data.Linq.Implementation
 42{
 43    /// <summary>
 44    /// QueryProvider is used by both DataContext and Table
 45    /// to build queries
 46    /// It is split is two parts (non-generic and generic) for copy reasons
 47    /// </summary>
 48    internal abstract class QueryProvider
 49    {
 50        /// <summary>
 51        /// Gets or sets the expression chain.
 52        /// </summary>
 53        /// <value>The expression chain.</value>
 54        public ExpressionChain ExpressionChain { get; set; }
 55        /// <summary>
 56        /// Gets or sets the type of the table.
 57        /// </summary>
 58        /// <value>The type of the table.</value>
 59        public Type TableType { get; set; }
 60        /// <summary>
 61        /// Gets the query.
 62        /// </summary>
 63        /// <param name="expression">The expression.</param>
 64        /// <returns></returns>
 65        public abstract SelectQuery GetQuery(Expression expression);
 66    }
 67
 68    /// <summary>
 69    /// QueryProvider, generic version
 70    /// </summary>
 71    /// <typeparam name="T"></typeparam>
 72    internal class QueryProvider<T> : QueryProvider, IQueryProvider, IQueryable<T>, IOrderedQueryable<T>
 73    {
 74        /// <summary>
 75        /// Holder current datancontext
 76        /// </summary>
 77        protected readonly DataContext _dataContext;
 78
 79        /// <summary>
 80        /// Initializes a new instance of the <see cref="QueryProvider&lt;T&gt;"/> class.
 81        /// </summary>
 82        /// <param name="dataContext">The data context.</param>
 83        public QueryProvider(DataContext dataContext)
 84        {
 85            _dataContext = dataContext;
 86            TableType = typeof(T);
 87            ExpressionChain = new ExpressionChain();
 88        }
 89
 90        /// <summary>
 91        /// Initializes a new instance of the <see cref="QueryProvider&lt;T&gt;"/> class.
 92        /// </summary>
 93        /// <param name="tableType">Type of the table.</param>
 94        /// <param name="dataContext">The data context.</param>
 95        /// <param name="expressionChain">The expression chain.</param>
 96        /// <param name="expression">The expression.</param>
 97        public QueryProvider(Type tableType, DataContext dataContext, ExpressionChain expressionChain, Expression expression)
 98        {
 99            _dataContext = dataContext;
100            TableType = tableType;
101            ExpressionChain = new ExpressionChain(expressionChain, expression);
102        }
103
104        /// <summary>
105        /// Creates the query.
106        /// </summary>
107        /// <typeparam name="S"></typeparam>
108        /// <param name="t">The t.</param>
109        /// <param name="tableType">Type of the table.</param>
110        /// <param name="dataContext">The data context.</param>
111        /// <param name="expressionChain">The expression chain.</param>
112        /// <param name="expression">The expression.</param>
113        /// <returns></returns>
114        protected S CreateQuery<S>(Type t, Type tableType, DataContext dataContext, ExpressionChain expressionChain, Expression expression)
115        {
116            // no way to work differently
117            var typedQueryProviderType = typeof(QueryProvider<>).MakeGenericType(t);
118            var queryProvider = (S)Activator.CreateInstance(typedQueryProviderType, tableType, dataContext,
119                                                             expressionChain, expression);
120            return queryProvider;
121        }
122
123        /// <summary>
124        /// Builds the query, given a LINQ expression
125        /// </summary>
126        /// <param name="expression"></param>
127        /// <returns></returns>
128        public IQueryable CreateQuery(Expression expression)
129        {
130            var type = expression.Type;
131            if (!type.IsGenericType)
132                throw Error.BadArgument("S0066: Don't know how to handle non-generic type '{0}'", type);
133            var genericType = type.GetGenericTypeDefinition();
134            if (genericType == typeof(IQueryable<>) || genericType == typeof(IOrderedQueryable<>))
135                type = type.GetGenericArguments()[0];
136            else
137                Error.BadArgument("S0068: Don't know how to handle type '{0}'", type);
138            return CreateQuery<IQueryable>(type, TableType, _dataContext, ExpressionChain, expression);
139        }
140
141        /// <summary>
142        /// Creates the query.
143        /// </summary>
144        /// <typeparam name="TElement">The type of the element.</typeparam>
145        /// <param name="expression">The expression.</param>
146        /// <returns></returns>
147        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
148        {
149            Profiler.At("START QueryProvider.CreateQuery<{0}>({1})", typeof(TElement).Name, expression.ToString());
150            var query = new QueryProvider<TElement>(TableType, _dataContext, ExpressionChain, expression);
151            Profiler.At("END QueryProvider.CreateQuery<{0}>(...)", typeof(TElement).Name);
152            return query;
153        }
154
155        /// <summary>
156        /// Gets the query.
157        /// </summary>
158        /// <param name="expression">The expression.</param>
159        /// <returns></returns>
160        public override SelectQuery GetQuery(Expression expression)
161        {
162            var expressionChain = ExpressionChain;
163            if (expression != null)
164                expressionChain = new ExpressionChain(expressionChain, expression);
165            return _dataContext.QueryBuilder.GetSelectQuery(expressionChain, new QueryContext(_dataContext));
166        }
167
168        /// <summary>
169        /// Runs query
170        /// </summary>
171        /// <param name="expression"></param>
172        /// <returns></returns>
173        public object Execute(Expression expression)
174        {
175            return this.GetType()
176                .GetMethods()
177                .Where(m => m.Name == "Execute" && m.IsGenericMethod)
178                .Single()
179                .MakeGenericMethod(new Type[] { expression.Type })
180                .Invoke(this, new object[] { expression });
181        }
182
183        /// <summary>
184        /// Runs query
185        /// </summary>
186        /// <typeparam name="TResult"></typeparam>
187        /// <param name="expression"></param>
188        /// <returns></returns>
189        public TResult Execute<TResult>(Expression expression)
190        {
191            Profiler.At("START QueryProvider.Execute<{0}>(): Executing expression...", typeof(TResult).Name);
192            var query = GetQuery(expression);
193            var result = _dataContext.QueryRunner.SelectScalar<TResult>(query);
194            Profiler.At("END QueryProvider.Execute<{0}>(): Executing expression...", typeof(TResult).Name);
195            return result;
196        }
197
198        /// <summary>
199        /// Enumerates all query items
200        /// </summary>
201        /// <returns></returns>
202        IEnumerator IEnumerable.GetEnumerator()
203        {
204            var enumerator = GetEnumerator();
205            return enumerator;
206        }
207
208        /// <summary>
209        /// Enumerates all query items
210        /// </summary>
211        /// <returns></returns>
212        public IEnumerator<T> GetEnumerator()
213        {
214            Profiler.At("START QueryProvider.GetEnumerator<{0}>(): Executing expression...", typeof(T).Name);
215            var query = GetQuery(null);
216            var enumerator = _dataContext.QueryRunner.Select<T>(query).GetEnumerator();
217            Profiler.At("END QueryProvider.GetEnumerator<{0}>(): Executing expression...", typeof(T).Name);
218            return enumerator;
219        }
220
221        /// <summary>
222        /// Returns this QueryProvider as an exception
223        /// </summary>
224        public Expression Expression
225        {
226            get { return Expression.Constant(this); }
227        }
228
229        public Type ElementType
230        {
231            get { return (typeof(T)); }
232        }
233
234        public IQueryProvider Provider
235        {
236            get { return this; }
237        }
238    }
239}