IGNITE-6704 .NET: CacheConfiguration.KeyConfiguration This closes #2916
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/5b3ad97b Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/5b3ad97b Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/5b3ad97b Branch: refs/heads/ignite-5937 Commit: 5b3ad97b939bee6f3e272f93c75e920208cb7491 Parents: 1aab9d8 Author: Pavel Tupitsyn <[email protected]> Authored: Tue Oct 24 16:45:57 2017 +0300 Committer: Pavel Tupitsyn <[email protected]> Committed: Tue Oct 24 16:45:57 2017 +0300 ---------------------------------------------------------------------- .../utils/PlatformConfigurationUtils.java | 26 ++++ .../Apache.Ignite.Core.Tests.csproj | 1 + .../ApiParity/CacheConfigurationParityTest.cs | 2 - .../Cache/Affinity/AffinityAttributeTest.cs | 135 +++++++++++++++++++ .../Cache/Affinity/AffinityFieldTest.cs | 35 ++++- .../Cache/CacheConfigurationTest.cs | 12 +- .../Config/full-config.xml | 3 + .../IgniteConfigurationSerializerTest.cs | 13 +- .../Apache.Ignite.Core.Tests/TestUtils.cs | 49 ++++--- .../Apache.Ignite.Core.csproj | 2 + .../Affinity/AffinityKeyMappedAttribute.cs | 26 +++- .../Cache/Configuration/CacheConfiguration.cs | 44 +++--- .../Configuration/CacheKeyConfiguration.cs | 84 ++++++++++++ .../Cache/Configuration/QueryEntity.cs | 34 +---- .../Apache.Ignite.Core/IgniteConfiguration.cs | 17 +-- .../IgniteConfigurationSection.xsd | 26 ++++ .../Impl/Binary/BinaryReaderExtensions.cs | 27 ++++ .../Impl/Binary/BinaryUtils.cs | 2 + .../Impl/Binary/BinaryWriterExtensions.cs | 29 ++++ .../Impl/Binary/IBinaryRawWriteAware.cs | 42 ++++++ .../Impl/Binary/Marshaller.cs | 23 +--- .../Impl/Binary/ReflectionUtils.cs | 27 ++++ 22 files changed, 542 insertions(+), 117 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java index 9711e62..981a231 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java @@ -39,6 +39,7 @@ import org.apache.ignite.binary.BinaryBasicNameMapper; import org.apache.ignite.binary.BinaryRawReader; import org.apache.ignite.binary.BinaryRawWriter; import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.CacheKeyConfiguration; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cache.CacheRebalanceMode; import org.apache.ignite.cache.CacheWriteSynchronizationMode; @@ -223,6 +224,18 @@ public class PlatformConfigurationUtils { ccfg.setAffinity(readAffinityFunction(in)); ccfg.setExpiryPolicyFactory(readExpiryPolicyFactory(in)); + int keyCnt = in.readInt(); + + if (keyCnt > 0) { + CacheKeyConfiguration[] keys = new CacheKeyConfiguration[keyCnt]; + + for (int i = 0; i < keyCnt; i++) { + keys[i] = new CacheKeyConfiguration(in.readString(), in.readString()); + } + + ccfg.setKeyConfiguration(keys); + } + int pluginCnt = in.readInt(); if (pluginCnt > 0) { @@ -916,6 +929,19 @@ public class PlatformConfigurationUtils { writeAffinityFunction(writer, ccfg.getAffinity()); writeExpiryPolicyFactory(writer, ccfg.getExpiryPolicyFactory()); + CacheKeyConfiguration[] keys = ccfg.getKeyConfiguration(); + + if (keys != null) { + writer.writeInt(keys.length); + + for (CacheKeyConfiguration key : keys) { + writer.writeString(key.getTypeName()); + writer.writeString(key.getAffinityKeyFieldName()); + } + } else { + writer.writeInt(0); + } + CachePluginConfiguration[] plugins = ccfg.getPluginConfigurations(); if (plugins != null) { int cnt = 0; http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/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 7e1753c..e7302bb 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 @@ -86,6 +86,7 @@ <Compile Include="Binary\BinarySelfTestSimpleName.cs" /> <Compile Include="Binary\EnumsTestOnline.cs" /> <Compile Include="Binary\Serializable\GenericCollectionsTest.cs" /> + <Compile Include="Cache\Affinity\AffinityAttributeTest.cs" /> <Compile Include="Cache\DataRegionMetricsTest.cs" /> <Compile Include="Cache\DataStorageMetricsTest.cs" /> <Compile Include="Cache\PersistenceTest.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs index 617eb83..6bc5472 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/CacheConfigurationParityTest.cs @@ -58,8 +58,6 @@ namespace Apache.Ignite.Core.Tests.ApiParity { "NodeFilter", // IGNITE-2890 - "KeyConfiguration", // IGNITE-6704 - // IGNITE-6705 "IsOnheapCacheEnabled", "StoreConcurrentLoadAllThreshold", http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityAttributeTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityAttributeTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityAttributeTest.cs new file mode 100644 index 0000000..d99501a --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityAttributeTest.cs @@ -0,0 +1,135 @@ +/* + * 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. + */ + +#pragma warning disable 169 +#pragma warning disable 649 +namespace Apache.Ignite.Core.Tests.Cache.Affinity +{ + using System.Diagnostics.CodeAnalysis; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache.Affinity; + using NUnit.Framework; + + /// <summary> + /// Tests the <see cref="AffinityKeyMappedAttribute"/>. + /// </summary> + [SuppressMessage("ReSharper", "UnusedMember.Local")] + public class AffinityAttributeTest + { + /// <summary> + /// Tests the property attribute. + /// </summary> + [Test] + public void TestPropertyAttribute() + { + Assert.IsNull(AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(NoAttr))); + Assert.AreEqual("Abc", AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(PublicProperty))); + Assert.AreEqual("Abc", AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(InheritPublicProperty))); + Assert.AreEqual("Abc", AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(PrivateProperty))); + Assert.AreEqual("Abc", AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(InheritPrivateProperty))); + } + + /// <summary> + /// Tests the field attribute. + /// </summary> + [Test] + public void TestFieldAttribute() + { + Assert.AreEqual("Abc", AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(PublicField))); + Assert.AreEqual("_abc", AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(PrivateField))); + Assert.AreEqual("Abc", AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(InheritPublicField))); + Assert.AreEqual("_abc", AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(InheritPrivateField))); + } + + /// <summary> + /// Tests multiple attributes per class. + /// </summary> + [Test] + public void TestMultipleAttributes() + { + var ex = Assert.Throws<BinaryObjectException>(() => + AffinityKeyMappedAttribute.GetFieldNameFromAttribute(typeof(MultipleAttributes))); + + Assert.AreEqual(string.Format( + "Multiple 'AffinityKeyMappedAttribute' attributes found on type '{0}'. There can be only one " + + "affinity field.", typeof(MultipleAttributes).FullName), ex.Message); + } + + private class NoAttr + { + public string Abc { get; set; } + } + + private class PublicProperty + { + public string Foo { get; set; } + + [AffinityKeyMapped] + public string Abc { get; set; } + } + + private class PrivateProperty + { + private string Foo { get; set; } + + [AffinityKeyMapped] + private string Abc { get; set; } + } + + private class PublicField + { + public string Foo; + + [AffinityKeyMapped] + public string Abc; + } + + private class PrivateField + { + private string _foo; + + [AffinityKeyMapped] + private string _abc; + } + + private class InheritPublicProperty : PublicProperty + { + // No-op. + } + + private class InheritPrivateProperty : PrivateProperty + { + // No-op. + } + + private class InheritPublicField : PublicField + { + // No-op. + } + + private class InheritPrivateField : PrivateField + { + // No-op. + } + + private class MultipleAttributes : PublicProperty + { + [AffinityKeyMapped] + public int Baz { get; set; } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs index c3482bb..d10f1a1 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Affinity/AffinityFieldTest.cs @@ -20,6 +20,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Linq; using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Cache; @@ -50,7 +51,12 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity _cache1 = grid1.CreateCache<object, string>(new CacheConfiguration("default") { - CacheMode = CacheMode.Partitioned + CacheMode = CacheMode.Partitioned, + KeyConfiguration = new[] + { + new CacheKeyConfiguration(typeof(CacheKey2)) {AffinityKeyFieldName = "AffinityKey"}, + new CacheKeyConfiguration{TypeName = "Baz", AffinityKeyFieldName = "Bar"} + } }); _cache2 = grid2.GetCache<object, string>("default"); } @@ -74,6 +80,7 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity _cache1.Put(new CacheKey(), string.Empty); _cache1.Put(new CacheKeyAttr(), string.Empty); _cache1.Put(new CacheKeyAttrOverride(), string.Empty); + _cache1.Put(new CacheKey2(), string.Empty); // Verify foreach (var type in new[] { typeof(CacheKey), typeof(CacheKeyAttr), @@ -85,6 +92,25 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity } /// <summary> + /// Tests the cache configuration. + /// </summary> + [Test] + public void TestConfiguration() + { + var cfg = _cache1.GetConfiguration(); + var keys = cfg.KeyConfiguration; + + Assert.IsNotNull(keys); + Assert.AreEqual(2, keys.Count); + + Assert.AreEqual(typeof(CacheKey2).FullName, keys.First().TypeName); + Assert.AreEqual("AffinityKey", keys.First().AffinityKeyFieldName); + + Assert.AreEqual("Baz", keys.Last().TypeName); + Assert.AreEqual("Bar", keys.Last().AffinityKeyFieldName); + } + + /// <summary> /// Tests that keys are located properly in cache partitions. /// </summary> [Test] @@ -203,5 +229,12 @@ namespace Apache.Ignite.Core.Tests.Cache.Affinity [AffinityKeyMapped] public int Key { get; set; } public int AffinityKey { get; set; } } + + [SuppressMessage("ReSharper", "UnusedMember.Local")] + private class CacheKey2 + { + public int Key { get; set; } + public int AffinityKey2 { get; set; } + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/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 4f13172..5556807 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheConfigurationTest.cs @@ -329,6 +329,8 @@ namespace Apache.Ignite.Core.Tests.Cache Assert.AreEqual(x.PluginConfigurations.Select(p => p.GetType()), y.PluginConfigurations.Select(p => p.GetType())); } + + TestUtils.AssertReflectionEqual(x.KeyConfiguration, y.KeyConfiguration); } /// <summary> @@ -635,7 +637,15 @@ namespace Apache.Ignite.Core.Tests.Cache #pragma warning restore 618 PartitionLossPolicy = PartitionLossPolicy.ReadOnlySafe, PluginConfigurations = new[] { new MyPluginConfiguration() }, - SqlIndexMaxInlineSize = 10000 + SqlIndexMaxInlineSize = 10000, + KeyConfiguration = new[] + { + new CacheKeyConfiguration + { + TypeName = "foobar", + AffinityKeyFieldName = "barbaz" + } + } }; } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml index 1e17752..7ad5d48 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Config/full-config.xml @@ -78,6 +78,9 @@ <pluginConfigurations> <iCachePluginConfiguration type='Apache.Ignite.Core.Tests.IgniteConfigurationSerializerTest+MyPluginConfiguration, Apache.Ignite.Core.Tests' /> </pluginConfigurations> + <keyConfiguration> + <cacheKeyConfiguration typeName='foo' affinityKeyFieldName='bar' /> + </keyConfiguration> </cacheConfiguration> <cacheConfiguration name='secondCache' /> </cacheConfiguration> http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs index 72c73e4..4be34c7 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationSerializerTest.cs @@ -111,6 +111,9 @@ namespace Apache.Ignite.Core.Tests Assert.IsFalse(cacheCfg.WriteBehindCoalescing); Assert.AreEqual(PartitionLossPolicy.ReadWriteAll, cacheCfg.PartitionLossPolicy); Assert.AreEqual("fooGroup", cacheCfg.GroupName); + + Assert.AreEqual("bar", cacheCfg.KeyConfiguration.Single().AffinityKeyFieldName); + Assert.AreEqual("foo", cacheCfg.KeyConfiguration.Single().TypeName); var queryEntity = cacheCfg.QueryEntities.Single(); Assert.AreEqual(typeof(int), queryEntity.KeyType); @@ -722,7 +725,15 @@ namespace Apache.Ignite.Core.Tests MemoryPolicyName = "somePolicy", PartitionLossPolicy = PartitionLossPolicy.ReadOnlyAll, GroupName = "abc", - SqlIndexMaxInlineSize = 24 + SqlIndexMaxInlineSize = 24, + KeyConfiguration = new[] + { + new CacheKeyConfiguration + { + AffinityKeyFieldName = "abc", + TypeName = "def" + }, + } } }, ClientMode = true, http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs index 34e356b..28e7ae8 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs @@ -410,8 +410,31 @@ namespace Apache.Ignite.Core.Tests public static void AssertReflectionEqual(object x, object y, string propertyPath = null, HashSet<string> ignoredProperties = null) { + if (x == null && y == null) + { + return; + } + + Assert.IsNotNull(x, propertyPath); + Assert.IsNotNull(y, propertyPath); + var type = x.GetType(); + if (type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type)) + { + var xCol = ((IEnumerable)x).OfType<object>().ToList(); + var yCol = ((IEnumerable)y).OfType<object>().ToList(); + + Assert.AreEqual(xCol.Count, yCol.Count, propertyPath); + + for (var i = 0; i < xCol.Count; i++) + { + AssertReflectionEqual(xCol[i], yCol[i], propertyPath, ignoredProperties); + } + + return; + } + Assert.AreEqual(type, y.GetType()); propertyPath = propertyPath ?? type.Name; @@ -426,8 +449,6 @@ namespace Apache.Ignite.Core.Tests foreach (var propInfo in props) { - var propType = propInfo.PropertyType; - if (ignoredProperties != null && ignoredProperties.Contains(propInfo.Name)) { continue; @@ -438,29 +459,7 @@ namespace Apache.Ignite.Core.Tests var xVal = propInfo.GetValue(x, null); var yVal = propInfo.GetValue(y, null); - if (xVal == null || yVal == null) - { - Assert.IsNull(xVal, propName); - Assert.IsNull(yVal, propName); - } - else if (propType != typeof(string) && propType.IsGenericType && - (propType.GetGenericTypeDefinition() == typeof(ICollection<>) || - propType.GetGenericTypeDefinition() == typeof(IDictionary<,>))) - { - var xCol = ((IEnumerable)xVal).OfType<object>().ToList(); - var yCol = ((IEnumerable)yVal).OfType<object>().ToList(); - - Assert.AreEqual(xCol.Count, yCol.Count, propName); - - for (var i = 0; i < xCol.Count; i++) - { - AssertReflectionEqual(xCol[i], yCol[i], propName, ignoredProperties); - } - } - else - { - AssertReflectionEqual(xVal, yVal, propName, ignoredProperties); - } + AssertReflectionEqual(xVal, yVal, propName, ignoredProperties); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/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 20a54d0..4e73d15 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -93,6 +93,7 @@ <ItemGroup> <Compile Include="Binary\BinaryBasicNameMapper.cs" /> <Compile Include="Binary\TimestampAttribute.cs" /> + <Compile Include="Cache\Configuration\CacheKeyConfiguration.cs" /> <Compile Include="Cache\Configuration\DataPageEvictionMode.cs" /> <Compile Include="Configuration\CheckpointWriteOrder.cs" /> <Compile Include="Configuration\DataPageEvictionMode.cs" /> @@ -113,6 +114,7 @@ <Compile Include="IDataStorageMetrics.cs" /> <Compile Include="Configuration\WalMode.cs" /> <Compile Include="Impl\Binary\BinaryTypeId.cs" /> + <Compile Include="Impl\Binary\IBinaryRawWriteAware.cs" /> <Compile Include="Impl\Client\Cache\CacheFlags.cs" /> <Compile Include="Impl\Client\Cache\Query\ClientQueryCursor.cs" /> <Compile Include="Impl\Cache\Query\PlatformQueryQursorBase.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityKeyMappedAttribute.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityKeyMappedAttribute.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityKeyMappedAttribute.cs index 1bfda9a..3b58471 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityKeyMappedAttribute.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Affinity/AffinityKeyMappedAttribute.cs @@ -18,7 +18,11 @@ namespace Apache.Ignite.Core.Cache.Affinity { using System; + using System.Diagnostics; + using System.Linq; + using System.Reflection; using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Impl.Binary; /// <summary> /// Specifies cache key field to be used to determine a node on which given cache key will be stored. @@ -41,6 +45,26 @@ namespace Apache.Ignite.Core.Cache.Affinity [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public sealed class AffinityKeyMappedAttribute : Attribute { - // No-op. + /// <summary> + /// Gets the affinity key field name from attribute. + /// </summary> + public static string GetFieldNameFromAttribute(Type type) + { + Debug.Assert(type != null); + + var res = ReflectionUtils.GetFieldsAndProperties(type) + .Select(x => x.Key) + .Where(x => x.GetCustomAttributes(false).OfType<AffinityKeyMappedAttribute>().Any()) + .Select(x => x.Name).ToArray(); + + if (res.Length > 1) + { + throw new BinaryObjectException(string.Format( + "Multiple '{0}' attributes found on type '{1}'. There can be only one affinity field.", + typeof(AffinityKeyMappedAttribute).Name, type)); + } + + return res.SingleOrDefault(); + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs index e7252b2..f4af778 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheConfiguration.cs @@ -28,6 +28,7 @@ namespace Apache.Ignite.Core.Cache.Configuration using System.IO; using System.Linq; using System.Xml.Serialization; + using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Cache; using Apache.Ignite.Core.Cache.Affinity; using Apache.Ignite.Core.Cache.Affinity.Rendezvous; @@ -48,7 +49,7 @@ namespace Apache.Ignite.Core.Cache.Configuration /// <summary> /// Defines grid cache configuration. /// </summary> - public class CacheConfiguration + public class CacheConfiguration : IBinaryRawWriteAware<BinaryWriter> { /// <summary> Default size of rebalance thread pool. </summary> public const int DefaultRebalanceThreadPoolSize = 2; @@ -294,10 +295,7 @@ namespace Apache.Ignite.Core.Cache.Configuration CacheStoreFactory = reader.ReadObject<IFactory<ICacheStore>>(); SqlIndexMaxInlineSize = reader.ReadInt(); - var count = reader.ReadInt(); - QueryEntities = count == 0 - ? null - : Enumerable.Range(0, count).Select(x => new QueryEntity(reader)).ToList(); + QueryEntities = reader.ReadCollectionRaw(r => new QueryEntity(r)); NearConfiguration = reader.ReadBoolean() ? new NearCacheConfiguration(reader) : null; @@ -305,7 +303,9 @@ namespace Apache.Ignite.Core.Cache.Configuration AffinityFunction = AffinityFunctionSerializer.Read(reader); ExpiryPolicyFactory = ExpiryPolicySerializer.ReadPolicyFactory(reader); - count = reader.ReadInt(); + KeyConfiguration = reader.ReadCollectionRaw(r => new CacheKeyConfiguration(r)); + + var count = reader.ReadInt(); if (count > 0) { @@ -332,6 +332,15 @@ namespace Apache.Ignite.Core.Cache.Configuration /// Writes this instance to the specified writer. /// </summary> /// <param name="writer">The writer.</param> + void IBinaryRawWriteAware<BinaryWriter>.Write(BinaryWriter writer) + { + Write(writer); + } + + /// <summary> + /// Writes this instance to the specified writer. + /// </summary> + /// <param name="writer">The writer.</param> internal void Write(BinaryWriter writer) { // Make sure system marshaller is used. @@ -374,20 +383,7 @@ namespace Apache.Ignite.Core.Cache.Configuration writer.WriteObject(CacheStoreFactory); writer.WriteInt(SqlIndexMaxInlineSize); - if (QueryEntities != null) - { - writer.WriteInt(QueryEntities.Count); - - foreach (var entity in QueryEntities) - { - if (entity == null) - throw new InvalidOperationException("Invalid cache configuration: QueryEntity can't be null."); - - entity.Write(writer); - } - } - else - writer.WriteInt(0); + writer.WriteCollectionRaw(QueryEntities); if (NearConfiguration != null) { @@ -401,6 +397,8 @@ namespace Apache.Ignite.Core.Cache.Configuration AffinityFunctionSerializer.Write(writer, AffinityFunction); ExpiryPolicySerializer.WritePolicyFactory(writer, ExpiryPolicyFactory); + writer.WriteCollectionRaw(KeyConfiguration); + if (PluginConfigurations != null) { writer.WriteInt(PluginConfigurations.Count); @@ -795,5 +793,11 @@ namespace Apache.Ignite.Core.Cache.Configuration /// </summary> [DefaultValue(DefaultSqlIndexMaxInlineSize)] public int SqlIndexMaxInlineSize { get; set; } + + /// <summary> + /// Gets or sets the key configuration. + /// </summary> + [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public ICollection<CacheKeyConfiguration> KeyConfiguration { get; set; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheKeyConfiguration.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheKeyConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheKeyConfiguration.cs new file mode 100644 index 0000000..efe31d9 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/CacheKeyConfiguration.cs @@ -0,0 +1,84 @@ +/* + * 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.Cache.Configuration +{ + using System; + using System.Diagnostics; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache.Affinity; + using Apache.Ignite.Core.Impl.Binary; + using Apache.Ignite.Core.Impl.Common; + + /// <summary> + /// Configuration defining various aspects of cache keys without explicit usage of annotations on user classes. + /// </summary> + public sealed class CacheKeyConfiguration : IBinaryRawWriteAware + { + /// <summary> + /// Initializes a new instance of the <see cref="CacheKeyConfiguration"/> class. + /// </summary> + public CacheKeyConfiguration() + { + // No-op. + } + + /// <summary> + /// Initializes a new instance of the <see cref="CacheKeyConfiguration"/> class, using specified type to look + /// for <see cref="AffinityKeyMappedAttribute"/>. + /// </summary> + public CacheKeyConfiguration(Type keyType) + { + IgniteArgumentCheck.NotNull(keyType, "keyType"); + + TypeName = keyType.FullName; + AffinityKeyFieldName = AffinityKeyMappedAttribute.GetFieldNameFromAttribute(keyType); + } + + /// <summary> + /// Gets or sets the name of the key type. + /// </summary> + public string TypeName { get; set; } + + /// <summary> + /// Gets or sets the name of the affinity key field. + /// See also <see cref="AffinityKeyMappedAttribute"/>, + /// <see cref="BinaryTypeConfiguration.AffinityKeyFieldName"/>. + /// </summary> + public string AffinityKeyFieldName { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="CacheKeyConfiguration"/> class. + /// </summary> + internal CacheKeyConfiguration(IBinaryRawReader reader) + { + Debug.Assert(reader != null); + + TypeName = reader.ReadString(); + AffinityKeyFieldName = reader.ReadString(); + } + + /// <summary> + /// Writes this object to the given writer. + /// </summary> + void IBinaryRawWriteAware<IBinaryRawWriter>.Write(IBinaryRawWriter writer) + { + writer.WriteString(TypeName); + writer.WriteString(AffinityKeyFieldName); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/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 e8d0c91..eb509a0 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Cache/Configuration/QueryEntity.cs @@ -24,7 +24,6 @@ namespace Apache.Ignite.Core.Cache.Configuration using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; - using System.Reflection; using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Impl.Cache; @@ -34,7 +33,7 @@ namespace Apache.Ignite.Core.Cache.Configuration /// 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 sealed class QueryEntity : IQueryEntityInternal + public sealed class QueryEntity : IQueryEntityInternal, IBinaryRawWriteAware { /** */ private Type _keyType; @@ -258,7 +257,7 @@ namespace Apache.Ignite.Core.Cache.Configuration /// <summary> /// Writes this instance. /// </summary> - internal void Write(IBinaryRawWriter writer) + void IBinaryRawWriteAware<IBinaryRawWriter>.Write(IBinaryRawWriter writer) { writer.WriteString(KeyTypeName); writer.WriteString(ValueTypeName); @@ -434,7 +433,7 @@ namespace Apache.Ignite.Core.Cache.Configuration visitedTypes.Add(type); - foreach (var memberInfo in GetFieldsAndProperties(type)) + foreach (var memberInfo in ReflectionUtils.GetFieldsAndProperties(type)) { var customAttributes = memberInfo.Key.GetCustomAttributes(true); @@ -487,33 +486,6 @@ namespace Apache.Ignite.Core.Cache.Configuration } /// <summary> - /// Gets the fields and properties. - /// </summary> - /// <param name="type">The type.</param> - /// <returns></returns> - private static IEnumerable<KeyValuePair<MemberInfo, Type>> GetFieldsAndProperties(Type type) - { - Debug.Assert(type != null); - - if (type.IsPrimitive) - yield break; - - const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | - BindingFlags.DeclaredOnly; - - while (type != typeof (object) && type != null) - { - foreach (var fieldInfo in type.GetFields(bindingFlags)) - yield return new KeyValuePair<MemberInfo, Type>(fieldInfo, fieldInfo.FieldType); - - foreach (var propertyInfo in type.GetProperties(bindingFlags)) - yield return new KeyValuePair<MemberInfo, Type>(propertyInfo, propertyInfo.PropertyType); - - type = type.BaseType; - } - } - - /// <summary> /// Extended index with group names. /// </summary> private class QueryIndexEx : QueryIndex http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs index a6ff324..e890577 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs @@ -302,17 +302,7 @@ namespace Apache.Ignite.Core writer.WriteIntNullable(_queryThreadPoolSize); // Cache config - var caches = CacheConfiguration; - - if (caches == null) - writer.WriteInt(0); - else - { - writer.WriteInt(caches.Count); - - foreach (var cache in caches) - cache.Write(writer); - } + writer.WriteCollectionRaw(CacheConfiguration); // Discovery config var disco = DiscoverySpi; @@ -623,10 +613,7 @@ namespace Apache.Ignite.Core _queryThreadPoolSize = r.ReadIntNullable(); // Cache config - var cacheCfgCount = r.ReadInt(); - CacheConfiguration = new List<CacheConfiguration>(cacheCfgCount); - for (int i = 0; i < cacheCfgCount; i++) - CacheConfiguration.Add(new CacheConfiguration(r)); + CacheConfiguration = r.ReadCollectionRaw(x => new CacheConfiguration(x)); // Discovery config DiscoverySpi = r.ReadBoolean() ? new TcpDiscoverySpi(r) : null; http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd index 6ede267..82eb465 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd @@ -575,6 +575,32 @@ </xs:attribute> </xs:complexType> </xs:element> + <xs:element name="keyConfiguration" minOccurs="0"> + <xs:annotation> + <xs:documentation>Cache key configuration collection.</xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:sequence> + <xs:element name="cacheKeyConfiguration" maxOccurs="unbounded"> + <xs:annotation> + <xs:documentation>Cache key configuration.</xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:attribute name="typeName" type="xs:string" use="required"> + <xs:annotation> + <xs:documentation>Key type name.</xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute name="affinityKeyFieldName" type="xs:string" use="required"> + <xs:annotation> + <xs:documentation>Affinity key field name.</xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> <xs:element name="pluginConfigurations" minOccurs="0"> <xs:annotation> <xs:documentation>Cache plugin configurations.</xs:documentation> http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs index da87d21..9be06c5 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReaderExtensions.cs @@ -19,6 +19,7 @@ namespace Apache.Ignite.Core.Impl.Binary { using System; using System.Collections.Generic; + using System.Diagnostics; using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Impl.Common; @@ -97,5 +98,31 @@ namespace Apache.Ignite.Core.Impl.Binary return obj is T ? (T) obj : ((ObjectInfoHolder) obj).CreateInstance<T>(); } + + /// <summary> + /// Reads the collection. + /// </summary> + public static ICollection<T> ReadCollectionRaw<T, TReader>(this TReader reader, + Func<TReader, T> factory) where TReader : IBinaryRawReader + { + Debug.Assert(reader != null); + Debug.Assert(factory != null); + + int count = reader.ReadInt(); + + if (count <= 0) + { + return null; + } + + var res = new List<T>(count); + + for (var i = 0; i < count; i++) + { + res.Add(factory(reader)); + } + + return res; + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs index 139783d..5233db8 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs @@ -23,10 +23,12 @@ namespace Apache.Ignite.Core.Impl.Binary using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; + using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache.Affinity; using Apache.Ignite.Core.Impl.Binary.IO; using Apache.Ignite.Core.Impl.Common; http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriterExtensions.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriterExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriterExtensions.cs index f75fcf8..d87d217 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriterExtensions.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriterExtensions.cs @@ -19,6 +19,7 @@ namespace Apache.Ignite.Core.Impl.Binary { using System; using System.Collections.Generic; + using System.Diagnostics; using System.IO; using Apache.Ignite.Core.Binary; @@ -182,5 +183,33 @@ namespace Apache.Ignite.Core.Impl.Binary writer.Stream.WriteInt(pos, cnt); } + + /// <summary> + /// Writes the collection of write-aware items. + /// </summary> + public static void WriteCollectionRaw<T, TWriter>(this TWriter writer, ICollection<T> collection) + where T : IBinaryRawWriteAware<TWriter> where TWriter: IBinaryRawWriter + { + Debug.Assert(writer != null); + + if (collection != null) + { + writer.WriteInt(collection.Count); + + foreach (var x in collection) + { + if (x == null) + { + throw new ArgumentNullException(string.Format("{0} can not be null", typeof(T).Name)); + } + + x.Write(writer); + } + } + else + { + writer.WriteInt(0); + } + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryRawWriteAware.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryRawWriteAware.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryRawWriteAware.cs new file mode 100644 index 0000000..9b191e4 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/IBinaryRawWriteAware.cs @@ -0,0 +1,42 @@ +/* + * 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.Binary +{ + using Apache.Ignite.Core.Binary; + + /// <summary> + /// Represents an object that can write itself to a raw binary writer. + /// </summary> + internal interface IBinaryRawWriteAware<in T> where T : IBinaryRawWriter + { + /// <summary> + /// Writes this object to the given writer. + /// </summary> + /// <param name="writer">Writer.</param> + /// <exception cref="System.IO.IOException">If write failed.</exception> + void Write(T writer); + } + + /// <summary> + /// Represents an object that can write itself to a raw binary writer. + /// </summary> + internal interface IBinaryRawWriteAware : IBinaryRawWriteAware<IBinaryRawWriter> + { + // No-op. + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs index e68aa0b..55b6121 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs @@ -505,7 +505,7 @@ namespace Apache.Ignite.Core.Impl.Binary desc = desc == null ? new BinaryFullTypeDescriptor(type, typeId, typeName, true, _cfg.NameMapper, - _cfg.IdMapper, ser, false, GetAffinityKeyFieldNameFromAttribute(type), + _cfg.IdMapper, ser, false, AffinityKeyMappedAttribute.GetFieldNameFromAttribute(type), BinaryUtils.IsIgniteEnum(type), registered) : new BinaryFullTypeDescriptor(desc, type, ser, registered); @@ -576,7 +576,8 @@ namespace Apache.Ignite.Core.Impl.Binary // Type is found. var typeName = GetTypeName(type, nameMapper); int typeId = GetTypeId(typeName, idMapper); - var affKeyFld = typeCfg.AffinityKeyFieldName ?? GetAffinityKeyFieldNameFromAttribute(type); + var affKeyFld = typeCfg.AffinityKeyFieldName + ?? AffinityKeyMappedAttribute.GetFieldNameFromAttribute(type); var serializer = GetSerializer(_cfg, typeCfg, type, typeId, nameMapper, idMapper, _log); return AddType(type, typeId, typeName, true, keepDeserialized, nameMapper, idMapper, serializer, @@ -627,24 +628,6 @@ namespace Apache.Ignite.Core.Impl.Binary } /// <summary> - /// Gets the affinity key field name from attribute. - /// </summary> - private static string GetAffinityKeyFieldNameFromAttribute(Type type) - { - var res = type.GetMembers() - .Where(x => x.GetCustomAttributes(false).OfType<AffinityKeyMappedAttribute>().Any()) - .Select(x => x.Name).ToArray(); - - if (res.Length > 1) - { - throw new BinaryObjectException(string.Format("Multiple '{0}' attributes found on type '{1}'. " + - "There can be only one affinity field.", typeof (AffinityKeyMappedAttribute).Name, type)); - } - - return res.SingleOrDefault(); - } - - /// <summary> /// Add type. /// </summary> /// <param name="type">Type.</param> http://git-wip-us.apache.org/repos/asf/ignite/blob/5b3ad97b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs index 50c51a7..9f004ae 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/ReflectionUtils.cs @@ -19,6 +19,7 @@ namespace Apache.Ignite.Core.Impl.Binary { using System; using System.Collections.Generic; + using System.Diagnostics; using System.Reflection; /// <summary> @@ -46,5 +47,31 @@ namespace Apache.Ignite.Core.Impl.Binary curType = curType.BaseType; } } + + /// <summary> + /// Gets all fields and properties, including base classes. + /// </summary> + /// <param name="type">The type.</param> + public static IEnumerable<KeyValuePair<MemberInfo, Type>> GetFieldsAndProperties(Type type) + { + Debug.Assert(type != null); + + if (type.IsPrimitive) + yield break; + + const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | + BindingFlags.DeclaredOnly; + + while (type != typeof(object) && type != null) + { + foreach (var fieldInfo in type.GetFields(bindingFlags)) + yield return new KeyValuePair<MemberInfo, Type>(fieldInfo, fieldInfo.FieldType); + + foreach (var propertyInfo in type.GetProperties(bindingFlags)) + yield return new KeyValuePair<MemberInfo, Type>(propertyInfo, propertyInfo.PropertyType); + + type = type.BaseType; + } + } } }
