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 14:32:24 UTC

[15/22] ignite git commit: IGNITE-5315 .NET: Fix LINQ, examples, and cache configuration to account for IGNITE-5287 (SqlEscapeAll)

IGNITE-5315 .NET: Fix LINQ, examples, and cache configuration to account for IGNITE-5287 (SqlEscapeAll)

This closes #2023


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

Branch: refs/heads/ignite-5075
Commit: f5bbc71d4c1cd1a01b08dbc5c5df892bd2f55316
Parents: e0b2053
Author: Pavel Tupitsyn <pt...@apache.org>
Authored: Mon May 29 15:53:37 2017 +0300
Committer: Pavel Tupitsyn <pt...@apache.org>
Committed: Mon May 29 15:53:37 2017 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Core.Tests.csproj             |   1 +
 .../Cache/CacheConfigurationTest.cs             |   6 +-
 .../Cache/Query/CacheLinqTest.cs                | 131 ++++++++++++++-----
 .../Cache/Query/CacheLinqTestSqlEscapeAll.cs    |  34 +++++
 .../Apache.Ignite.Core.csproj                   |   1 +
 .../Cache/Configuration/QueryEntity.cs          |  64 +++++++--
 .../Impl/Cache/IQueryEntityInternal.cs          |  31 +++++
 .../Impl/CacheFieldsQueryProvider.cs            |   9 ++
 .../Impl/CacheQueryExpressionVisitor.cs         |  76 ++++++++---
 .../Apache.Ignite.Linq/Impl/ExpressionWalker.cs |   7 +-
 10 files changed, 295 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/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 f27e774..974f858 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
@@ -102,6 +102,7 @@
     <Compile Include="Cache\Query\CacheDmlQueriesTest.cs" />
     <Compile Include="Cache\CacheAbstractTransactionalTest.cs" />
     <Compile Include="Cache\Query\CacheDmlQueriesTestSimpleName.cs" />
+    <Compile Include="Cache\Query\CacheLinqTestSqlEscapeAll.cs" />
     <Compile Include="Cache\Query\CacheLinqTestSimpleName.cs" />
     <Compile Include="Cache\Query\CacheQueriesTestSimpleName.cs" />
     <Compile Include="Cache\Query\Continuous\ContinuousQueryTest.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs
index cf70970..7935cc3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs
@@ -401,10 +401,11 @@ namespace Apache.Ignite.Core.Tests.Cache
                 return;
             }
 
-            Assert.AreEqual(x.Count, y.Count);
+            // Resulting configuration may include additional aliases.
+            Assert.LessOrEqual(x.Count, y.Count);
 
             for (var i = 0; i < x.Count; i++)
-                AssertConfigsAreEqual(x.ElementAt(i), y.ElementAt(i));
+                AssertConfigsAreEqual(x.ElementAt(i), y.FirstOrDefault(a => a.FullName == x.ElementAt(i).FullName));
         }
 
         /// <summary>
