diff --git a/Amazon.DynamoDB/DataModel/EntityUtils.cs b/Amazon.DynamoDB/DataModel/EntityUtils.cs index 8dc3e853c418..8fa5120c86a2 100644 --- a/Amazon.DynamoDB/DataModel/EntityUtils.cs +++ b/Amazon.DynamoDB/DataModel/EntityUtils.cs @@ -74,32 +74,48 @@ public static void ValidateVersionType(Type memberType) public static DynamoDBTableAttribute GetTableAttribute(Type type) { - DynamoDBTableAttribute tableAttribute = GetAttribute(type) as DynamoDBTableAttribute; + DynamoDBTableAttribute tableAttribute = null; + int count =0; + + foreach (var attribute in GetAttributes(type)) + { + if (!(attribute is DynamoDBTableAttribute)) + continue; + + count++; + if(count > 1) + throw new Exception("There can only be one TableAttribute per table."); + + tableAttribute = attribute as DynamoDBTableAttribute; + } + if (tableAttribute == null) return null; return tableAttribute; } - public static DynamoDBAttribute GetAttribute(Type targetType) + public static DynamoDBAttribute[] GetAttributes(Type targetType) { if (targetType == null) throw new ArgumentNullException("targetType"); - object[] attributes = targetType.GetCustomAttributes(typeof(DynamoDBAttribute), true); - return GetSingleDDBAttribute(attributes); + var attributes = targetType.GetCustomAttributes(typeof(DynamoDBAttribute), true); + return GetAttributes(attributes); } - public static DynamoDBAttribute GetAttribute(MemberInfo targetMemberInfo) + + public static DynamoDBAttribute[] GetAttributes(MemberInfo targetMemberInfo) { if (targetMemberInfo == null) throw new ArgumentNullException("targetMemberInfo"); - object[] attributes = targetMemberInfo.GetCustomAttributes(typeof(DynamoDBAttribute), true); - return GetSingleDDBAttribute(attributes); + var attributes = targetMemberInfo.GetCustomAttributes(typeof(DynamoDBAttribute), true); + return GetAttributes(attributes); } - public static DynamoDBAttribute GetSingleDDBAttribute(object[] attributes) + private static DynamoDBAttribute[] GetAttributes(object[] attributes) { - if (attributes.Length == 0) - return null; - if (attributes.Length == 1) - return (attributes[0] as DynamoDBAttribute); - throw new InvalidOperationException("Cannot have multiple DynamoDBAttributes on a single member"); + var result = new DynamoDBAttribute[attributes.Length]; + + for (int x = 0; x < attributes.Length; x++ ) + result[x] = attributes[x] as DynamoDBAttribute; + + return result; } #endregion diff --git a/Amazon.DynamoDB/DataModel/InternalModel.cs b/Amazon.DynamoDB/DataModel/InternalModel.cs index 1eeaa71e9415..c3694171c19b 100644 --- a/Amazon.DynamoDB/DataModel/InternalModel.cs +++ b/Amazon.DynamoDB/DataModel/InternalModel.cs @@ -159,7 +159,7 @@ internal static ItemStorageConfig CreateStorageConfig(Type type) ItemStorageConfig config = new ItemStorageConfig(); - DynamoDBTableAttribute tableAttribute = EntityUtils.GetTableAttribute(type); + var tableAttribute = EntityUtils.GetTableAttribute(type); if (tableAttribute == null || string.IsNullOrEmpty(tableAttribute.TableName)) throw new InvalidOperationException("No DynamoDBTableAttribute on type"); if (string.IsNullOrEmpty(tableAttribute.TableName)) throw new InvalidOperationException("DynamoDBTableAttribute.Table is empty or null"); @@ -174,22 +174,52 @@ internal static ItemStorageConfig CreateStorageConfig(Type type) // filter out properties that aren't both read and write if (!EntityUtils.IsReadWrite(member)) continue; - DynamoDBAttribute attribute = EntityUtils.GetAttribute(member); - - // filter out ignored properties - if (attribute is DynamoDBIgnoreAttribute) continue; + var attributes = EntityUtils.GetAttributes(member); Type memberType = EntityUtils.GetType(member); string attributeName = GetAccurateCase(config, member.Name); string propertyName = member.Name; - PropertyStorage propertyStorage = new PropertyStorage + var propertyStorage = new PropertyStorage + { + Member = member, + MemberType = memberType, + }; + + bool ignoreAttiribute = false; + DynamoDBPropertyAttribute propertyAttribute = null; + DynamoDBHashKeyAttribute hashKeyAttribute = null; + DynamoDBRangeKeyAttribute rangeKeyAttribute = null; + DynamoDBVersionAttribute versionAttribute = null; + + foreach (var attribute in attributes) { - Member = member, - MemberType = memberType, - }; + // filter out ignored properties + if (attribute is DynamoDBIgnoreAttribute) + { + ignoreAttiribute = true; + continue; + } + + if (attribute is DynamoDBVersionAttribute) + versionAttribute = attribute as DynamoDBVersionAttribute; + + if (attribute is DynamoDBPropertyAttribute) + propertyAttribute = attribute as DynamoDBPropertyAttribute; - if (attribute is DynamoDBVersionAttribute) + if (attribute is DynamoDBHashKeyAttribute) + hashKeyAttribute = attribute as DynamoDBHashKeyAttribute; + + if (attribute is DynamoDBRangeKeyAttribute) + rangeKeyAttribute = attribute as DynamoDBRangeKeyAttribute; + } + + if (ignoreAttiribute) + continue; + + //TODO: test for valid attribute combinations + + if (versionAttribute != null) { EntityUtils.ValidateVersionType(memberType); // no conversion is possible, so type must be a nullable primitive @@ -200,46 +230,48 @@ internal static ItemStorageConfig CreateStorageConfig(Type type) propertyStorage.IsVersion = true; } - DynamoDBPropertyAttribute propertyAttribute = attribute as DynamoDBPropertyAttribute; - if (propertyAttribute != null) + if (hashKeyAttribute != null) { - if (!string.IsNullOrEmpty(propertyAttribute.AttributeName)) - attributeName = GetAccurateCase(config, propertyAttribute.AttributeName); + if (propertyAttribute.Converter == null && !EntityUtils.IsPrimitive(memberType)) + throw new InvalidOperationException("Hash key " + propertyName + " must be of primitive type"); + if (!string.IsNullOrEmpty(config.HashKeyPropertyName)) + throw new InvalidOperationException("Multiple hash keys defined"); - if (propertyAttribute is DynamoDBHashKeyAttribute) - { - if (propertyAttribute.Converter == null && !EntityUtils.IsPrimitive(memberType)) - throw new InvalidOperationException("Hash key " + propertyName + " must be of primitive type"); - if (!string.IsNullOrEmpty(config.HashKeyPropertyName)) - throw new InvalidOperationException("Multiple hash keys defined"); + config.HashKeyPropertyName = propertyName; + propertyStorage.IsHashKey = true; + } - config.HashKeyPropertyName = propertyName; - propertyStorage.IsHashKey = true; - } - if (propertyAttribute is DynamoDBRangeKeyAttribute) - { - if (propertyAttribute.Converter == null && !EntityUtils.IsPrimitive(memberType)) - throw new InvalidOperationException("Range key " + propertyName + " must be of primitive type"); - if (!string.IsNullOrEmpty(config.RangeKeyPropertyName)) - throw new InvalidOperationException("Multiple range keys defined"); + if (rangeKeyAttribute != null) + { + if (propertyAttribute.Converter == null && !EntityUtils.IsPrimitive(memberType)) + throw new InvalidOperationException("Range key " + propertyName + " must be of primitive type"); + if (!string.IsNullOrEmpty(config.RangeKeyPropertyName)) + throw new InvalidOperationException("Multiple range keys defined"); - config.RangeKeyPropertyName = propertyName; - propertyStorage.IsRangeKey = true; - } + config.RangeKeyPropertyName = propertyName; + propertyStorage.IsRangeKey = true; + } + if (propertyAttribute != null) + { + if (!string.IsNullOrEmpty(propertyAttribute.AttributeName)) + attributeName = GetAccurateCase(config, propertyAttribute.AttributeName); if (propertyAttribute.Converter != null) { - if (!EntityUtils.CanInstantiate(propertyAttribute.Converter) || !EntityUtils.ImplementsInterface(propertyAttribute.Converter, typeof(IPropertyConverter))) + if (!EntityUtils.CanInstantiate(propertyAttribute.Converter) || + !EntityUtils.ImplementsInterface(propertyAttribute.Converter, + typeof(IPropertyConverter))) throw new InvalidOperationException("Converter for " + propertyName + " must be instantiable with no parameters and must implement IPropertyConverter"); - propertyStorage.Converter = EntityUtils.Instantiate(propertyAttribute.Converter) as IPropertyConverter; + propertyStorage.Converter = + EntityUtils.Instantiate(propertyAttribute.Converter) as IPropertyConverter; } } propertyStorage.PropertyName = propertyName; propertyStorage.AttributeName = attributeName; - + config.AttributesToGet.Add(attributeName); config.AddPropertyStorage(propertyStorage); }