寫了幾篇 Azure Storage Table , 接下來就是這系列最後一篇了,主要目的我們要探討一下 關於物件中有特殊型別怎麼辦,身為真男人,當然你可以把複雜型別開成 string
把資料拿回來後自己在還原成物件,但是這樣做蠻麻煩的,這時候我在想如果乾脆複寫掉 TableEntity 自己來做一個,並且在序列化跟反序列化動手腳的話,這不是很完美。
前置作業 首先你要 安裝 nuget https://www.nuget.org/packages/Microsoft.Azure.Cosmos.Table
,這邊我撰寫案例是用 .net core 3.1;在 Azure Portal 開一個 儲存體帳戶,並且在左側的存取金鑰中拿到 Connection String.
說明一下今天要做的,我之前有設計一個測試的物件如下
public class User : DTableEntity
{
public string Name { get; set; }
public Int32? Age { get; set; }
public DateTime Create { get; set; }
public List Friends { get; set; }
public string Meta { get; set; }
public DateTime? LastLoginDate { get; set; }
public User()
{
Friends = new List();
}
public User(string classId, string userId)
{
PartitionKey = classId;
RowKey = userId;
Friends = new List();
}
}
這裡面有一個 Property 是 List<User> Friends ,這是一個複雜型別,這時候我們必須把資料寫入至 Azure Table ,但是需要用 JSON 儲存
不多說直接給我搞得一個 DTableEntity ,於是只要把 User 繼承他,就可以輕輕鬆鬆達到這效果
using Microsoft.Azure.Cosmos.Table;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
internal class ObjectUtil
{
public static Type GetType(string typeName)
{
var type = Type.GetType(typeName);
if (type != null) return type;
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
type = a.GetType(typeName);
if (type != null)
return type;
}
return null;
}
///
/// 轉成可以擴充的物件
///
///
///
public static dynamic ConvertToDynamic(object obj)
{
return JObject.Parse(JsonConvert.SerializeObject(obj));
}
}
public class DTableEntity : TableEntity
{
public override void ReadEntity(IDictionary 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 || properties[thisProperty.Name].PropertyType == EdmType.DateTime)))
{
var t = thisProperty.PropertyType;
if (t.IsPrimitive || t == typeof(String))
{
Convert.ChangeType(properties[thisProperty.Name].PropertyAsObject, thisProperty.PropertyType);
}
else if (t == typeof(DateTime?) || t == typeof(DateTime))
{
if (properties[thisProperty.Name] != null)
{
thisProperty.SetValue(this, TimeZoneInfo.ConvertTimeFromUtc(properties[thisProperty.Name].DateTime.Value, TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id)));
}
}
else
{
if (thisProperty.PropertyType.IsGenericType && (thisProperty.PropertyType.GetGenericTypeDefinition() == typeof(List<>)))
{
var newStr = thisProperty.PropertyType.ToString().Replace("System.Collections.Generic.List`1[", "").Replace("]", "");
var type = ObjectUtil.GetType(newStr);
Type listType = typeof(List<>).MakeGenericType(new Type[] { type });
thisProperty.SetValue(this, JsonConvert.DeserializeObject(properties[thisProperty.Name].StringValue, listType));
}
else
{
thisProperty.SetValue(this, JsonConvert.DeserializeObject(properties[thisProperty.Name].StringValue, ObjectUtil.GetType(thisProperty.PropertyType.ToString())));
}
}
}
}
public override IDictionary 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)
{
var t = thisProperty.GetType();
properties.Add(thisProperty.Name, new EntityProperty(JsonConvert.SerializeObject(value)));
}
}
return properties;
}
}
中間的序列化跟反序列化,我都幫你處理了,但是會用掉一點性能去換,當然這世界沒有完美的,這裡面參考許多開源,整理出來一個輕量參考那些文件已經不可考了所以也沒有附上了,在這系列的最後提供這讓大家可以輕鬆使用。
如果你是專案直接要用可以直接到這邊下宰我編譯好的 https://github.com/donma/Azure.Cosmos.Table
Happy Coding : )