[英]Storing blobs in windows azure store additional data such as content type in DB
[英]Storing decimal data type in Azure Tables
覆蓋基類中的ReadEntity
和WriteEntity
對此有好處。 每次檢索實體時都沒有必要編寫EntityResolver
。
public class CustomTableEntity : TableEntity
{
public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
{
base.ReadEntity(properties, operationContext);
foreach (var thisProperty in
GetType().GetProperties().Where(thisProperty =>
thisProperty.GetType() != typeof(string) &&
properties.ContainsKey(thisProperty.Name) &&
properties[thisProperty.Name].PropertyType == EdmType.String))
{
var parse = thisProperty.PropertyType.GetMethods().SingleOrDefault(m =>
m.Name == "Parse" &&
m.GetParameters().Length == 1 &&
m.GetParameters()[0].ParameterType == typeof(string));
var value = parse != null ?
parse.Invoke(thisProperty, new object[] { properties[thisProperty.Name].StringValue }) :
Convert.ChangeType(properties[thisProperty.Name].PropertyAsObject, thisProperty.PropertyType);
thisProperty.SetValue(this, value);
}
}
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
var properties = base.WriteEntity(operationContext);
foreach (var thisProperty in
GetType().GetProperties().Where(thisProperty =>
!properties.ContainsKey(thisProperty.Name) &&
typeof(TableEntity).GetProperties().All(p => p.Name != thisProperty.Name)))
{
var value = thisProperty.GetValue(this);
if (value != null)
{
properties.Add(thisProperty.Name, new EntityProperty(value.ToString()));
}
}
return properties;
}
}
使用時,只需從CustomTableEntity
擴展實體,插入或檢索實體時它將是透明的。 它支持DateTime
, TimeSpan
, decimal
和那些具有Parse
方法或實現IConvertible
接口的類型。
您可以覆蓋TableEntity中的WriteEntity方法並使用EntityResolver
public class CustomTableEntity : TableEntity
{
private const string DecimalPrefix = "D_";
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
var entityProperties = base.WriteEntity(operationContext);
var objectProperties = GetType().GetProperties();
foreach (var item in objectProperties.Where(f => f.PropertyType == typeof (decimal)))
{
entityProperties.Add(DecimalPrefix + item.Name, new EntityProperty(item.GetValue(this, null).ToString()));
}
return entityProperties;
}
}
我們將使用的實體
public class MyEntity : CustomTableEntity
{
public string MyProperty { get; set; }
public decimal MyDecimalProperty1 { get; set; }
public decimal MyDecimalProperty2 { get; set; }
}
用法包括Create Table / Insert / Retreive
#region connection
CloudStorageAccount account = CloudStorageAccount.DevelopmentStorageAccount;
CloudTableClient client = account.CreateCloudTableClient();
CloudTable table = client.GetTableReference("mytable");
table.CreateIfNotExists();
#endregion
const string decimalPrefix = "D_";
const string partitionKey = "BlaBlaBla";
string rowKey = DateTime.Now.ToString("yyyyMMddHHmmss");
#region Insert
var entity = new MyEntity
{
PartitionKey = partitionKey,
RowKey = rowKey,
MyProperty = "Test",
MyDecimalProperty1 = (decimal) 1.2,
MyDecimalProperty2 = (decimal) 3.45
};
TableOperation insertOperation = TableOperation.Insert(entity);
table.Execute(insertOperation);
#endregion
#region Retrieve
EntityResolver<MyEntity> myEntityResolver = (pk, rk, ts, props, etag) =>
{
var resolvedEntity = new MyEntity {PartitionKey = pk, RowKey = rk, Timestamp = ts, ETag = etag};
foreach (var item in props.Where(p => p.Key.StartsWith(decimalPrefix)))
{
string realPropertyName = item.Key.Substring(decimalPrefix.Length);
System.Reflection.PropertyInfo propertyInfo = resolvedEntity.GetType().GetProperty(realPropertyName);
propertyInfo.SetValue(resolvedEntity, Convert.ChangeType(item.Value.StringValue, propertyInfo.PropertyType), null);
}
resolvedEntity.ReadEntity(props, null);
return resolvedEntity;
};
TableOperation retrieveOperation = TableOperation.Retrieve(partitionKey, rowKey, myEntityResolver);
TableResult retrievedResult = table.Execute(retrieveOperation);
var myRetrievedEntity = retrievedResult.Result as MyEntity;
// myRetrievedEntity.Dump();
#endregion
您是否嘗試過使用Lokad.Cloud FatEntities產品?
我認為他們只是使用二進制序列化器來處理要存儲在表中的整個對象。 看看“對象到雲映射器”項目也是值得的:
@EUYUIL已經提出了一個很好的通用解決方案,我已經習慣了很好的效果,但是當他的回答表明它在使用Nullable類型時會失敗。
// Get the underlying types 'Parse' method
if (curType.IsGenericType && curType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
curType = Nullable.GetUnderlyingType(curType);
}
如果它幫助任何人,readEntity的內容覆蓋foreach內部的方法。 可能有更好的方法來寫這個,但為了說明的目的,這將做。
var curType = thisProperty.PropertyType;
// Get the underlying types 'Parse' method
if (curType.IsGenericType && curType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
curType = Nullable.GetUnderlyingType(curType);
}
var parse = curType.GetMethods().SingleOrDefault(m =>
m.Name == "Parse" &&
m.GetParameters().Length == 1 &&
m.GetParameters()[0].ParameterType == typeof(string));
var value = parse != null ?
parse.Invoke(thisProperty, new object[] { properties[thisProperty.Name].StringValue }) :
Convert.ChangeType(properties[thisProperty.Name].PropertyAsObject, thisProperty.PropertyType);
thisProperty.SetValue(this, value);
您可以將屬性的類型更改為double
。 然后,您必須通過將表實體映射到您自己的域類型來在decimal
和double
之間進行轉換。 另一種選擇是在由單個decimal
字段支持的實體上具有兩個屬性。 但是,您可能希望繼續使用decimal
屬性的Quantity
名稱,因為它是存儲在表中的double
屬性,您必須通過重寫ReadEntity
和WriteEntity
將此屬性重命名為Quantity
。 那么你不妨使用這里提出的其他一些解決方案。
現在,您可能認為將decimal
存儲為double
會導致某些值無法正確地進行往返。 雖然肯定存在不會往返的值,因為兩種類型的范圍和精度是非常不同的,大多數“正常”值,例如貨幣值不是天文數字大且具有人類可讀的精度,將會沒有任何問題地往返。 原因是Convert.ToDouble
執行的從double
到decimal
轉換具有一個特殊屬性:
此方法返回的Decimal值最多包含15位有效數字。
下面是一個例子,說明如何解決其他有問題的數字,因為這樣:
var originalValue = 2.24M;
var doubleValue = (double) originalValue;
問題是使用浮點沒有精確表示十進制數2.24,因為沒有使用十進制數(2.24是有理數224/100)的有理數1/3的精確表示。 0.3333333333333333與1/3不同。 您可以通過以足夠的精度打印doubleValue
來驗證這一點。 Console.WriteLine($"{doubleValue:G17}")
產生
2.2400000000000002
但是,繞過該值仍然有效:
var roundTripValue = (decimal) doubleValue;
現在Console.WriteLine(roundTripValue)
產生
2.24
因此,只要您不對double
值進行任何計算,就可以使用它們來存儲decimal
值,前提是double
和decimal
之間的轉換符合上面引用的.NET規則。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.