/// <summary>Enumerates create enumerable in this collection.</summary> /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception> /// <returns> /// An enumerator that allows foreach to be used to process create enumerable in this collection. /// </returns> public IEnumerable <T> CreateEnumerable() { QueryIncludeOptimizedIncludeSubPath.RemoveLazyChild(this); // MODIFY query if necessary #if EF5 || EF6 var objectContext = OriginalQueryable.GetObjectQuery().Context; var keyMembers = ((dynamic)objectContext).CreateObjectSet <T>().EntitySet.ElementType.KeyMembers; var keyNames = ((IEnumerable <EdmMember>)keyMembers).Select(x => x.Name).ToArray(); #elif EFCORE var context = currentQuery.OriginalQueryable.GetDbContext(); var keyNames = context.Model.FindEntityType(typeof(TResult).DisplayName(true)) .GetKeys().ToList()[0] .Properties.Select(x => x.Name).ToArray(); #endif var newQuery = OriginalQueryable.AddToRootOrAppendOrderBy(keyNames).Select(x => x); foreach (var child in Childs) { child.CreateIncludeQuery(newQuery); } // RESOLVE current and all future child queries var list = QueryIncludeOptimizedManager.AllowQueryBatch ? newQuery.Future().ToList() : newQuery.ToList(); // FIX collection null QueryIncludeOptimizedNullCollection.NullCollectionToEmpty(list, Childs); return(list); }
private static IQueryable <T> IncludeOptimizedSingle <T, TChild>(this IQueryable <T> query, Expression <Func <T, TChild> > queryIncludeFilter) where T : class where TChild : class { // INCLUDE sub path query = QueryIncludeOptimizedIncludeSubPath.IncludeSubPath(query, queryIncludeFilter); // GET query root var includeOrderedQueryable = query as QueryIncludeOptimizedParentQueryable <T> ?? new QueryIncludeOptimizedParentQueryable <T>(query); // ADD sub query includeOrderedQueryable.Childs.Add(new QueryIncludeOptimizedChild <T, TChild>(queryIncludeFilter)); // RETURN root return(includeOrderedQueryable); }
/// <summary>Enumerates create enumerable in this collection.</summary> /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception> /// <returns> /// An enumerator that allows foreach to be used to process create enumerable in this collection. /// </returns> public IEnumerable <T> CreateEnumerable() { //var objectQuery = OriginalQueryable.GetObjectQuery(); //if (objectQuery.MergeOption == MergeOption.NoTracking) //{ // objectQuery.MergeOption = MergeOption.AppendOnly; // var newContext = QueryIncludeOptimizedManager.DbContextFactory(objectQuery.Context.GetDbContext()).GetObjectContext(); // // CHANGE the context under the objectQuery // { // var internalQueryProperty = OriginalQueryable.GetType().GetProperty("InternalQuery", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); // var internalQuery = internalQueryProperty.GetValue(OriginalQueryable); // //var internalQueryProperty = typeof(DbQuery).GetProperty("InternalQuery", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); // //var internalQuery = internalQueryProperty.GetValue(OriginalQueryable, null); // var stateField = typeof(ObjectQuery).GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance); // var state = stateField.GetValue(objectQuery); // var assembly = typeof(ObjectQuery).Assembly; // var objectQueryState = assembly.GetType("System.Data.Entity.Core.Objects.Internal.ObjectQueryState"); // var contextField = objectQueryState.GetField("_context", BindingFlags.NonPublic | BindingFlags.Instance); // contextField.SetValue(state, newContext); // var expressionField = state.GetType().GetField("_expression", BindingFlags.NonPublic | BindingFlags.Instance); // var expression = (Expression)expressionField.GetValue(state); // var visitor = new QueryIncludeOptimizedExpressionReduceVisitor2(); // expression = visitor.Visit(expression); // } //} QueryIncludeOptimizedIncludeSubPath.RemoveLazyChild(this); // MODIFY query if necessary #if EF5 || EF6 var objectContext = OriginalQueryable.GetObjectQuery().Context; var keyMembers = objectContext.GetEntitySet <T>().ElementType.KeyMembers; var keyNames = keyMembers.Select(x => x.Name).ToArray(); #elif EFCORE var context = currentQuery.OriginalQueryable.GetDbContext(); var keyNames = context.Model.FindEntityType(typeof(TResult).DisplayName(true)) .GetKeys().ToList()[0] .Properties.Select(x => x.Name).ToArray(); #endif var newQuery = OriginalQueryable.AddToRootOrAppendOrderBy(keyNames).Select(x => x); List <T> list; if (QueryIncludeOptimizedManager.AllowQueryBatch) { var future = newQuery.Future(); foreach (var child in Childs) { child.CreateIncludeQuery(newQuery); } list = future.ToList(); } else { list = newQuery.ToList(); foreach (var child in Childs) { child.CreateIncludeQuery(newQuery); } } #if EF6 // FIX lazy loading QueryIncludeOptimizedLazyLoading.SetLazyLoaded(list, Childs); #endif // FIX collection null QueryIncludeOptimizedNullCollection.NullCollectionToEmpty(list, Childs); return(list); }
/// <summary>Executes the given expression.</summary> /// <exception cref="Exception">Thrown when an exception error condition occurs.</exception> /// <typeparam name="TResult">Type of the result.</typeparam> /// <param name="expression">The expression to execute.</param> /// <returns>The object returned by the execution of the expression.</returns> public TResult Execute <TResult>(Expression expression) { var methodCall = expression as MethodCallExpression; if (methodCall == null) { throw new Exception(ExceptionMessage.GeneralException); } if (methodCall.Method.Name == "All" || methodCall.Method.Name == "Any" || methodCall.Method.Name == "Average" || methodCall.Method.Name == "Contains" || methodCall.Method.Name == "Count" || methodCall.Method.Name == "LongCount" || methodCall.Method.Name == "Max" || methodCall.Method.Name == "Min" || methodCall.Method.Name == "SequenceEqual" || methodCall.Method.Name == "Sum") { return(OriginalProvider.Execute <TResult>(expression)); } QueryIncludeOptimizedIncludeSubPath.RemoveLazyChild(CurrentQueryable); var currentQuery = CurrentQueryable; var currentMethod = methodCall.Method.GetGenericMethodDefinition(); // CHECK if the internal expression can be supported var isExpressionSupported = false; var firstExpression = methodCall.Arguments.FirstOrDefault(x => x.Type.IsSubclassOf(typeof(Expression))); if (firstExpression != null && methodCall.Arguments.Count == 2) { var quoteExpression = ((UnaryExpression)firstExpression).Operand; var lambdaExpression = quoteExpression as LambdaExpression; if (lambdaExpression != null) { if (lambdaExpression.Type == typeof(Func <,>).MakeGenericType(currentQuery.ElementType, typeof(bool))) { var method = typeof(Queryable).GetMethods().First(x => x.Name == "Where" && x.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2); var methodGeneric = method.MakeGenericMethod(currentQuery.ElementType); currentQuery = (QueryIncludeOptimizedParentQueryable <T>)methodGeneric.Invoke(null, new object[] { currentQuery, lambdaExpression }); currentMethod = typeof(Queryable).GetMethods().FirstOrDefault(x => x.Name == currentMethod.Name && x.GetParameters().Length == 1); isExpressionSupported = currentMethod != null; } } } if (firstExpression != null && !isExpressionSupported) { throw new Exception(ExceptionMessage.QueryIncludeOptimized_ArgumentExpression); } // CREATE the new query by selecting included entities in an anonymous type var newQuery = currentQuery; // REPLACE the first argument with the new query expression var arguments = methodCall.Arguments.ToList(); arguments[0] = newQuery.Expression; // REMOVE the last argument if a "Predicate" method was previously used if (firstExpression != null) { arguments.RemoveAt(1); } // RESOLE parent queries using .FutureValue(); #if EFCORE_3X var immediateQuery = new EntityQueryable <TResult>((IAsyncQueryProvider)OriginalProvider, expression); #elif EF5 || EF6 var objectQuery = CurrentQueryable.OriginalQueryable.GetObjectQuery(); // GET provider // because IQueryable.Provider call : ObjectQueryProvider and now that work for EF5 var objectQueryProviderField = typeof(ObjectQuery).GetProperty("System.Linq.IQueryable.Provider", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); var provider = (IQueryProvider)objectQueryProviderField.GetValue(objectQuery, null); // CREATE query from the expression var createQueryMethod = provider.GetType().GetMethod("CreateQuery", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(Expression) }, null); createQueryMethod = createQueryMethod.MakeGenericMethod(typeof(TResult)); var immediateQuery = (ObjectQuery <T>)createQueryMethod.Invoke(provider, new object[] { expression }); #endif object value = null; if (QueryIncludeOptimizedManager.AllowQueryBatch) { var futureValue = immediateQuery.FutureValue(); // RESOLVE child queries using .Future() { // MODIFY query if necessary #if EF5 || EF6 var objectContext = CurrentQueryable.OriginalQueryable.GetObjectQuery().Context; var keyMembers = objectContext.GetEntitySet <T>().ElementType.KeyMembers; var keyNames = ((IEnumerable <EdmMember>)keyMembers).Select(x => x.Name).ToArray(); #elif EFCORE var context = currentQuery.OriginalQueryable.GetDbContext(); var keyNames = context.Model.FindEntityType(typeof(TResult).DisplayName(true)) .GetKeys().ToList()[0] .Properties.Select(x => x.Name).ToArray(); #endif var currentNewQuery = methodCall.Method.Name == "First" || methodCall.Method.Name == "FirstOrDefault" ? currentQuery.AddToRootOrAppendOrderBy(keyNames).Take(1) : methodCall.Method.Name == "Last" || methodCall.Method.Name == "LastOrDefault" ? currentQuery.AddToRootOrAppendOrderBy(keyNames).Reverse().Take(1) : currentQuery; currentQuery.CreateQueryable(currentNewQuery); } value = futureValue.Value; } else { #if EFCORE_3X value = immediateQuery.FutureValue().Value; #else value = immediateQuery.Execute(objectQuery.MergeOption).FirstOrDefault(); #endif // RESOLVE child queries using .Future() { // MODIFY query if necessary #if EF5 || EF6 var objectContext = CurrentQueryable.OriginalQueryable.GetObjectQuery().Context; var keyMembers = ((dynamic)objectContext).CreateObjectSet <T>().EntitySet.ElementType.KeyMembers; var keyNames = ((IEnumerable <EdmMember>)keyMembers).Select(x => x.Name).ToArray(); #elif EFCORE var context = currentQuery.OriginalQueryable.GetDbContext(); var keyNames = context.Model.FindEntityType(typeof(TResult).DisplayName(true)) .GetKeys().ToList()[0] .Properties.Select(x => x.Name).ToArray(); #endif var currentNewQuery = methodCall.Method.Name == "First" || methodCall.Method.Name == "FirstOrDefault" ? currentQuery.AddToRootOrAppendOrderBy(keyNames).Take(1) : methodCall.Method.Name == "Last" || methodCall.Method.Name == "LastOrDefault" ? currentQuery.AddToRootOrAppendOrderBy(keyNames).Reverse().Take(1) : currentQuery; currentQuery.CreateQueryable(currentNewQuery); } } // EXECUTE the new expression //var value = QueryIncludeOptimizedManager.AllowQueryBatch ? immediateQuery.FutureValue().Value : immediateQuery.FirstOrDefault(); // CHECK if a value has been returned if (value == null) { return((TResult)(object)null); } #if EF6 // FIX lazy loading QueryIncludeOptimizedLazyLoading.SetLazyLoaded(value, CurrentQueryable.Childs); #endif // FIX null collection QueryIncludeOptimizedNullCollection.NullCollectionToEmpty(value, CurrentQueryable.Childs); #if EF5 || EF6 return((TResult)(object)value); #elif EFCORE return((TResult)value); #endif }
public async Task <List <T> > CreateEnumerableAsync(CancellationToken cancellationToken) { QueryIncludeOptimizedIncludeSubPath.RemoveLazyChild(this); // MODIFY query if necessary #if EF5 || EF6 var objectContext = OriginalQueryable.GetObjectQuery().Context; var keyMembers = objectContext.GetEntitySet <T>().ElementType.KeyMembers; var keyNames = keyMembers.Select(x => x.Name).ToArray(); #elif EFCORE DbContext context = null; if (OriginalQueryable.IsInMemoryQueryContext()) { context = OriginalQueryable.GetInMemoryContext(); } else { // MODIFY query if necessary context = OriginalQueryable.GetDbContext(); } var keyNames = context.Model.FindEntityType(typeof(T).DisplayName(true)) .GetKeys().ToList()[0] .Properties.Select(x => x.Name).ToArray(); #endif var newQuery = OriginalQueryable.AddToRootOrAppendOrderBy(keyNames).Select(x => x); List <T> list; if (QueryIncludeOptimizedManager.AllowQueryBatch) { var future = newQuery.Future(); foreach (var child in Childs) { child.CreateIncludeQuery(newQuery); } list = await future.ToListAsync(cancellationToken).ConfigureAwait(false); } else { list = await newQuery.ToListAsync(cancellationToken).ConfigureAwait(false); foreach (var child in Childs) { child.CreateIncludeQuery(newQuery); } } #if EF6 // FIX lazy loading QueryIncludeOptimizedLazyLoading.SetLazyLoaded(list, Childs); #endif // FIX collection null QueryIncludeOptimizedNullCollection.NullCollectionToEmpty(list, Childs); return(list); }