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/12/05 07:31:17 UTC

[02/11] ignite git commit: IGNITE-6338 .NET: Thin client: LINQ

IGNITE-6338 .NET: Thin client: LINQ

This closes #3125


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

Branch: refs/heads/ignite-zk
Commit: 1f4337527ee2f75b90b46a297b5056064e78eb40
Parents: f08c9d3
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Mon Dec 4 11:14:32 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Mon Dec 4 11:14:32 2017 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.Tests.DotNetCore.csproj  |   2 +
 .../Apache.Ignite.Core.Tests.csproj             |   2 +
 .../Query/Linq/CacheLinqTest.Introspection.cs   |   8 +-
 .../Client/Cache/CreateCacheTest.cs             |   1 -
 .../Client/Cache/LinqTest.cs                    | 117 +++++++++++
 .../Client/Cache/SqlQueryTest.cs                |  43 +---
 .../Client/Cache/SqlQueryTestBase.cs            |  68 +++++++
 .../Client/RawSocketTest.cs                     |   1 -
 .../TestUtils.Windows.cs                        |   2 -
 .../Impl/Cache/ICacheInternal.cs                |   6 +
 .../Impl/Client/Cache/CacheClient.cs            |  64 +++++-
 .../Client/Cache/Query/ClientQueryCursorBase.cs |   4 +-
 .../Apache.Ignite.Linq.csproj                   |   3 +-
 .../CacheClientLinqExtensions.cs                | 131 ++++++++++++
 .../Apache.Ignite.Linq/CacheExtensions.cs       | 195 ------------------
 .../Apache.Ignite.Linq/CacheLinqExtensions.cs   | 197 +++++++++++++++++++
 .../Apache.Ignite.Linq/ICacheQueryable.cs       |   1 +
 .../Impl/CacheFieldsQueryProvider.cs            |   2 +-
 .../Apache.Ignite.Linq/Impl/CacheQueryable.cs   |   8 +-
 .../Impl/CacheQueryableBase.cs                  |   1 +
 .../dotnet/Apache.Ignite/IgniteRunner.cs        |   1 -
 21 files changed, 598 insertions(+), 259 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
index 5d735eb..8e4de7f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj
@@ -64,7 +64,9 @@
     <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\EmptyObject.cs" Link="ThinClient\Cache\EmptyObject.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\Person.cs" Link="ThinClient\Cache\Person.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\ScanQueryTest.cs" Link="ThinClient\Cache\ScanQueryTest.cs" />
+    <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\SqlQueryTestBase.cs" Link="ThinClient\Cache\SqlQueryTestBase.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\SqlQueryTest.cs" Link="ThinClient\Cache\SqlQueryTest.cs" />
+    <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\LinqTest.cs" Link="ThinClient\Cache\LinqTest.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientConnectionTest.cs" Link="ThinClient\ClientConnectionTest.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientTestBase.cs" Link="ThinClient\ClientTestBase.cs" />
     <Compile Include="..\Apache.Ignite.Core.Tests\Client\IgniteClientConfigurationTest.cs" Link="ThinClient\IgniteClientConfigurationTest.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
index 8bd8f28..77b2e6e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj
@@ -113,9 +113,11 @@
     <Compile Include="Client\Cache\ClientCacheConfigurationTest.cs" />
     <Compile Include="Client\Cache\EmptyObject.cs" />
     <Compile Include="Client\Cache\CreateCacheTest.cs" />
+    <Compile Include="Client\Cache\LinqTest.cs" />
     <Compile Include="Client\Cache\ScanQueryTest.cs" />
     <Compile Include="Client\Cache\Person.cs" />
     <Compile Include="Client\Cache\SqlQueryTest.cs" />
+    <Compile Include="Client\Cache\SqlQueryTestBase.cs" />
     <Compile Include="Client\ClientTestBase.cs" />
     <Compile Include="Client\RawSocketTest.cs" />
     <Compile Include="Client\ClientConnectionTest.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs
index a13131b..6e7483e 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs
@@ -58,7 +58,9 @@ namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
             }).Where(x => x.Key > 10).ToCacheQueryable();
 
             Assert.AreEqual(cache.Name, query.CacheName);
+#pragma warning disable 618 // Type or member is obsolete
             Assert.AreEqual(cache.Ignite, query.Ignite);
+#pragma warning restore 618 // Type or member is obsolete
 
             var fq = query.GetFieldsQuery();
 
@@ -93,10 +95,12 @@ namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
                   "Timeout=00:00:02.5000000, ReplicatedOnly=True, Colocated=True, Schema=, Lazy=True]]", str);
 
             // Check fields query
-            var fieldsQuery = (ICacheQueryable)cache.AsCacheQueryable().Select(x => x.Value.Name);
+            var fieldsQuery = cache.AsCacheQueryable().Select(x => x.Value.Name).ToCacheQueryable();
 
             Assert.AreEqual(cache.Name, fieldsQuery.CacheName);