@@ -517,6 +518,7 @@ namespace Apache.Ignite.Core.Tests.Cache
                     {
                         KeyTypeName = "Integer",
                         ValueTypeName = "java.lang.String",
+                        TableName = "Table1",
                         Fields = new[]
                         {
                             new QueryField("length", typeof(int)), 

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/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 b603d75..04ce965 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
@@ -142,6 +142,14 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         }
 
         /// <summary>
+        /// Gets the SqlEscapeAll setting.
+        /// </summary>
+        protected virtual bool GetSqlEscapeAll()
+        {
+            return false;
+        }
+
+        /// <summary>
         /// Fixture tear down.
         /// </summary>
         [TestFixtureTearDown]
@@ -941,7 +949,10 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         public void TestNumerics()
         {
             var cache = Ignition.GetIgnite()
-                    .GetOrCreateCache<int, Numerics>(new CacheConfiguration("numerics", typeof (Numerics)));
+                    .GetOrCreateCache<int, Numerics>(new CacheConfiguration("numerics", typeof (Numerics))
+                {
+                    SqlEscapeAll = GetSqlEscapeAll()
+                });
 
             for (var i = 0; i < 100; i++)
                 cache[i] = new Numerics(((double) i - 50)/3);
@@ -1221,10 +1232,14 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         public void TestPrimitiveCache()
         {
             // Create partitioned cache
-            var cache =
-                Ignition.GetIgnite()
-                    .GetOrCreateCache<int, string>(new CacheConfiguration("primitiveCache",
-                        new QueryEntity(typeof (int), typeof (string))) {CacheMode = CacheMode.Replicated});
+            var cache = Ignition.GetIgnite()
+                .GetOrCreateCache<int, string>(
+                    new CacheConfiguration("primitiveCache",
+                        new QueryEntity(typeof(int), typeof(string)))
+                    {
+                        CacheMode = CacheMode.Replicated,
+                        SqlEscapeAll = GetSqlEscapeAll()
+                    });
 
             var qry = cache.AsCacheQueryable();
 
@@ -1246,7 +1261,10 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         {
             // Create partitioned cache
             var cache =
-                Ignition.GetIgnite().GetOrCreateCache<int, int>(new CacheConfiguration("partCache", typeof (int)));
+                Ignition.GetIgnite().GetOrCreateCache<int, int>(new CacheConfiguration("partCache", typeof (int))
+                {
+                    SqlEscapeAll = GetSqlEscapeAll()
+                });
 
             // Populate
             const int count = 100;
@@ -1284,8 +1302,13 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
             Assert.AreEqual(cache.Ignite, query.Ignite);
 
             var fq = query.GetFieldsQuery();
-            Assert.AreEqual("select _T0._key, _T0._val from \"person_org\".Person as _T0 where (_T0._key > ?)", 
+
+            Assert.AreEqual(
+                GetSqlEscapeAll()
+                    ? "select _T0._KEY, _T0._VAL from \"person_org\".\"Person\" as _T0 where (_T0.\"_KEY\" > ?)"
+                    : "select _T0._KEY, _T0._VAL from \"person_org\".Person as _T0 where (_T0._KEY > ?)",
                 fq.Sql);
+
             Assert.AreEqual(new[] {10}, fq.Arguments);
             Assert.IsTrue(fq.Local);
             Assert.AreEqual(PersonCount - 11, cache.QueryFields(fq).GetAll().Count);
@@ -1297,11 +1320,17 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
             Assert.AreEqual(TimeSpan.FromSeconds(2.5), fq.Timeout);
 
             var str = query.ToString();
-            Assert.AreEqual("CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
-                            "[Sql=select _T0._key, _T0._val from \"person_org\".Person as _T0 where " +
-                            "(_T0._key > ?), Arguments=[10], " +
-                            "Local=True, PageSize=999, EnableDistributedJoins=False, EnforceJoinOrder=True, " +
-                            "Timeout=00:00:02.5000000, ReplicatedOnly=True, Colocated=True]]", str);
+            Assert.AreEqual(GetSqlEscapeAll()
+                ? "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+                  "[Sql=select _T0._KEY, _T0._VAL from \"person_org\".\"Person\" as _T0 where " +
+                  "(_T0.\"_KEY\" > ?), Arguments=[10], " +
+                  "Local=True, PageSize=999, EnableDistributedJoins=False, EnforceJoinOrder=True, " +
+                  "Timeout=00:00:02.5000000, ReplicatedOnly=True, Colocated=True]]"
+                : "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+                  "[Sql=select _T0._KEY, _T0._VAL from \"person_org\".Person as _T0 where " +
+                  "(_T0._KEY > ?), Arguments=[10], " +
+                  "Local=True, PageSize=999, EnableDistributedJoins=False, EnforceJoinOrder=True, " +
+                  "Timeout=00:00:02.5000000, ReplicatedOnly=True, Colocated=True]]", str);
 
             // Check fields query
             var fieldsQuery = (ICacheQueryable) cache.AsCacheQueryable().Select(x => x.Value.Name);
@@ -1310,17 +1339,26 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
             Assert.AreEqual(cache.Ignite, fieldsQuery.Ignite);
 
             fq = fieldsQuery.GetFieldsQuery();
-            Assert.AreEqual("select _T0.Name from \"person_org\".Person as _T0", fq.Sql);
+            Assert.AreEqual(GetSqlEscapeAll()
+                    ? "select _T0.\"Name\" from \"person_org\".\"Person\" as _T0"
+                    : "select _T0.NAME from \"person_org\".Person as _T0",
+                fq.Sql);
+
             Assert.IsFalse(fq.Local);
             Assert.AreEqual(SqlFieldsQuery.DefaultPageSize, fq.PageSize);
             Assert.IsFalse(fq.EnableDistributedJoins);
             Assert.IsFalse(fq.EnforceJoinOrder);
 
             str = fieldsQuery.ToString();
-            Assert.AreEqual("CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
-                            "[Sql=select _T0.Name from \"person_org\".Person as _T0, Arguments=[], Local=False, " +
-                            "PageSize=1024, EnableDistributedJoins=False, EnforceJoinOrder=False, " +
-                            "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False]]", str);
+            Assert.AreEqual(GetSqlEscapeAll()
+                ? "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+                  "[Sql=select _T0.\"Name\" from \"person_org\".\"Person\" as _T0, Arguments=[], Local=False, " +
+                  "PageSize=1024, EnableDistributedJoins=False, EnforceJoinOrder=False, " +
+                  "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False]]"
+                : "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+                  "[Sql=select _T0.NAME from \"person_org\".Person as _T0, Arguments=[], Local=False, " +
+                  "PageSize=1024, EnableDistributedJoins=False, EnforceJoinOrder=False, " +
+                  "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False]]", str);
             
             // Check distributed joins flag propagation
             var distrQuery = cache.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true})
@@ -1331,12 +1369,19 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
             Assert.IsTrue(query.GetFieldsQuery().EnableDistributedJoins);
 
             str = distrQuery.ToString();
-            Assert.AreEqual("CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
-                            "[Sql=select _T0._key, _T0._val from \"person_org\".Person as _T0 where " +
-                            "(((_T0._key > ?) and (_T0.age1 > ?)) " +
-                            "and (_T0.Name like \'%\' || ? || \'%\') ), Arguments=[10, 20, x], Local=False, " +
-                            "PageSize=1024, EnableDistributedJoins=True, EnforceJoinOrder=False, " +
-                            "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False]]", str);
+            Assert.AreEqual(GetSqlEscapeAll()
+                ? "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+                  "[Sql=select _T0._KEY, _T0._VAL from \"person_org\".\"Person\" as _T0 where " +
+                  "(((_T0.\"_KEY\" > ?) and (_T0.\"age1\" > ?)) " +
+                  "and (_T0.\"Name\" like \'%\' || ? || \'%\') ), Arguments=[10, 20, x], Local=False, " +
+                  "PageSize=1024, EnableDistributedJoins=True, EnforceJoinOrder=False, " +
+                  "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False]]"
+                : "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+                  "[Sql=select _T0._KEY, _T0._VAL from \"person_org\".Person as _T0 where " +
+                  "(((_T0._KEY > ?) and (_T0.AGE1 > ?)) " +
+                  "and (_T0.NAME like \'%\' || ? || \'%\') ), Arguments=[10, 20, x], Local=False, " +
+                  "PageSize=1024, EnableDistributedJoins=True, EnforceJoinOrder=False, " +
+                  "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False]]", str);
         }
 
         /// <summary>
@@ -1377,12 +1422,18 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
 
             // Create and populate partitioned caches
             var personCache = ignite.CreateCache<int, Person>(new CacheConfiguration("partitioned_persons",
-                new QueryEntity(typeof(int), typeof(Person))));
+                new QueryEntity(typeof(int), typeof(Person)))
+            {
+                SqlEscapeAll = GetSqlEscapeAll()
+            });
 
             personCache.PutAll(GetSecondPersonCache().ToDictionary(x => x.Key, x => x.Value));
 
             var roleCache = ignite.CreateCache<int, Role>(new CacheConfiguration("partitioned_roles",
-                    new QueryEntity(typeof(int), typeof(Role))));
+                    new QueryEntity(typeof(int), typeof(Role)))
+            {
+                SqlEscapeAll = GetSqlEscapeAll()
+            });
 
             roleCache.PutAll(GetRoleCache().ToDictionary(x => x.Key.Foo, x => x.Value));
 
@@ -1432,7 +1483,10 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         {
             // Use new cache to avoid touching static data.
             var cache = Ignition.GetIgnite().CreateCache<int, Person>(new CacheConfiguration("deleteAllTest",
-                    new QueryEntity(typeof(int), typeof(Person))));
+                    new QueryEntity(typeof(int), typeof(Person)))
+            {
+                SqlEscapeAll = GetSqlEscapeAll()
+            });
 
             Enumerable.Range(1, 10).ToList().ForEach(x => cache.Put(x, new Person(x, x.ToString())));
             
@@ -1491,7 +1545,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         /// Gets the person cache.
         /// </summary>
         /// <returns></returns>
-        private static ICache<int, Person> GetPersonCache()
+        private ICache<int, Person> GetPersonCache()
         {
             return GetCacheOf<Person>();
         }
@@ -1500,7 +1554,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         /// Gets the org cache.
         /// </summary>
         /// <returns></returns>
-        private static ICache<int, Organization> GetOrgCache()
+        private ICache<int, Organization> GetOrgCache()
         {
             return GetCacheOf<Organization>();
         }
@@ -1508,7 +1562,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
         /// <summary>
         /// Gets the cache.
         /// </summary>
-        private static ICache<int, T> GetCacheOf<T>()
+        private ICache<int, T> GetCacheOf<T>()
         {
             return Ignition.GetIgnite()
                 .GetOrCreateCache<int, T>(new CacheConfiguration(PersonOrgCacheName,
@@ -1527,23 +1581,31 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
                             new QueryField("MyValue", typeof(T)),
                         }
                     },
-                    new QueryEntity(typeof (int), typeof (Organization))) {CacheMode = CacheMode.Replicated});
+                    new QueryEntity(typeof (int), typeof (Organization)))
+                {
+                    CacheMode = CacheMode.Replicated,
+                    SqlEscapeAll = GetSqlEscapeAll()
+                });
         }
 
         /// <summary>
         /// Gets the role cache.
         /// </summary>
