You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2017/05/29 12:53:54 UTC
ignite git commit: IGNITE-5315 .NET: Fix LINQ, examples,
and cache configuration to account for IGNITE-5287 (SqlEscapeAll)
Repository: ignite
Updated Branches:
refs/heads/master e0b2053e6 -> f5bbc71d4
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/master
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);
}
}
}