You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/05/29 07:18:34 UTC

[18/30] ignite git commit: IGNITE-4904 .NET: DML Delete via LINQ

IGNITE-4904 .NET: DML Delete via LINQ

This closes #2009


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/d38ca8b1
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/d38ca8b1
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/d38ca8b1

Branch: refs/heads/ignite-5075-pds
Commit: d38ca8b1004effefa5126981f434649d26db1e68
Parents: 279f35b
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Fri May 26 13:02:01 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Fri May 26 13:02:01 2017 +0300

----------------------------------------------------------------------
 .../Cache/Query/CacheLinqTest.cs                | 70 +++++++++++++++-
 .../Apache.Ignite.Linq.csproj                   |  3 +
 .../Apache.Ignite.Linq/CacheExtensions.cs       | 65 +++++++++++++++
 .../Impl/CacheQueryModelVisitor.cs              | 60 +++++++++++--
 .../Apache.Ignite.Linq/Impl/CacheQueryParser.cs | 21 ++++-
 .../Impl/Dml/RemoveAllExpressionNode.cs         | 88 ++++++++++++++++++++
 .../Impl/Dml/RemoveAllResultOperator.cs         | 61 ++++++++++++++
 .../dotnet/Apache.Ignite.sln.DotSettings        |  1 +
 8 files changed, 359 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/d38ca8b1/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
index cb3fece..b603d75 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTest.cs
@@ -37,6 +37,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
     using Apache.Ignite.Core.Cache;
     using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Query;
+    using Apache.Ignite.Core.Common;
     using Apache.Ignite.Linq;
     using NUnit.Framework;
 
@@ -1269,7 +1270,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
             var cache = GetPersonCache();
 
             // Check regular query
-            var query = (ICacheQueryable) cache.AsCacheQueryable(new QueryOptions
+            var query = cache.AsCacheQueryable(new QueryOptions
             {
                 Local = true,
                 PageSize = 999,
@@ -1277,7 +1278,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
                 Timeout = TimeSpan.FromSeconds(2.5),
                 ReplicatedOnly = true,
                 Colocated = true
-            }).Where(x => x.Key > 10);
+            }).Where(x => x.Key > 10).ToCacheQueryable();
 
             Assert.AreEqual(cache.Name, query.CacheName);
             Assert.AreEqual(cache.Ignite, query.Ignite);
@@ -1325,7 +1326,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
             var distrQuery = cache.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true})
                 .Where(x => x.Key > 10 && x.Value.Age > 20 && x.Value.Name.Contains("x"));
 
-            query = (ICacheQueryable) distrQuery;
+            query = distrQuery.ToCacheQueryable();
 
             Assert.IsTrue(query.GetFieldsQuery().EnableDistributedJoins);
 
@@ -1424,6 +1425,69 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         }
 
         /// <summary>