-            Assert.AreEqual(cache.Ignite, fieldsQuery.Ignite);
+#pragma warning disable 618 // Type or member is obsolete
+            Assert.AreEqual(cache.Ignite, query.Ignite);
+#pragma warning restore 618 // Type or member is obsolete
 
             fq = fieldsQuery.GetFieldsQuery();
             Assert.AreEqual(GetSqlEscapeAll()

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
index 4489462..94ae6cd 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs
@@ -22,7 +22,6 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
     using Apache.Ignite.Core.Client;
     using Apache.Ignite.Core.Client.Cache;
     using Apache.Ignite.Core.Configuration;
-    using Apache.Ignite.Core.Impl.Client;
     using Apache.Ignite.Core.Tests.Cache;
     using NUnit.Framework;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/LinqTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/LinqTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/LinqTest.cs
new file mode 100644
index 0000000..e61f712
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/LinqTest.cs
@@ -0,0 +1,117 @@
+/*
+ * 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.Core.Tests.Client.Cache
+{
+    using System;
+    using System.Linq;
+    using Apache.Ignite.Linq;
+    using NUnit.Framework;
+
+    /// <summary>
+    /// Tests LINQ in thin client.
+    /// </summary>
+    public class LinqTest : SqlQueryTestBase
+    {
+        /// <summary>
+        /// Tests basic queries.
+        /// </summary>
+        [Test]
+        public void TestBasicQueries()
+        {
+            var cache = GetClientCache<Person>();
+
+            // All items.
+            var qry = cache.AsCacheQueryable();
+            Assert.AreEqual(Count, qry.Count());
+
+            // Filter.
+            qry = cache.AsCacheQueryable().Where(x => x.Value.Name.EndsWith("7"));
+            Assert.AreEqual(7, qry.Single().Key);
+            Assert.AreEqual("select _T0._KEY, _T0._VAL from \"cache\".PERSON as _T0 where (_T0.NAME like '%' || ?) ",
+                qry.ToCacheQueryable().GetFieldsQuery().Sql);
+
+            // DateTime.
+            var arg = DateTime.UtcNow.AddDays(Count - 1);
+            var qry2 = cache.AsCacheQueryable(false, "Person")
+                .Where(x => x.Value.DateTime > arg).Select(x => x.Key);
+            Assert.AreEqual(Count, qry2.Single());
+        }
+
+        /// <summary>
+        /// Tests joins.
+        /// </summary>
+        [Test]
+        public void TestJoins()
+        {
+            var cache1 = Client.GetCache<int, Person>(CacheName);
+            var cache2 = Client.GetCache<int, Person>(CacheName2);
+
+            // Non-distributed join returns incomplete results.
+            var persons1 = cache1.AsCacheQueryable(false);
+            var persons2 = cache2.AsCacheQueryable();
+
+            var qry = persons1
+                .Join(persons2, p1 => p1.Value.Id, p2 => Count + 1 - p2.Value.Id, (p1, p2) => p2.Value.Name);
+
+            Assert.Greater(Count, qry.ToArray().Length);
+
+
+            // Distributed join fixes the problem.
+            persons1 = cache1.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true});
+            persons2 = cache2.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true});
+
+            var qry2 =
+                from p1 in persons1
+                join p2 in persons2 on p1.Value.Id equals Count + 1 - p2.Value.Id
+                select p2.Value.DateTime;
+
+            Assert.AreEqual(Count, qry2.ToArray().Length);
+        }
+
+        /// <summary>
+        /// Tests DML via LINQ.
+        /// </summary>
+        [Test]
+        public void TestDml()
+        {
+            var cache = GetClientCache<Person>();
+
+            Assert.AreEqual(Count, cache.GetSize());
+
+            var res = cache.AsCacheQueryable().Where(x => x.Key % 3 == 0).RemoveAll();
+            Assert.AreEqual(Count / 3, res);
+
+            Assert.AreEqual(Count - res, cache.GetSize());
+        }
+
+        /// <summary>
+        /// Tests the compiled query.
+        /// </summary>
+        [Test]
+        public void TestCompiledQuery()
+        {
+            var cache = GetClientCache<Person>();
+            var persons = cache.AsCacheQueryable();
+
+            var qry = CompiledQuery.Compile((int id) => persons.Where(x => x.Value.Id == id));
+
+            Assert.AreEqual(1, qry(1).Single().Key);
+            Assert.AreEqual(3, qry(3).Single().Key);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs
index 720a71b..6f6df11 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs
@@ -19,7 +19,6 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
 {
     using System;
     using System.Linq;
-    using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Query;
     using Apache.Ignite.Core.Client;
     using NUnit.Framework;
@@ -27,36 +26,9 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
     /// <summary>
     /// Tests SQL queries via thin client.
     /// </summary>
-    public class SqlQueryTest : ClientTestBase
+    public class SqlQueryTest : SqlQueryTestBase
     {
         /// <summary>
-        /// Cache item count.
-        /// </summary>
-        private const int Count = 10;
-
-        /// <summary>
-        /// Second cache name.
-        /// </summary>
-        private const string CacheName2 = CacheName + "2";
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="ScanQueryTest"/> class.
-        /// </summary>
-        public SqlQueryTest() : base(2)
-        {
-            // No-op.
-        }
-
-        /// <summary>
-        /// Sets up the test.
-        /// </summary>
-        public override void TestSetUp()
-        {
-            InitCache(CacheName);
-            InitCache(CacheName2);
-        }
-
-        /// <summary>
         /// Tests the SQL query.
         /// </summary>
         [Test]
@@ -251,18 +223,5 @@ namespace Apache.Ignite.Core.Tests.Client.Cache
             Assert.AreEqual(1, res[0][0]);
             Assert.AreEqual("baz", cache[-10].Name);
         }
-
-        /// <summary>
-        /// Initializes the cache.
-        /// </summary>
-        private static void InitCache(string cacheName)
-        {
-            var cache = Ignition.GetIgnite().GetOrCreateCache<int, Person>(
-                new CacheConfiguration(cacheName, new QueryEntity(typeof(int), typeof(Person))));
-
-            cache.RemoveAll();
-
-            cache.PutAll(Enumerable.Range(1, Count).ToDictionary(x => x, x => new Person(x)));
-        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTestBase.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTestBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTestBase.cs
new file mode 100644
index 0000000..7efcb9c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTestBase.cs
@@ -0,0 +1,68 @@
+/*
+ * 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.Core.Tests.Client.Cache
+{
+    using System.Linq;
+    using Apache.Ignite.Core.Cache.Configuration;
+
+    /// <summary>
+    /// Base class for SQL tests.
+    /// </summary>
+    public class SqlQueryTestBase : ClientTestBase
+    {
+        /// <summary>
+        /// Cache item count.
+        /// </summary>
+        protected const int Count = 10;
+
+        /// <summary>
+        /// Second cache name.
+        /// </summary>
+        protected const string CacheName2 = CacheName + "2";
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScanQueryTest"/> class.
+        /// </summary>
+        public SqlQueryTestBase() : base(2)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Sets up the test.
+        /// </summary>
+        public override void TestSetUp()
+        {
+            InitCache(CacheName);
+            InitCache(CacheName2);
+        }
+
+        /// <summary>
+        /// Initializes the cache.
+        /// </summary>
+        private static void InitCache(string cacheName)
+        {
+            var cache = Ignition.GetIgnite().GetOrCreateCache<int, Person>(
+                new CacheConfiguration(cacheName, new QueryEntity(typeof(int), typeof(Person))));
+
+            cache.RemoveAll();
+
+            cache.PutAll(Enumerable.Range(1, Count).ToDictionary(x => x, x => new Person(x)));
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
index b088bb6..8ab110f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs
@@ -25,7 +25,6 @@ namespace Apache.Ignite.Core.Tests.Client
     using Apache.Ignite.Core.Impl;
     using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Binary.IO;
-    using Apache.Ignite.Core.Impl.Client;
     using NUnit.Framework;
 
     /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs
index 14b58f2..2169630 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs
@@ -20,10 +20,8 @@ namespace Apache.Ignite.Core.Tests
     using System;
     using System.Diagnostics;
     using System.Diagnostics.CodeAnalysis;
-    using System.Linq;
     using Apache.Ignite.Core.Configuration;
     using Apache.Ignite.Core.Impl;
-    using Apache.Ignite.Core.Impl.Binary;
     using Apache.Ignite.Core.Impl.Common;
     using Apache.Ignite.Core.Tests.Process;
     using NUnit.Framework;

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs
index 0349db8..1ec5341 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs
@@ -19,6 +19,7 @@ namespace Apache.Ignite.Core.Impl.Cache
 {
     using System;
     using Apache.Ignite.Core.Binary;
+    using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Query;
 
     /// <summary>
@@ -50,5 +51,10 @@ namespace Apache.Ignite.Core.Impl.Cache
         /// </returns>
         T DoOutInOpExtension<T>(int extensionId, int opCode, Action<IBinaryRawWriter> writeAction, 
             Func<IBinaryRawReader, T> readFunc);
+
+        /// <summary>
+        /// Gets the cache configuration.
+        /// </summary>
+        CacheConfiguration GetConfiguration();
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
index 45c0b0f..93829c2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs
@@ -20,9 +20,11 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
     using System;
     using System.Collections.Generic;
     using System.Diagnostics;
+    using System.Diagnostics.CodeAnalysis;
     using System.IO;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Cache;
+    using Apache.Ignite.Core.Cache.Configuration;
     using Apache.Ignite.Core.Cache.Query;
     using Apache.Ignite.Core.Client;
     using Apache.Ignite.Core.Client.Cache;
@@ -37,7 +39,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
     /// <summary>
     /// Client cache implementation.
     /// </summary>
-    internal sealed class CacheClient<TK, TV> : ICacheClient<TK, TV>
+    internal sealed class CacheClient<TK, TV> : ICacheClient<TK, TV>, ICacheInternal
     {
         /** Scan query filter platform code: .NET filter. */
         private const byte FilterPlatformDotnet = 2;
@@ -188,10 +190,17 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
             IgniteArgumentCheck.NotNull(sqlFieldsQuery, "sqlFieldsQuery");
             IgniteArgumentCheck.NotNull(sqlFieldsQuery.Sql, "sqlFieldsQuery.Sql");
 
-            return DoOutInOp(ClientOp.QuerySqlFields, w => WriteSqlFieldsQuery(w, sqlFieldsQuery),
-                s => new ClientFieldsQueryCursor(
-                    _ignite, s.ReadLong(), _keepBinary, s, ClientOp.QuerySqlFieldsCursorGetPage,
-                    ClientFieldsQueryCursor.ReadColumns(_marsh.StartUnmarshal(s))));
+            return DoOutInOp(ClientOp.QuerySqlFields,
+                w => WriteSqlFieldsQuery(w, sqlFieldsQuery),
+                s => GetFieldsCursor(s));
+        }
+
+        /** <inheritDoc /> */
+        public IQueryCursor<T> QueryFields<T>(SqlFieldsQuery sqlFieldsQuery, Func<IBinaryRawReader, int, T> readerFunc)
+        {
+            return DoOutInOp(ClientOp.QuerySqlFields, 
+                w => WriteSqlFieldsQuery(w, sqlFieldsQuery, false),
+                s => GetFieldsCursorNoColumnNames(s, readerFunc));
         }
 
         /** <inheritDoc /> */