-        private static ICache<RoleKey, Role> GetRoleCache()
+        private ICache<RoleKey, Role> GetRoleCache()
         {
             return Ignition.GetIgnite()
                 .GetOrCreateCache<RoleKey, Role>(new CacheConfiguration(RoleCacheName,
-                    new QueryEntity(typeof (RoleKey), typeof (Role))) {CacheMode = CacheMode.Replicated});
+                    new QueryEntity(typeof (RoleKey), typeof (Role)))
+                {
+                    CacheMode = CacheMode.Replicated,
+                    SqlEscapeAll = GetSqlEscapeAll()
+                });
         }
 
         /// <summary>
         /// Gets the second person cache.
         /// </summary>
-        private static ICache<int, Person> GetSecondPersonCache()
+        private ICache<int, Person> GetSecondPersonCache()
         {
             return Ignition.GetIgnite()
                 .GetOrCreateCache<int, Person>(
@@ -1553,7 +1615,8 @@ namespace Apache.Ignite.Core.Tests.Cache.Query
                             TableName = "CustomPersons"
                         })
                     {
-                        CacheMode = CacheMode.Replicated
+                        CacheMode = CacheMode.Replicated,
+                        SqlEscapeAll = GetSqlEscapeAll()
                     });
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSqlEscapeAll.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSqlEscapeAll.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSqlEscapeAll.cs
new file mode 100644
index 0000000..7473be9
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSqlEscapeAll.cs
@@ -0,0 +1,34 @@
+/*
+ * 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.Cache.Query
+{
+    using NUnit.Framework;
+
+    /// <summary>
+    /// LINQ test with simple name mapper.
+    /// </summary>
+    [TestFixture]
+    public class CacheLinqTestSqlEscapeAll : CacheLinqTest
+    {
+        /** <inheritdoc /> */
+        protected override bool GetSqlEscapeAll()
+        {
+            return true;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index 25b9603..9ce9dd2 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -198,6 +198,7 @@
     <Compile Include="Impl\Binary\ReflectionUtils.cs" />
     <Compile Include="Cache\Affinity\AffinityFunctionBase.cs" />
     <Compile Include="Impl\Binary\TypeNameParser.cs" />
+    <Compile Include="Impl\Cache\IQueryEntityInternal.cs" />
     <Compile Include="Impl\Cache\MemoryMetrics.cs" />
     <Compile Include="Impl\Cache\Store\CacheStore.cs" />
     <Compile Include="Impl\Cache\Store\ICacheStoreInternal.cs" />

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
index b6163ee..58e5af9 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs
@@ -27,13 +27,14 @@ namespace Apache.Ignite.Core.Cache.Configuration
     using System.Reflection;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Cache;
     using Apache.Ignite.Core.Log;
 
     /// <summary>
     /// Query entity is a description of cache entry (composed of key and value) 
     /// in a way of how it must be indexed and can be queried.
     /// </summary>
-    public class QueryEntity
+    public class QueryEntity : IQueryEntityInternal
     {
         /** */
         private Type _keyType;
@@ -47,6 +48,11 @@ namespace Apache.Ignite.Core.Cache.Configuration
         /** */
         private string _keyTypeName;
 
+        /** */
+        private Dictionary<string, string> _aliasMap;
+
+        private ICollection<QueryAlias> _aliases;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="QueryEntity"/> class.
         /// </summary>
@@ -180,7 +186,15 @@ namespace Apache.Ignite.Core.Cache.Configuration
         /// Example: {"parent.name" -> "parentName"}.
         /// </summary>
         [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
-        public ICollection<QueryAlias> Aliases { get; set; }
+        public ICollection<QueryAlias> Aliases
+        {
+            get { return _aliases; }
+            set
+            {
+                _aliases = value;
+                _aliasMap = null;
+            }
+        }
 
         /// <summary>
         /// Gets or sets the query indexes.
@@ -189,6 +203,32 @@ namespace Apache.Ignite.Core.Cache.Configuration
         public ICollection<QueryIndex> Indexes { get; set; }
 
         /// <summary>
+        /// Gets the alias by field name, or null when no match found.
+        /// This method constructs a dictionary lazily to perform lookups.
+        /// </summary>
+        string IQueryEntityInternal.GetAlias(string fieldName)
+        {
+            if (Aliases == null || Aliases.Count == 0)
+            {
+                return null;
+            }
+
+            // PERF: No ToDictionary.
+            if (_aliasMap == null)
+            {
+                _aliasMap = new Dictionary<string, string>(Aliases.Count, StringComparer.InvariantCulture);
+
+                foreach (var alias in Aliases)
+                {
+                    _aliasMap[alias.FullName] = alias.Alias;
+                }
+            }
+
+            string res;
+            return _aliasMap.TryGetValue(fieldName, out res) ? res : null;
+        }
+
+        /// <summary>
         /// Initializes a new instance of the <see cref="QueryEntity"/> class.
         /// </summary>
         /// <param name="reader">The reader.</param>
@@ -372,14 +412,17 @@ namespace Apache.Ignite.Core.Cache.Configuration
                 {
                     var columnName = attr.Name ?? memberInfo.Key.Name;
 
-                    // No dot notation for indexes
+                    // Dot notation is required for nested SQL fields.
+                    if (parentPropName != null)
+                    {
+                        columnName = parentPropName + "." + columnName;
+                    }
+
                     if (attr.IsIndexed)
+                    {
                         indexes.Add(new QueryIndexEx(columnName, attr.IsDescending, QueryIndexType.Sorted,
                             attr.IndexGroups));
-
-                    // Dot notation is required for nested SQL fields
-                    if (parentPropName != null)
-                        columnName = parentPropName + "." + columnName;
+                    }
 
                     fields.Add(new QueryField(columnName, memberInfo.Value) {IsKeyField = isKey});
 
@@ -390,11 +433,12 @@ namespace Apache.Ignite.Core.Cache.Configuration
                 {
                     var columnName = attr.Name ?? memberInfo.Key.Name;
 
-                    // No dot notation for FullText index names
-                    indexes.Add(new QueryIndexEx(columnName, false, QueryIndexType.FullText, null));
-
                     if (parentPropName != null)
+                    {
                         columnName = parentPropName + "." + columnName;
+                    }
+
+                    indexes.Add(new QueryIndexEx(columnName, false, QueryIndexType.FullText, null));
 
                     fields.Add(new QueryField(columnName, memberInfo.Value) {IsKeyField = isKey});
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/IQueryEntityInternal.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/IQueryEntityInternal.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/IQueryEntityInternal.cs
new file mode 100644
index 0000000..c312a52
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/IQueryEntityInternal.cs
@@ -0,0 +1,31 @@
+/*
+ * 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.Impl.Cache
+{
+    /// <summary>
+    /// Extended QueryEntity interface for internal needs.
+    /// </summary>
+    public interface IQueryEntityInternal
+    {
+        /// <summary>
+        /// Gets the alias by field name, or null when no match found.
+        /// This method constructs a dictionary lazily to perform lookups.
+        /// </summary>
+        string GetAlias(string fieldName);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/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 c665fe7..cce89fd 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs
@@ -217,6 +217,7 @@ namespace Apache.Ignite.Linq.Impl
                 return EscapeTableName(validTableNames[0]);
             }
 
+            // Try with full type name (this works when TableName is not set).
             var valueTypeName = cacheValueType.FullName;
 
             if (validTableNames.Contains(valueTypeName, StringComparer.OrdinalIgnoreCase))
@@ -224,6 +225,14 @@ namespace Apache.Ignite.Linq.Impl
                 return EscapeTableName(valueTypeName);
             }
 
+            // Remove namespace and nested class qualification and try again.
+            valueTypeName = EscapeTableName(valueTypeName);
+
+            if (validTableNames.Contains(valueTypeName, StringComparer.OrdinalIgnoreCase))
+            {
+                return valueTypeName;
+            }
+
             throw new CacheException(string.Format("Table name cannot be inferred for cache '{0}', " +
                                                    "please use AsCacheQueryable overload with tableName parameter. " +
                                                    "Valid table names: {1}", _cacheConfiguration.Name ?? "null",

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs
index 8fa0b5d..1b42aad 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryExpressionVisitor.cs
@@ -29,6 +29,7 @@ namespace Apache.Ignite.Linq.Impl
     using System.Reflection;
     using Apache.Ignite.Core.Cache;
     using Apache.Ignite.Core.Cache.Configuration;
+    using Apache.Ignite.Core.Impl.Cache;
     using Apache.Ignite.Core.Impl.Common;
     using Remotion.Linq;
     using Remotion.Linq.Clauses;
@@ -278,10 +279,10 @@ namespace Apache.Ignite.Linq.Impl
             // Count, sum, max, min expect a single field or *
             // In other cases we need both parts of cache entry
             var format = _includeAllFields
-                ? "{0}.*, {0}._key, {0}._val"
+                ? "{0}.*, {0}._KEY, {0}._VAL"
                 : _useStar
                     ? "{0}.*"
-                    : "{0}._key, {0}._val";
+                    : "{0}._KEY, {0}._VAL";
 
             var tableName = Aliases.GetTableAlias(expression);
 
@@ -308,7 +309,7 @@ namespace Apache.Ignite.Linq.Impl
 
             if (queryable != null)
             {
-                var fieldName = GetFieldName(expression, queryable);
+                var fieldName = GetEscapedFieldName(expression, queryable);
 
                 ResultBuilder.AppendFormat("{0}.{1}", Aliases.GetTableAlias(expression), fieldName);
             }
@@ -319,9 +320,21 @@ namespace Apache.Ignite.Linq.Impl
         }
 
         /// <summary>
-        /// Gets the name of the field from a member expression.
+        /// Gets the name of the field from a member expression, with quotes when necessary.
         /// </summary>
-        private static string GetFieldName(MemberExpression expression, ICacheQueryableInternal queryable)
+        private static string GetEscapedFieldName(MemberExpression expression, ICacheQueryableInternal queryable)
+        {
+            var sqlEscapeAll = queryable.CacheConfiguration.SqlEscapeAll;
+            var fieldName = GetFieldName(expression, queryable);
+
+            return sqlEscapeAll ? string.Format("\"{0}\"", fieldName) : fieldName;
+        }
+
+        /// <summary>
+        /// Gets the name of the field from a member expression, with quotes when necessary.
+        /// </summary>
+        private static string GetFieldName(MemberExpression expression, ICacheQueryableInternal queryable,
+            bool ignoreAlias = false)
         {
             var fieldName = GetMemberFieldName(expression.Member);
 
@@ -329,20 +342,18 @@ namespace Apache.Ignite.Linq.Impl
             var cacheCfg = queryable.CacheConfiguration;
 
             if (cacheCfg.QueryEntities == null || cacheCfg.QueryEntities.All(x => x.Aliases == null))
-                return fieldName;  // There are no aliases defined - early exit
+            {
+                // There are no aliases defined - early exit.
+                return fieldName;
+            }
 
             // Find query entity by key-val types
-            var keyValTypes = queryable.ElementType.GetGenericArguments();
-
-            Debug.Assert(keyValTypes.Length == 2);
-
-            var entity = cacheCfg.QueryEntities.FirstOrDefault(e =>
-                e.Aliases != null &&
-                (e.KeyType == keyValTypes[0] || e.KeyTypeName == keyValTypes[0].FullName) &&
-                (e.ValueType == keyValTypes[1] || e.ValueTypeName == keyValTypes[1].FullName));
+            var entity = GetQueryEntity(queryable, cacheCfg);
 
             if (entity == null)
+            {
                 return fieldName;
+            }
 
             // There are some aliases for the current query type
             // Calculate full field name and look for alias
@@ -351,15 +362,44 @@ namespace Apache.Ignite.Linq.Impl
 
             while ((member = member.Expression as MemberExpression) != null &&
                    member.Member.DeclaringType != queryable.ElementType)
-                fullFieldName = GetFieldName(member, queryable) + "." + fullFieldName;
+            {
+                fullFieldName = GetFieldName(member, queryable, true) + "." + fullFieldName;
+            }
 
-            var alias = entity.Aliases.Where(x => x.FullName == fullFieldName)
-                .Select(x => x.Alias).FirstOrDefault();
+            var alias = ignoreAlias ? null : ((IQueryEntityInternal)entity).GetAlias(fullFieldName);
 
             return alias ?? fieldName;
         }
 
         /// <summary>
+        /// Finds matching query entity in the cache configuration.
+        /// </summary>
+        private static QueryEntity GetQueryEntity(ICacheQueryableInternal queryable, CacheConfiguration cacheCfg)
+        {
+            if (cacheCfg.QueryEntities.Count == 1)
+            {
+                return cacheCfg.QueryEntities.Single();
+            }
+
+            var keyValTypes = queryable.ElementType.GetGenericArguments();
+
+            Debug.Assert(keyValTypes.Length == 2);
+
+            // PERF: No LINQ.
+            foreach (var e in cacheCfg.QueryEntities)
+            {
+                if (e.Aliases != null
+                    && (e.KeyType == keyValTypes[0] || e.KeyTypeName == keyValTypes[0].FullName)
+                    && (e.ValueType == keyValTypes[1] || e.ValueTypeName == keyValTypes[1].FullName))
+                {
+                    return e;
+                }
+            }
+            
+            return null;
+        }
+
+        /// <summary>
         /// Gets the name of the member field.
         /// </summary>
         [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", 
@@ -377,7 +417,7 @@ namespace Apache.Ignite.Linq.Impl
                 if (m.DeclaringType != null &&
                     m.DeclaringType.IsGenericType &&
                     m.DeclaringType.GetGenericTypeDefinition() == typeof (ICacheEntry<,>))
-                    return "_" + m.Name.ToLowerInvariant().Substring(0, 3);
+                    return "_" + m.Name.ToUpperInvariant().Substring(0, 3);
 
                 var qryFieldAttr = m.GetCustomAttributes(true)
                     .OfType<QuerySqlFieldAttribute>().FirstOrDefault();

http://git-wip-us.apache.org/repos/asf/ignite/blob/f5bbc71d/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs
index 4407f96..f00a13b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/ExpressionWalker.cs
@@ -176,7 +176,12 @@ namespace Apache.Ignite.Linq.Impl
         {
             Debug.Assert(queryable != null);
 
-            return string.Format("\"{0}\".{1}", queryable.CacheConfiguration.Name, queryable.TableName);
+            var cacheCfg = queryable.CacheConfiguration;
+
+            return string.Format(cacheCfg.SqlEscapeAll
+                    ? "\"{0}\".\"{1}\""
+                    : "\"{0}\".{1}",
+                cacheCfg.Name, queryable.TableName);
         }
     }
 }