+        /// Tests the RemoveAll extension.
+        /// </summary>
+        [Test]
+        public void TestRemoveAll()
+        {
+            // Use new cache to avoid touching static data.
+            var cache = Ignition.GetIgnite().CreateCache<int, Person>(new CacheConfiguration("deleteAllTest",
+                    new QueryEntity(typeof(int), typeof(Person))));
+
+            Enumerable.Range(1, 10).ToList().ForEach(x => cache.Put(x, new Person(x, x.ToString())));
+            
+            var queryable = cache.AsCacheQueryable();
+
+            Func<int[]> getKeys = () => cache.Select(x => x.Key).OrderBy(x => x).ToArray();
+
+            // Without predicate.
+            var res = queryable.Where(x => x.Key < 3).RemoveAll();
+            Assert.AreEqual(2, res);
+            Assert.AreEqual(Enumerable.Range(3, 8), getKeys());
+
+            // With predicate.
+            res = queryable.RemoveAll(x => x.Key < 7);
+            Assert.AreEqual(4, res);
+            Assert.AreEqual(Enumerable.Range(7, 4), getKeys());
+
+            // Subquery-style join.
+            var ids = GetPersonCache().AsCacheQueryable().Where(x => x.Key == 7).Select(x => x.Key);
+
+            res = queryable.Where(x => ids.Contains(x.Key)).RemoveAll();
+            Assert.AreEqual(1, res);
+            Assert.AreEqual(Enumerable.Range(8, 3), getKeys());
+
+            // Row number limit.
+            res = queryable.Take(2).RemoveAll();
+            Assert.AreEqual(2, res);
+            Assert.AreEqual(1, getKeys().Length);
+
+            // Unconditional.
+            queryable.RemoveAll();
+            Assert.AreEqual(0, cache.GetSize());
+
+            // Skip is not supported with DELETE.
+            var nex = Assert.Throws<NotSupportedException>(() => queryable.Skip(1).RemoveAll());
+            Assert.AreEqual(
+                "RemoveAll can not be combined with result operators (other than Take): SkipResultOperator",
+                nex.Message);
+
+            // Multiple result operators are not supported with DELETE.
+            nex = Assert.Throws<NotSupportedException>(() => queryable.Skip(1).Take(1).RemoveAll());
+            Assert.AreEqual(
+                "RemoveAll can not be combined with result operators (other than Take): SkipResultOperator, " +
+                "TakeResultOperator, RemoveAllResultOperator", nex.Message);
+
+            // Joins are not supported in H2.
+            var qry = queryable
+                .Where(x => x.Key == 7)
+                .Join(GetPersonCache().AsCacheQueryable(), p => p.Key, p => p.Key, (p1, p2) => p1);
+
+            var ex = Assert.Throws<IgniteException>(() => qry.RemoveAll());
+            Assert.AreEqual("Failed to parse query", ex.Message.Substring(0, 21));
+        }
+
+        /// <summary>
         /// Gets the person cache.
         /// </summary>
         /// <returns></returns>

http://git-wip-us.apache.org/repos/asf/ignite/blob/d38ca8b1/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
index a7ec402..f4949d7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
@@ -63,6 +63,8 @@
     <Compile Include="Impl\CacheQueryExpressionVisitor.cs" />
     <Compile Include="Impl\CacheQueryModelVisitor.cs" />
     <Compile Include="Impl\CacheQueryParser.cs" />
+    <Compile Include="Impl\Dml\RemoveAllExpressionNode.cs" />
+    <Compile Include="Impl\Dml\RemoveAllResultOperator.cs" />
     <Compile Include="Impl\ICacheQueryableInternal.cs" />
     <Compile Include="Impl\MethodVisitor.cs" />
     <Compile Include="Impl\QueryData.cs" />
@@ -83,6 +85,7 @@
       <Name>Apache.Ignite.Core</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

http://git-wip-us.apache.org/repos/asf/ignite/blob/d38ca8b1/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
index 2c609c6..f759dbb 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
@@ -17,11 +17,15 @@
 
 namespace Apache.Ignite.Linq
 {
+    using System;
+    using System.Diagnostics.CodeAnalysis;
     using System.Linq;
+    using System.Linq.Expressions;
     using Apache.Ignite.Core.Cache;
     using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Linq.Impl;
+    using Apache.Ignite.Linq.Impl.Dml;
 
     /// <summary>
     /// Extensions methods for <see cref="ICache{TK,TV}"/>.
@@ -126,5 +130,66 @@ namespace Apache.Ignite.Linq
 
             return new CacheQueryable<TKey, TValue>(cache, queryOptions);
         }
