将动态 class 与 TableEntityAdapter 用于 Azure Table 存储
Using dynamic class with TableEntityAdapter for Azure Table Storage
我有下面一行代码:
var entity = new TableEntityAdapter<object>(obj, partitionKey, id);
对象 obj
包含属性,当我保存到 Table 存储时,这些属性不会被保存。我明白为什么,因为它们没有定义在class object
.
如何定义 TableEntityAdapter 在运行时使用的 class?
更新
是的,我用下面提到的 ElasticTableEntity 解决了这个问题 - 但是,我还发现现在有一个内置的 DynamicTableEntity
,这是默认的 table 结果.它的用途相同。
更新:
Microsoft.Azure.Cosmos.Table
的最新版本有一个内置的 class ElasticTableEntity
正是为了这个目的。
旧解决方案:
我用这个 ElasticTableEntity 解决了它
http://pascallaurin42.blogspot.com/2013/03/using-azure-table-storage-with-dynamic.html
public class ElasticTableEntity : DynamicObject, ITableEntity,
ICustomMemberProvider // For LinqPad's Dump
{
public ElasticTableEntity()
{
this.Properties = new Dictionary<string, EntityProperty>();
}
public IDictionary<string, EntityProperty> Properties { get; private set; }
public object this[string key]
{
get
{
if (!this.Properties.ContainsKey(key))
this.Properties.Add(key, this.GetEntityProperty(key, null));
return this.Properties[key];
}
set
{
var property = this.GetEntityProperty(key, value);
if (this.Properties.ContainsKey(key))
this.Properties[key] = property;
else
this.Properties.Add(key, property);
}
}
#region DynamicObject overrides
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this[binder.Name];
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this[binder.Name] = value;
return true;
}
#endregion
#region ITableEntity implementation
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset Timestamp { get; set; }
public string ETag { get; set; }
public void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
{
this.Properties = properties;
}
public IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
return this.Properties;
}
#endregion
#region ICustomMemberProvider implementation for LinqPad's Dump
public IEnumerable<string> GetNames()
{
return new[] { "PartitionKey", "RowKey", "Timestamp", "ETag" }
.Union(this.Properties.Keys);
}
public IEnumerable<Type> GetTypes()
{
return new[] { typeof(string), typeof(string), typeof(DateTimeOffset), typeof(string) }
.Union(this.Properties.Values.Select(x => this.GetType(x.PropertyType)));
}
public IEnumerable<object> GetValues()
{
return new object[] { this.PartitionKey, this.RowKey, this.Timestamp, this.ETag }
.Union(this.Properties.Values.Select(x => this.GetValue(x)));
}
#endregion
private EntityProperty GetEntityProperty(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("not supported " + value.GetType() + " for " + key);
}
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 Exception("not supported " + edmType);
}
}
private object GetValue(EntityProperty property)
{
switch (property.PropertyType)
{
case EdmType.Binary : return property.BinaryValue;
case EdmType.Boolean : return property.BooleanValue;
case EdmType.DateTime : return property.DateTimeOffsetValue;
case EdmType.Double : return property.DoubleValue;
case EdmType.Guid : return property.GuidValue;
case EdmType.Int32 : return property.Int32Value;
case EdmType.Int64 : return property.Int64Value;
case EdmType.String : return property.StringValue;
default: throw new Exception("not supported " + property.PropertyType);
}
}
}
我有下面一行代码:
var entity = new TableEntityAdapter<object>(obj, partitionKey, id);
对象 obj
包含属性,当我保存到 Table 存储时,这些属性不会被保存。我明白为什么,因为它们没有定义在class object
.
如何定义 TableEntityAdapter 在运行时使用的 class?
更新
是的,我用下面提到的 ElasticTableEntity 解决了这个问题 - 但是,我还发现现在有一个内置的 DynamicTableEntity
,这是默认的 table 结果.它的用途相同。
更新:
Microsoft.Azure.Cosmos.Table
的最新版本有一个内置的 class ElasticTableEntity
正是为了这个目的。
旧解决方案:
我用这个 ElasticTableEntity 解决了它
http://pascallaurin42.blogspot.com/2013/03/using-azure-table-storage-with-dynamic.html
public class ElasticTableEntity : DynamicObject, ITableEntity,
ICustomMemberProvider // For LinqPad's Dump
{
public ElasticTableEntity()
{
this.Properties = new Dictionary<string, EntityProperty>();
}
public IDictionary<string, EntityProperty> Properties { get; private set; }
public object this[string key]
{
get
{
if (!this.Properties.ContainsKey(key))
this.Properties.Add(key, this.GetEntityProperty(key, null));
return this.Properties[key];
}
set
{
var property = this.GetEntityProperty(key, value);
if (this.Properties.ContainsKey(key))
this.Properties[key] = property;
else
this.Properties.Add(key, property);
}
}
#region DynamicObject overrides
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this[binder.Name];
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this[binder.Name] = value;
return true;
}
#endregion
#region ITableEntity implementation
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset Timestamp { get; set; }
public string ETag { get; set; }
public void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
{
this.Properties = properties;
}
public IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
return this.Properties;
}
#endregion
#region ICustomMemberProvider implementation for LinqPad's Dump
public IEnumerable<string> GetNames()
{
return new[] { "PartitionKey", "RowKey", "Timestamp", "ETag" }
.Union(this.Properties.Keys);
}
public IEnumerable<Type> GetTypes()
{
return new[] { typeof(string), typeof(string), typeof(DateTimeOffset), typeof(string) }
.Union(this.Properties.Values.Select(x => this.GetType(x.PropertyType)));
}
public IEnumerable<object> GetValues()
{
return new object[] { this.PartitionKey, this.RowKey, this.Timestamp, this.ETag }
.Union(this.Properties.Values.Select(x => this.GetValue(x)));
}
#endregion
private EntityProperty GetEntityProperty(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("not supported " + value.GetType() + " for " + key);
}
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 Exception("not supported " + edmType);
}
}
private object GetValue(EntityProperty property)
{
switch (property.PropertyType)
{
case EdmType.Binary : return property.BinaryValue;
case EdmType.Boolean : return property.BooleanValue;
case EdmType.DateTime : return property.DateTimeOffsetValue;
case EdmType.Double : return property.DoubleValue;
case EdmType.Guid : return property.GuidValue;
case EdmType.Int32 : return property.Int32Value;
case EdmType.Int64 : return property.Int64Value;
case EdmType.String : return property.StringValue;
default: throw new Exception("not supported " + property.PropertyType);
}
}
}