forked from CoreHelpers/AzureStorageTable
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTableEntityDynamic.cs
More file actions
154 lines (129 loc) · 6.46 KB
/
TableEntityDynamic.cs
File metadata and controls
154 lines (129 loc) · 6.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Azure.Data.Tables;
using CoreHelpers.WindowsAzure.Storage.Table.Attributes;
using CoreHelpers.WindowsAzure.Storage.Table.Extensions;
using CoreHelpers.WindowsAzure.Storage.Table.Internal;
using HandlebarsDotNet;
namespace CoreHelpers.WindowsAzure.Storage.Table.Serialization
{
internal static class TableEntityDynamic
{
public static TableEntity ToEntity<T>(T model, IStorageContext context) where T : new()
{
if (context as StorageContext == null)
throw new Exception("Invalid interface implemnetation");
else
return TableEntityDynamic.ToEntity<T>(model, (context as StorageContext).GetEntityMapper<T>());
}
public static TableEntity ToEntity<T>(T model, StorageEntityMapper entityMapper) where T : new()
{
var builder = new TableEntityBuilder();
// set the keys
builder.AddPartitionKey(GetTableStorageDefaultProperty<string, T>(entityMapper.PartitionKeyFormat, model));
builder.AddRowKey(GetTableStorageDefaultProperty<string, T>(entityMapper.RowKeyFormat, model), entityMapper.RowKeyEncoding);
// get all properties from model
IEnumerable<PropertyInfo> objectProperties = model.GetType().GetTypeInfo().GetProperties();
// visit all properties
foreach (PropertyInfo property in objectProperties)
{
if (ShouldSkipProperty(property))
continue;
// check if we have a special convert attached via attribute if so generate the required target
// properties with the correct converter
var virtualTypeAttribute = property.GetCustomAttributes().Where(a => a is IVirtualTypeAttribute).Select(a => a as IVirtualTypeAttribute).FirstOrDefault<IVirtualTypeAttribute>();
if (virtualTypeAttribute != null)
virtualTypeAttribute.WriteProperty<T>(property, model, builder);
else if (property.PropertyType.IsEnum)
builder.AddProperty(property.Name, property.GetValue(model, null).ToString());
else
builder.AddProperty(property.Name, property.GetValue(model, null));
}
// build the result
return builder.Build();
}
public static T fromEntity<T>(TableEntity entity, StorageEntityMapper entityMapper) where T : class, new()
{
// create the target model
var model = new T();
// get all properties from model
IEnumerable<PropertyInfo> objectProperties = model.GetType().GetTypeInfo().GetProperties();
// visit all properties
foreach (PropertyInfo property in objectProperties)
{
if (ShouldSkipProperty(property))
continue;
// check if we have a special convert attached via attribute if so generate the required target
// properties with the correct converter
var virtualTypeAttribute = property.GetCustomAttributes().Where(a => a is IVirtualTypeAttribute).Select(a => a as IVirtualTypeAttribute).FirstOrDefault<IVirtualTypeAttribute>();
if (virtualTypeAttribute != null)
virtualTypeAttribute.ReadProperty<T>(entity, property, model);
else
{
if (!entity.ContainsKey(property.Name))
continue;
var objectValue = default(object);
if (!entity.TryGetValue(property.Name, out objectValue))
continue;
if (property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?) || property.PropertyType == typeof(DateTimeOffset) || property.PropertyType == typeof(DateTimeOffset?))
property.SetDateTimeOffsetValue(model, objectValue);
else if (property.PropertyType.IsEnum && int.TryParse(objectValue.ToString(), out var intEnum) && property.PropertyType.IsEnumDefined(intEnum))
property.SetValue(model, Enum.ToObject(property.PropertyType, intEnum));
else if (property.PropertyType.IsEnum && property.PropertyType.IsEnumDefined(objectValue.ToString()))
property.SetValue(model, Enum.Parse(property.PropertyType, objectValue.ToString()));
else
property.SetValue(model, objectValue);
}
}
return model;
}
private static S GetTableStorageDefaultProperty<S, T>(string format, T model) where S : class
{
if (typeof(S) == typeof(string) && format.Contains("{{") && format.Contains("}}"))
{
var template = Handlebars.Compile(format);
return template(model) as S;
}
else
{
var propertyInfo = model.GetType().GetRuntimeProperty(format);
return propertyInfo.GetValue(model) as S;
}
}
private static bool ShouldSkipProperty(PropertyInfo property)
{
// reserved properties
string propName = property.Name;
if (propName == TableConstants.PartitionKey ||
propName == TableConstants.RowKey ||
propName == TableConstants.Timestamp ||
propName == TableConstants.Etag)
{
return true;
}
MethodInfo setter = property.SetMethod;
MethodInfo getter = property.GetMethod;
// Enforce public getter / setter
if (setter == null || !setter.IsPublic || getter == null || !getter.IsPublic)
{
// Logger.LogInformational(operationContext, SR.TraceNonPublicGetSet, property.Name);
return true;
}
// Skip static properties
if (setter.IsStatic)
{
return true;
}
// properties with [IgnoreAttribute]
if (property.GetCustomAttribute(typeof(IgnoreDataMemberAttribute)) != null)
{
// Logger.LogInformational(operationContext, SR.TraceIgnoreAttribute, property.Name);
return true;
}
return false;
}
}
}