+
+        /// <summary>
+        /// Casts this query to <see cref="ICacheQueryable"/>.
+        /// </summary>
+        public static ICacheQueryable ToCacheQueryable<T>(this IQueryable<T> query)
+        {
+            IgniteArgumentCheck.NotNull(query, "query");
+
+            return (ICacheQueryable) query;
+        }
+
+        /// <summary>
+        /// Removes all rows that are matched by the specified query.
+        /// <para />
+        /// This method results in "DELETE FROM" distributed SQL query, performing bulk delete 
+        /// (as opposed to fetching all rows locally).
+        /// </summary>
+        /// <typeparam name="TKey">Key type.</typeparam>
+        /// <typeparam name="TValue">Value type.</typeparam>
+        /// <param name="query">The query.</param>
+        /// <returns>Affected row count.</returns>
+        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods",
+            Justification = "Validation is present.")]
+        public static int RemoveAll<TKey, TValue>(this IQueryable<ICacheEntry<TKey, TValue>> query)
+        {
+            IgniteArgumentCheck.NotNull(query, "query");
+
+            var method = RemoveAllExpressionNode.RemoveAllMethodInfo.MakeGenericMethod(typeof(TKey), typeof(TValue));
+
+            return query.Provider.Execute<int>(Expression.Call(null, method, query.Expression));
+        }
+
+        /// <summary>
+        /// Deletes all rows that are matched by the specified query.
+        /// <para />
+        /// This method results in "DELETE FROM" distributed SQL query, performing bulk delete
+        /// (as opposed to fetching all rows locally).
+        /// </summary>
+        /// <typeparam name="TKey">Key type.</typeparam>
+        /// <typeparam name="TValue">Value type.</typeparam>
+        /// <param name="query">The query.</param>
+        /// <param name="predicate">The predicate.</param>
+        /// <returns>
+        /// Affected row count.
+        /// </returns>
+        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
+            Justification = "Only specified type of predicate is valid.")]
+        [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods",
+            Justification = "Validation is present.")]
+        public static int RemoveAll<TKey, TValue>(this IQueryable<ICacheEntry<TKey, TValue>> query, 
+            Expression<Func<ICacheEntry<TKey, TValue>, bool>> predicate)
+        {
+            IgniteArgumentCheck.NotNull(query, "query");
+            IgniteArgumentCheck.NotNull(predicate, "predicate");
+
+            var method = RemoveAllExpressionNode.RemoveAllPredicateMethodInfo
+                .MakeGenericMethod(typeof(TKey), typeof(TValue));
+
+            return query.Provider.Execute<int>(Expression.Call(null, method, query.Expression,
+                Expression.Quote(predicate)));
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d38ca8b1/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs
index f566caa..12b9502 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryModelVisitor.cs
@@ -26,6 +26,7 @@ namespace Apache.Ignite.Linq.Impl
     using System.Linq;
     using System.Linq.Expressions;
     using System.Text;
+    using Apache.Ignite.Linq.Impl.Dml;
     using Remotion.Linq;
     using Remotion.Linq.Clauses;
     using Remotion.Linq.Clauses.Expressions;
@@ -100,22 +101,69 @@ namespace Apache.Ignite.Linq.Impl
         {
             _aliases.Push();
 
-            // SELECT
-            _builder.Append("select ");
+            var hasDelete = VisitRemoveOperator(queryModel);
 
-            // TOP 1 FLD1, FLD2
-            VisitSelectors(queryModel, includeAllFields);
+            if (!hasDelete)
+            {
+                // SELECT
+                _builder.Append("select ");
+
+                // TOP 1 FLD1, FLD2
+                VisitSelectors(queryModel, includeAllFields);
+            }
 
             // FROM ... WHERE ... JOIN ...
             base.VisitQueryModel(queryModel);
 
-            // UNION ...
-            ProcessResultOperatorsEnd(queryModel);
+            if (!hasDelete)
+            {
+                // UNION ...
+                ProcessResultOperatorsEnd(queryModel);
+            }
 
             _aliases.Pop();
         }
 
         /// <summary>
+        /// Visits the remove operator. Returns true if it is present.
+        /// </summary>
+        private bool VisitRemoveOperator(QueryModel queryModel)
+        {
+            var resultOps = queryModel.ResultOperators;
+
+            if (resultOps.LastOrDefault() is RemoveAllResultOperator)
+            {
+                _builder.Append("delete ");
+
+                if (resultOps.Count == 2)
+                {
+                    var resOp = resultOps[0] as TakeResultOperator;
+
+                    if (resOp == null)
+                    {
+                        throw new NotSupportedException(
+                            "RemoveAll can not be combined with result operators (other than Take): " +
+                            resultOps[0].GetType().Name);
+                    }
+
+                    _builder.Append("top ");
+                    BuildSqlExpression(resOp.Count);
+                    _builder.Append(" ");
+                }
+                else if (resultOps.Count > 2)
+                {
+                    throw new NotSupportedException(
+                        "RemoveAll can not be combined with result operators (other than Take): " +
+                        string.Join(", ", resultOps.Select(x => x.GetType().Name)));
+                }
+
+                return true;
+            }
+                
+            return false;
+        }
+
+        /// <summary>
         /// Visits the selectors.
         /// </summary>
         public void VisitSelectors(QueryModel queryModel, bool includeAllFields)

http://git-wip-us.apache.org/repos/asf/ignite/blob/d38ca8b1/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryParser.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryParser.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryParser.cs
index 794ef2e..17ec0a3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryParser.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryParser.cs
@@ -18,10 +18,12 @@
 namespace Apache.Ignite.Linq.Impl
 {
     using System.Threading;
+    using Apache.Ignite.Linq.Impl.Dml;
     using Remotion.Linq.Parsing.ExpressionVisitors.Transformation;
     using Remotion.Linq.Parsing.ExpressionVisitors.TreeEvaluation;
     using Remotion.Linq.Parsing.Structure;
     using Remotion.Linq.Parsing.Structure.ExpressionTreeProcessors;
+    using Remotion.Linq.Parsing.Structure.NodeTypeProviders;
 
     /// <summary>
     /// Cache query parser.
@@ -49,12 +51,29 @@ namespace Apache.Ignite.Linq.Impl
 
             var proc = CreateCompoundProcessor(transformerRegistry);
 
-            var parser = new ExpressionTreeParser(ExpressionTreeParser.CreateDefaultNodeTypeProvider(), proc);
+            var parser = new ExpressionTreeParser(CreateNodeTypeProvider(), proc);
 
             return new QueryParser(parser);
         }
 
         /// <summary>
+        /// Creates the node type provider.
+        /// </summary>
+        private static INodeTypeProvider CreateNodeTypeProvider()
+        {
+            var methodInfoRegistry = MethodInfoBasedNodeTypeRegistry.CreateFromRelinqAssembly();
+
+            methodInfoRegistry.Register(RemoveAllExpressionNode.GetSupportedMethods(), 
+                typeof(RemoveAllExpressionNode));
+
+            return new CompoundNodeTypeProvider(new INodeTypeProvider[]
+            {
+                methodInfoRegistry,
+                MethodNameBasedNodeTypeRegistry.CreateFromRelinqAssembly()
+            });
+        }
+
+        /// <summary>
         /// Creates CompoundExpressionTreeProcessor.
         /// </summary>
         private static CompoundExpressionTreeProcessor CreateCompoundProcessor(

http://git-wip-us.apache.org/repos/asf/ignite/blob/d38ca8b1/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/Dml/RemoveAllExpressionNode.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/Dml/RemoveAllExpressionNode.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/Dml/RemoveAllExpressionNode.cs
new file mode 100644
index 0000000..53674ac
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/Dml/RemoveAllExpressionNode.cs
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Linq.Impl.Dml
+{
+    using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Linq;
+    using System.Linq.Expressions;
+    using System.Reflection;
+    using Apache.Ignite.Core.Cache;
+    using Remotion.Linq.Clauses;
+    using Remotion.Linq.Parsing.Structure.IntermediateModel;
+
+    /// <summary>
+    /// Represents a <see cref="MethodCallExpression"/> for 
+    /// <see cref="CacheLinqExtensions.RemoveAll{TKey,TValue}(IQueryable{ICacheEntry{TKey,TValue}})"/>.
+    /// When user calls RemoveAll, this node is generated.
+    /// </summary>
+    internal sealed class RemoveAllExpressionNode : ResultOperatorExpressionNodeBase
+    {
+        /** */
+        private static readonly MethodInfo[] RemoveAllMethodInfos = typeof(CacheLinqExtensions)
+            .GetMethods().Where(x => x.Name == "RemoveAll").ToArray();
+
+        /// <summary>
+        /// The RemoveAll() method.
+        /// </summary>
+        public static readonly MethodInfo RemoveAllMethodInfo =
+            RemoveAllMethodInfos.Single(x => x.GetParameters().Length == 1);
+
+        /// <summary>
+        /// The RemoveAll(pred) method.
+        /// </summary>
+        public static readonly MethodInfo RemoveAllPredicateMethodInfo =
+            RemoveAllMethodInfos.Single(x => x.GetParameters().Length == 2);
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RemoveAllExpressionNode"/> class.
+        /// </summary>
+        /// <param name="parseInfo">The parse information.</param>
+        /// <param name="optionalPredicate">The optional predicate.</param>
+        /// <param name="optionalSelector">The optional selector.</param>
+        public RemoveAllExpressionNode(MethodCallExpressionParseInfo parseInfo,
+            LambdaExpression optionalPredicate, LambdaExpression optionalSelector)
+            : base(parseInfo, optionalPredicate, optionalSelector)
+        {
+            // No-op.
+        }
+
+        /** <inheritdoc /> */
+        [ExcludeFromCodeCoverage]
+        public override Expression Resolve(ParameterExpression inputParameter, Expression expressionToBeResolved,
+            ClauseGenerationContext clauseGenerationContext)
+        {
+            throw CreateResolveNotSupportedException();
+        }
+
+        /** <inheritdoc /> */
+        protected override ResultOperatorBase CreateResultOperator(ClauseGenerationContext clauseGenerationContext)
+        {
+            return new RemoveAllResultOperator();
+        }
+
+        /// <summary>
+        /// Gets the supported methods.
+        /// </summary>
+        public static IEnumerable<MethodInfo> GetSupportedMethods()
+        {
+            yield return RemoveAllMethodInfo;
+            yield return RemoveAllPredicateMethodInfo;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/d38ca8b1/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/Dml/RemoveAllResultOperator.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/Dml/RemoveAllResultOperator.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/Dml/RemoveAllResultOperator.cs
new file mode 100644
index 0000000..76789cb
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/Dml/RemoveAllResultOperator.cs
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Linq.Impl.Dml
+{
+    using System;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Linq;
+    using System.Linq.Expressions;
+    using Apache.Ignite.Core.Cache;
+    using Remotion.Linq.Clauses;
+    using Remotion.Linq.Clauses.ResultOperators;
+    using Remotion.Linq.Clauses.StreamedData;
+
+    /// <summary>
+    /// Represents an operator for <see cref="CacheLinqExtensions.RemoveAll{TK,TV}(IQueryable{ICacheEntry{TK,TV}})"/>.
+    /// </summary>
+    internal sealed class RemoveAllResultOperator : ValueFromSequenceResultOperatorBase
+    {
+        /** <inheritdoc /> */
+        public override IStreamedDataInfo GetOutputDataInfo(IStreamedDataInfo inputInfo)
+        {
+            return new StreamedScalarValueInfo(typeof(int));
+        }
+
+        /** <inheritdoc /> */
+        [ExcludeFromCodeCoverage]
+        public override ResultOperatorBase Clone(CloneContext cloneContext)
+        {
+            return new RemoveAllResultOperator();
+        }
+
+        /** <inheritdoc /> */
+        [ExcludeFromCodeCoverage]
+        public override void TransformExpressions(Func<Expression, Expression> transformation)
+        {
+            // No-op.
+        }
+
+        /** <inheritdoc /> */
+        [ExcludeFromCodeCoverage]
+        public override StreamedValue ExecuteInMemory<T>(StreamedSequence sequence)
+        {
+            throw new NotSupportedException("RemoveAll is not supported for in-memory sequences.");
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/d38ca8b1/modules/platforms/dotnet/Apache.Ignite.sln.DotSettings
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.sln.DotSettings b/modules/platforms/dotnet/Apache.Ignite.sln.DotSettings
index 078e9fb..9d5b728 100644
--- a/modules/platforms/dotnet/Apache.Ignite.sln.DotSettings
+++ b/modules/platforms/dotnet/Apache.Ignite.sln.DotSettings
@@ -7,4 +7,5 @@
 	<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AddImportsToDeepestScope/@EntryValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/QualifiedUsingAtNestedScope/@EntryValue">True</s:Boolean>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertClosureToMethodGroup/@EntryIndexedValue">DO_NOT_SHOW</s:String>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EXml_002ECodeStyle_002EFormatSettingsUpgrade_002EXmlMoveToCommonFormatterSettingsUpgrade/@EntryIndexedValue">True</s:Boolean>
 </wpf:ResourceDictionary>
\ No newline at end of file