Azure Table storage 之改进DynamicTableEntity类为其添加动态语言扩展

在之前的一篇文章中提到,storage类库中包含一个可以用来动态获取Azure table storage 表结构的类-DynamicTableEntity。

我们可以通过这个类,我们无需为每一个表提前声明一个class,也能够对其进行操作。

但在我们要添加Entity到表中的时候会感觉到一点不舒服

以下我所希望使用的该类的方式:

dynamic entity = new DynamicTableEntity();
entity.Name=”sam”;
entity.Gender=true;
…

这样的形式

而实际代码却是

DynamicTableEntity entity1 = new DynamicTableEntity();
            Dictionary<string, EntityProperty> data1 = new Dictionary<string, EntityProperty>();
            data1.Add("Name", new EntityProperty("Sam"));
            data1.Add("Gender", new EntityProperty(true));
            data1.Add("Age", new EntityProperty(18));
            entity1.Properties = data1;
            entity1.PartitionKey = "Partition1";
            entity1.RowKey = "1";
            UserDataList.Add(entity1);

  

身为一个以dynamic开头的类居然不能够用dynamic关键字来初始化它,在实例化一个DynamicTableEntity类的时候居然要如此麻烦,实在让人不爽。

所以, 经过一番研究,发现了一个可以支持动态扩展的类,为了与DynamicTableEntity区分开来,所以取名DynamicObjectTableEntity。它实现了DynamicTableEntity相同的功能,而且继承了DynamicObject,从而具有动态语言的特性,更加方便 使用。

而且动态语言扩展一直以来除了在linq中使用比较多以外,其它地方基本看不到。这里正好通过对dynamicTableEntity的改造可以加深对动态语言扩展的理解。

实现代码如下:

public class DynamicObjectTableEntity : DynamicObject,ITableEntity
    {
        #region DynamicTableEntity's code
        // Methods
        public DynamicObjectTableEntity()
        {
            this.Properties = new Dictionary<string, EntityProperty>();
        }

        public DynamicObjectTableEntity(string partitionKey, string rowKey) : this(partitionKey, rowKey, DateTimeOffset.MinValue, null, new Dictionary<string, EntityProperty>())
        {
        }

        public DynamicObjectTableEntity(string partitionKey, string rowKey, string etag, IDictionary<string, EntityProperty> properties) : this(partitionKey, rowKey, DateTimeOffset.MinValue, etag, properties)
        {
        }

        internal DynamicObjectTableEntity(string partitionKey, string rowKey, DateTimeOffset timestamp, string etag, IDictionary<string, EntityProperty> properties)
        {
            //CommonUtility.AssertNotNull("partitionKey", partitionKey);
            //CommonUtility.AssertNotNull("rowKey", rowKey);
            //CommonUtility.AssertNotNull("properties", properties);
            this.PartitionKey = partitionKey;
            this.RowKey = rowKey;
            this.Timestamp = timestamp;
            this.ETag = etag;
            this.Properties = properties;
        }

        public void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
        {
            this.Properties = properties;
        }

        public IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
        {
            return this.Properties;
        }

        // Properties
        public string ETag { get; set; }

        public EntityProperty this[string key]
        {
            get
            {
                return this.Properties[key];
            }
            set
            {
                this.Properties[key] = value;
            }
        }

        public string PartitionKey { get; set; }

        public IDictionary<string, EntityProperty> Properties { get; set; }

        public string RowKey { get; set; }

        public DateTimeOffset Timestamp { get; set; }

        #endregion

        #region override DynamicObject's mehtods
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (!Properties.ContainsKey(binder.Name))
                Properties.Add(binder.Name, ConvertToEntityProperty(binder.Name, null));
            result = Properties[binder.Name];
            return true;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            EntityProperty property = ConvertToEntityProperty(binder.Name, value);

            if (Properties.ContainsKey(binder.Name))
                Properties[binder.Name] = property;
            else
                Properties.Add(binder.Name, property);

            return true;
        }

        /// <summary>
        /// Convert object value to EntityProperty.
        /// </summary>
        private EntityProperty ConvertToEntityProperty(string key, object value)
        {
            if (value == null) return new EntityProperty((string)null);
            if (value.GetType() == typeof(byte[]))
                return new EntityProperty((byte[])value);
            if (value.GetType() == typeof(bool))
                return new EntityProperty((bool)value);
            if (value.GetType() == typeof(DateTimeOffset))
                return new EntityProperty((DateTimeOffset)value);
            if (value.GetType() == typeof(DateTime))
                return new EntityProperty((DateTime)value);
            if (value.GetType() == typeof(double))
                return new EntityProperty((double)value);
            if (value.GetType() == typeof(Guid))
                return new EntityProperty((Guid)value);
            if (value.GetType() == typeof(int))
                return new EntityProperty((int)value);
            if (value.GetType() == typeof(long))
                return new EntityProperty((long)value);
            if (value.GetType() == typeof(string))
                return new EntityProperty((string)value);
            throw new Exception("This value type" + value.GetType() + " for " + key);
            throw new Exception(string.Format("This value type {0} is not supported for {1}", key));
        }

        /// <summary>
        /// Get the edm type, if the type is not a edm type throw a exception.
        /// </summary>
        private Type GetType(EdmType edmType)
        {
            switch (edmType)
            {
                case EdmType.Binary:
                    return typeof(byte[]);
                case EdmType.Boolean:
                    return typeof(bool);
                case EdmType.DateTime:
                    return typeof(DateTime);
                case EdmType.Double:
                    return typeof(double);
                case EdmType.Guid:
                    return typeof(Guid);
                case EdmType.Int32:
                    return typeof(int);
                case EdmType.Int64:
                    return typeof(long);
                case EdmType.String:
                    return typeof(string);
                default: throw new TypeLoadException(string.Format("not supported edmType:{0}", edmType));
            }
        }

        #endregion
    }

 

在使用了如下类之后,我们就可以用我预期的代码来操作table 了

代码如下:

static void Main(string[] args)
        {
            var connectionString = "DefaultEndpointsProtocol=https;AccountName=[Account];AccountKey=[Key]";
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
            try
            {
                var client = storageAccount.CreateCloudTableClient();
                var table = client.GetTableReference("ShortMessages");
                table.CreateIfNotExists();
                dynamic entity = new DynamicObjectTableEntity("default", DateTime.Now.ToShortTimeString());

                entity.Name = "pete";
                entity.Message = "Hello";
                table.Execute(TableOperation.Insert(entity));
                Console.WriteLine("insert successfully!");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.Read();    
        }

  

示例参考MSDN:http://code.msdn.microsoft.com/Dynamic-TableServiceEntity-151d661f

 

 

原文地址:https://www.cnblogs.com/he-yuan/p/3386143.html