@@ -361,6 +370,12 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
         }
 
         /** <inheritDoc /> */
+        CacheConfiguration ICacheInternal.GetConfiguration()
+        {
+            return GetConfiguration().ToCacheConfiguration();
+        }
+
+        /** <inheritDoc /> */
         public ICacheClient<TK1, TV1> WithKeepBinary<TK1, TV1>()
         {
             if (_keepBinary)
@@ -380,6 +395,15 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
             return new CacheClient<TK1, TV1>(_ignite, _name, true);
         }
 
+        /** <inheritDoc /> */
+        [ExcludeFromCodeCoverage]
+        public T DoOutInOpExtension<T>(int extensionId, int opCode, Action<IBinaryRawWriter> writeAction,
+            Func<IBinaryRawReader, T> readFunc)
+        {
+            // Should not be called, there are no usages for thin client.
+            throw IgniteClient.GetClientNotSupportedException();
+        }
+
         /// <summary>
         /// Does the out in op.
         /// </summary>
@@ -492,7 +516,8 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
         /// <summary>
         /// Writes the SQL fields query.
         /// </summary>
-        private static void WriteSqlFieldsQuery(IBinaryRawWriter writer, SqlFieldsQuery qry)
+        private static void WriteSqlFieldsQuery(IBinaryRawWriter writer, SqlFieldsQuery qry,
+            bool includeColumns = true)
         {
             Debug.Assert(qry != null);
 
@@ -513,10 +538,33 @@ namespace Apache.Ignite.Core.Impl.Client.Cache
             writer.WriteBoolean(qry.Colocated);
             writer.WriteBoolean(qry.Lazy);
             writer.WriteTimeSpanAsLong(qry.Timeout);
+            writer.WriteBoolean(includeColumns);
 
-            // Always include field names.
-            writer.WriteBoolean(true);
+        }
+
+        /// <summary>
+        /// Gets the fields cursor.
+        /// </summary>
+        private ClientFieldsQueryCursor GetFieldsCursor(IBinaryStream s)
+        {
+            var cursorId = s.ReadLong();
+            var columnNames = ClientFieldsQueryCursor.ReadColumns(_marsh.StartUnmarshal(s));
+
+            return new ClientFieldsQueryCursor(_ignite, cursorId, _keepBinary, s,
+                ClientOp.QuerySqlFieldsCursorGetPage, columnNames);
+        }
+
+        /// <summary>
+        /// Gets the fields cursor.
+        /// </summary>
+        private ClientQueryCursorBase<T> GetFieldsCursorNoColumnNames<T>(IBinaryStream s,
+            Func<IBinaryRawReader, int, T> readerFunc)
+        {
+            var cursorId = s.ReadLong();
+            var columnCount = s.ReadInt();
 
+            return new ClientQueryCursorBase<T>(_ignite, cursorId, _keepBinary, s,
+                ClientOp.QuerySqlFieldsCursorGetPage, r => readerFunc(r, columnCount));
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs
index 5123537..5a0a1f6 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs
@@ -26,7 +26,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache.Query
     /// <summary>
     /// Client query cursor base.
     /// </summary>
-    internal abstract class ClientQueryCursorBase<T> : QueryCursorBase<T>
+    internal class ClientQueryCursorBase<T> : QueryCursorBase<T>
     {
         /** Ignite. */
         private readonly IgniteClient _ignite;
@@ -46,7 +46,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache.Query
         /// <param name="initialBatchStream">Optional stream with initial batch.</param>
         /// <param name="getPageOp">The get page op.</param>
         /// <param name="readFunc">Read func.</param>
-        protected ClientQueryCursorBase(IgniteClient ignite, long cursorId, bool keepBinary, 
+        public ClientQueryCursorBase(IgniteClient ignite, long cursorId, bool keepBinary, 
             IBinaryStream initialBatchStream, ClientOp getPageOp, Func<BinaryReader, T> readFunc) 
             : base(ignite.Marshaller, keepBinary, readFunc, initialBatchStream)
         {

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/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 735e4f2..fc13914 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj
@@ -51,7 +51,8 @@
     <Reference Include="System.Core" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="CacheExtensions.cs" />
+    <Compile Include="CacheClientLinqExtensions.cs" />
+    <Compile Include="CacheLinqExtensions.cs" />
     <Compile Include="CompiledQuery.cs" />
     <Compile Include="ICacheQueryable.cs" />
     <Compile Include="Impl\AliasDictionary.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/CacheClientLinqExtensions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheClientLinqExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheClientLinqExtensions.cs
new file mode 100644
index 0000000..0c3544b
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheClientLinqExtensions.cs
@@ -0,0 +1,131 @@
+/*
+ * 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
+{
+    using System.Linq;
+    using Apache.Ignite.Core.Cache;
+    using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Cache.Query;
+    using Apache.Ignite.Core.Client.Cache;
+    using Apache.Ignite.Core.Impl.Cache;
+    using Apache.Ignite.Core.Impl.Common;
+    using Apache.Ignite.Linq.Impl;
+
+    /// <summary>
+    /// Extensions methods for <see cref="ICacheClient{TK,TV}"/>.
+    /// </summary>
+    public static class CacheClientLinqExtensions
+    {
+        /// <summary>
+        /// Gets an <see cref="IQueryable{T}"/> instance over this cache.
+        /// <para />
+        /// Resulting query will be translated to cache SQL query and executed over the cache instance 
+        /// via either <see cref="ICacheClient{TK,TV}.Query(SqlFieldsQuery)"/>.
+        /// <para />
+        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/>
+        /// for introspection, or converted with <see cref="CacheLinqExtensions.ToCacheQueryable{T}"/>
+        /// extension method.
+        /// </summary>
+        /// <typeparam name="TKey">The type of the key.</typeparam>
+        /// <typeparam name="TValue">The type of the value.</typeparam>
+        /// <param name="cache">The cache.</param>
+        /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns>
+        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
+            this ICacheClient<TKey, TValue> cache)
+        {
+            IgniteArgumentCheck.NotNull(cache, "cache");
+
+            return AsCacheQueryable(cache, false, null);
+        }
+
+        /// <summary>
+        /// Gets an <see cref="IQueryable{T}"/> instance over this cache.
+        /// <para />
+        /// Resulting query will be translated to cache SQL query and executed over the cache instance 
+        /// via either <see cref="ICacheClient{TK,TV}.Query(SqlFieldsQuery)"/>.
+        /// <para />
+        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> for introspection.
+        /// </summary>
+        /// <typeparam name="TKey">The type of the key.</typeparam>
+        /// <typeparam name="TValue">The type of the value.</typeparam>
+        /// <param name="cache">The cache.</param>
+        /// <param name="local">Local flag. When set query will be executed only on local node, so only local 
+        /// entries will be returned as query result.</param>
+        /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns>
+        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
+            this ICacheClient<TKey, TValue> cache, bool local)
+        {
+            IgniteArgumentCheck.NotNull(cache, "cache");
+
+            return AsCacheQueryable(cache, local, null);
+        }
+
+        /// <summary>
+        /// Gets an <see cref="IQueryable{T}" /> instance over this cache.
+        /// <para />
+        /// Resulting query will be translated to cache SQL query and executed over the cache instance 
+        /// via either <see cref="ICacheClient{TK,TV}.Query(SqlFieldsQuery)"/>.
+        /// <para />
+        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection.
+        /// </summary>
+        /// <typeparam name="TKey">The type of the key.</typeparam>
+        /// <typeparam name="TValue">The type of the value.</typeparam>
+        /// <param name="cache">The cache.</param>
+        /// <param name="local">Local flag. When set query will be executed only on local node, so only local 
+        /// entries will be returned as query result.</param>
+        /// <param name="tableName">
+        /// Name of the table.
+        /// <para />
+        /// Table name is equal to short class name of a cache value.
+        /// When a cache has only one type of values, or only one <see cref="QueryEntity"/> defined, 
+        /// table name will be inferred and can be omitted.
+        /// </param>
+        /// <returns><see cref="IQueryable{T}" /> instance over this cache.</returns>
+        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
+            this ICacheClient<TKey, TValue> cache, bool local, string tableName)
+        {
+            IgniteArgumentCheck.NotNull(cache, "cache");
+
+            return AsCacheQueryable(cache, new QueryOptions {Local = local, TableName = tableName});
+        }
+
+        /// <summary>
+        /// Gets an <see cref="IQueryable{T}" /> instance over this cache.
+        /// <para />
+        /// Resulting query will be translated to cache SQL query and executed over the cache instance 
+        /// via either <see cref="ICacheClient{TK,TV}.Query(SqlFieldsQuery)"/>.
+        /// <para />
+        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection.
+        /// </summary>
+        /// <typeparam name="TKey">The type of the key.</typeparam>
+        /// <typeparam name="TValue">The type of the value.</typeparam>
+        /// <param name="cache">The cache.</param>
+        /// <param name="queryOptions">The query options.</param>
+        /// <returns>
+        ///   <see cref="IQueryable{T}" /> instance over this cache.
+        /// </returns>
+        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
+            this ICacheClient<TKey, TValue> cache, QueryOptions queryOptions)
+        {
+            IgniteArgumentCheck.NotNull(cache, "cache");
+            IgniteArgumentCheck.NotNull(queryOptions, "queryOptions");
+
+            return new CacheQueryable<TKey, TValue>((ICacheInternal) cache, queryOptions);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/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
deleted file mode 100644
index f759dbb..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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
-{
-    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}"/>.
-    /// </summary>
-    public static class CacheLinqExtensions
-    {
-        /// <summary>
-        /// Gets an <see cref="IQueryable{T}"/> instance over this cache.
-        /// <para />
-        /// Resulting query will be translated to cache SQL query and executed over the cache instance 
-        /// via either <see cref="ICache{TK,TV}.Query"/> or <see cref="ICache{TK,TV}.QueryFields"/>,
-        /// depending on requested result. 
-        /// <para />
-        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> for introspection.
-        /// </summary>
-        /// <typeparam name="TKey">The type of the key.</typeparam>
-        /// <typeparam name="TValue">The type of the value.</typeparam>
-        /// <param name="cache">The cache.</param>
-        /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns>
-        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
-            this ICache<TKey, TValue> cache)
-        {
-            IgniteArgumentCheck.NotNull(cache, "cache");
-
-            return cache.AsCacheQueryable(false, null);
-        }
-
-        /// <summary>
-        /// Gets an <see cref="IQueryable{T}"/> instance over this cache.
-        /// <para />
-        /// Resulting query will be translated to cache SQL query and executed over the cache instance 
-        /// via either <see cref="ICache{TK,TV}.Query"/> or <see cref="ICache{TK,TV}.QueryFields"/>,
-        /// depending on requested result. 
-        /// <para />
-        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> for introspection.
-        /// </summary>
-        /// <typeparam name="TKey">The type of the key.</typeparam>
-        /// <typeparam name="TValue">The type of the value.</typeparam>
-        /// <param name="cache">The cache.</param>
-        /// <param name="local">Local flag. When set query will be executed only on local node, so only local 
-        /// entries will be returned as query result.</param>
-        /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns>
-        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
-            this ICache<TKey, TValue> cache, bool local)
-        {
-            IgniteArgumentCheck.NotNull(cache, "cache");
-
-            return cache.AsCacheQueryable(local, null);
-        }
-
-        /// <summary>
-        /// Gets an <see cref="IQueryable{T}" /> instance over this cache.
-        /// <para />
-        /// Resulting query will be translated to cache SQL query and executed over the cache instance
-        /// via either <see cref="ICache{TK,TV}.Query" /> or <see cref="ICache{TK,TV}.QueryFields" />,
-        /// depending on requested result.
-        /// <para />
-        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection.
-        /// </summary>
-        /// <typeparam name="TKey">The type of the key.</typeparam>
-        /// <typeparam name="TValue">The type of the value.</typeparam>
-        /// <param name="cache">The cache.</param>
-        /// <param name="local">Local flag. When set query will be executed only on local node, so only local 
-        /// entries will be returned as query result.</param>
-        /// <param name="tableName">
-        /// Name of the table.
-        /// <para />
-        /// Table name is equal to short class name of a cache value.
-        /// When a cache has only one type of values, or only one <see cref="QueryEntity"/> defined, 
-        /// table name will be inferred and can be omitted.
-        /// </param>
-        /// <returns><see cref="IQueryable{T}" /> instance over this cache.</returns>
-        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
-            this ICache<TKey, TValue> cache, bool local, string tableName)
-        {
-            IgniteArgumentCheck.NotNull(cache, "cache");
-
-            return cache.AsCacheQueryable(new QueryOptions {Local = local, TableName = tableName});
-        }
-
-        /// <summary>
-        /// Gets an <see cref="IQueryable{T}" /> instance over this cache.
-        /// <para />
-        /// Resulting query will be translated to cache SQL query and executed over the cache instance
-        /// via either <see cref="ICache{TK,TV}.Query" /> or <see cref="ICache{TK,TV}.QueryFields" />,
-        /// depending on requested result.
-        /// <para />
-        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection.
-        /// </summary>
-        /// <typeparam name="TKey">The type of the key.</typeparam>
-        /// <typeparam name="TValue">The type of the value.</typeparam>
-        /// <param name="cache">The cache.</param>
-        /// <param name="queryOptions">The query options.</param>
-        /// <returns>
-        ///   <see cref="IQueryable{T}" /> instance over this cache.
-        /// </returns>
-        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
-            this ICache<TKey, TValue> cache, QueryOptions queryOptions)
-        {
-            IgniteArgumentCheck.NotNull(cache, "cache");
-            IgniteArgumentCheck.NotNull(queryOptions, "queryOptions");
-
-            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/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/CacheLinqExtensions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheLinqExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheLinqExtensions.cs
new file mode 100644
index 0000000..940b23b
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheLinqExtensions.cs
@@ -0,0 +1,197 @@
+/*
+ * 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
+{
+    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.Cache;
+    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}"/>.
+    /// </summary>
+    public static class CacheLinqExtensions
+    {
+        /// <summary>
+        /// Gets an <see cref="IQueryable{T}"/> instance over this cache.
+        /// <para />
+        /// Resulting query will be translated to cache SQL query and executed over the cache instance 
+        /// via either <see cref="ICache{TK,TV}.Query"/> or <see cref="ICache{TK,TV}.QueryFields"/>,
+        /// depending on requested result. 
+        /// <para />
+        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/>
+        /// for introspection, or converted with <see cref="ToCacheQueryable{T}"/> extension method.
+        /// </summary>
+        /// <typeparam name="TKey">The type of the key.</typeparam>
+        /// <typeparam name="TValue">The type of the value.</typeparam>
+        /// <param name="cache">The cache.</param>
+        /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns>
+        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
+            this ICache<TKey, TValue> cache)
+        {
+            IgniteArgumentCheck.NotNull(cache, "cache");
+
+            return cache.AsCacheQueryable(false, null);
+        }
+
+        /// <summary>
+        /// Gets an <see cref="IQueryable{T}"/> instance over this cache.
+        /// <para />
+        /// Resulting query will be translated to cache SQL query and executed over the cache instance 
+        /// via either <see cref="ICache{TK,TV}.Query"/> or <see cref="ICache{TK,TV}.QueryFields"/>,
+        /// depending on requested result. 
+        /// <para />
+        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> for introspection.
+        /// </summary>
+        /// <typeparam name="TKey">The type of the key.</typeparam>
+        /// <typeparam name="TValue">The type of the value.</typeparam>
+        /// <param name="cache">The cache.</param>
+        /// <param name="local">Local flag. When set query will be executed only on local node, so only local 
+        /// entries will be returned as query result.</param>
+        /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns>
+        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
+            this ICache<TKey, TValue> cache, bool local)
+        {
+            IgniteArgumentCheck.NotNull(cache, "cache");
+
+            return cache.AsCacheQueryable(local, null);
+        }
+
+        /// <summary>
+        /// Gets an <see cref="IQueryable{T}" /> instance over this cache.
+        /// <para />
+        /// Resulting query will be translated to cache SQL query and executed over the cache instance
+        /// via either <see cref="ICache{TK,TV}.Query" /> or <see cref="ICache{TK,TV}.QueryFields" />,
+        /// depending on requested result.
+        /// <para />
+        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection.
+        /// </summary>
+        /// <typeparam name="TKey">The type of the key.</typeparam>
+        /// <typeparam name="TValue">The type of the value.</typeparam>
+        /// <param name="cache">The cache.</param>
+        /// <param name="local">Local flag. When set query will be executed only on local node, so only local 
+        /// entries will be returned as query result.</param>
+        /// <param name="tableName">
+        /// Name of the table.
+        /// <para />
+        /// Table name is equal to short class name of a cache value.
+        /// When a cache has only one type of values, or only one <see cref="QueryEntity"/> defined, 
+        /// table name will be inferred and can be omitted.
+        /// </param>
+        /// <returns><see cref="IQueryable{T}" /> instance over this cache.</returns>
+        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
+            this ICache<TKey, TValue> cache, bool local, string tableName)
+        {
+            IgniteArgumentCheck.NotNull(cache, "cache");
+
+            return cache.AsCacheQueryable(new QueryOptions {Local = local, TableName = tableName});
+        }
+
+        /// <summary>
+        /// Gets an <see cref="IQueryable{T}" /> instance over this cache.
+        /// <para />
+        /// Resulting query will be translated to cache SQL query and executed over the cache instance
+        /// via either <see cref="ICache{TK,TV}.Query" /> or <see cref="ICache{TK,TV}.QueryFields" />,
+        /// depending on requested result.
+        /// <para />
+        /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection.
+        /// </summary>
+        /// <typeparam name="TKey">The type of the key.</typeparam>
+        /// <typeparam name="TValue">The type of the value.</typeparam>
+        /// <param name="cache">The cache.</param>
+        /// <param name="queryOptions">The query options.</param>
+        /// <returns>
+        ///   <see cref="IQueryable{T}" /> instance over this cache.
+        /// </returns>
+        public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>(
+            this ICache<TKey, TValue> cache, QueryOptions queryOptions)
+        {
+            IgniteArgumentCheck.NotNull(cache, "cache");
+            IgniteArgumentCheck.NotNull(queryOptions, "queryOptions");
+
+            return new CacheQueryable<TKey, TValue>((ICacheInternal) cache, queryOptions, cache.Ignite);
+        }
+
+        /// <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/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs
index ef641e2..426d52c 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs
@@ -37,6 +37,7 @@ namespace Apache.Ignite.Linq
         /// <summary>
         /// Gets the Ignite instance associated with this query.
         /// </summary>
+        [Obsolete("Deprecated, null for thin client.")]
         IIgnite Ignite { get; }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs
index cce89fd..4f35a42 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs
@@ -63,7 +63,6 @@ namespace Apache.Ignite.Linq.Impl
         {
             Debug.Assert(queryParser != null);
             Debug.Assert(executor != null);
-            Debug.Assert(ignite != null);
             Debug.Assert(cacheConfiguration != null);
             Debug.Assert(cacheValueType != null);
 
@@ -85,6 +84,7 @@ namespace Apache.Ignite.Linq.Impl
         /// <summary>
         /// Gets the ignite.
         /// </summary>
+        [Obsolete("Deprecated, null for thin client, only used for ICacheQueryable.")]
         public IIgnite Ignite
         {
             get { return _ignite; }

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs
index e271363..5148020 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs
@@ -18,6 +18,7 @@
 namespace Apache.Ignite.Linq.Impl
 {
     using System.Linq;
+    using Apache.Ignite.Core;
     using Apache.Ignite.Core.Cache;
     using Apache.Ignite.Core.Impl.Cache;
 
@@ -31,10 +32,11 @@ namespace Apache.Ignite.Linq.Impl
         /// </summary>
         /// <param name="cache">The cache.</param>
         /// <param name="queryOptions">The query options.</param>
-        public CacheQueryable(ICache<TKey, TValue> cache, QueryOptions queryOptions)
+        /// <param name="ignite">The ignite.</param>
+        public CacheQueryable(ICacheInternal cache, QueryOptions queryOptions, IIgnite ignite = null)
             : base(new CacheFieldsQueryProvider(CacheQueryParser.Instance,
-                new CacheFieldsQueryExecutor((ICacheInternal) cache, queryOptions), 
-                cache.Ignite, cache.GetConfiguration(), queryOptions.TableName, typeof(TValue)))
+                new CacheFieldsQueryExecutor(cache, queryOptions), 
+                ignite, cache.GetConfiguration(), queryOptions.TableName, typeof(TValue)))
         {
             // No-op.
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs
index 5702f4f..c585119 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs
@@ -55,6 +55,7 @@ namespace Apache.Ignite.Linq.Impl
         }
 
         /** <inheritdoc /> */
+        [Obsolete("Deprecated, null for thin client.")]
         public IIgnite Ignite
         {
             get { return CacheQueryProvider.Ignite; }

http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs b/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs
index 6d8aa6b..c6660c3 100644
--- a/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs
@@ -25,7 +25,6 @@ namespace Apache.Ignite
     using System.Threading;
     using Apache.Ignite.Config;
     using Apache.Ignite.Core;
-    using Apache.Ignite.Core.Impl;
     using Apache.Ignite.Service;
 
     /// <summary>