-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathLoggedChangeTracker.cs
130 lines (107 loc) · 4.46 KB
/
LoggedChangeTracker.cs
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
using AO.Models.Interfaces;
using Dapper.CX.ChangeTracking.Models;
using Dapper.CX.Interfaces;
using ModelSync.Library.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
namespace Dapper.CX.Classes
{
public class LoggedChangeTracker<TModel> : Dictionary<string, object>, IDbSaveable
{
private static bool _initialized = false;
private readonly IUserBase _user;
private readonly string _nullText;
private readonly ISqlCrudProvider<long> _crudProvider;
public LoggedChangeTracker(ISqlCrudProvider<long> crudProvider, IUserBase user, TModel @object, string nullText = "<null>") : base(@object)
{
_user = user;
_nullText = nullText;
_crudProvider = crudProvider;
}
private enum ValueType
{
Enum,
Lookup,
Raw
}
public async Task SaveAsync(IDbConnection connection)
{
await InitializeAsync(connection);
string tableName = typeof(TModel).GetTableName();
long rowId = GetRowId();
using (var txn = connection.BeginTransaction())
{
try
{
int version = await IncrementRowVersionAsync(connection, tableName, rowId, txn);
var textLookup = Instance as ITextLookup;
foreach (var kp in GetModifiedProperties())
{
var rawOldValue = this[kp.Key];
var rawNewValue = kp.Value.GetValue(Instance);
var valueType =
(kp.Value.PropertyType.IsEnum) ? ValueType.Enum :
(textLookup?.GetLookupProperties()?.Contains(kp.Key) ?? false) ? ValueType.Lookup :
ValueType.Raw;
var oldValue =
(valueType == ValueType.Enum) ? rawOldValue?.ToString() :
(valueType == ValueType.Lookup) ? await textLookup.GetTextFromKeyAsync(connection, txn, kp.Key, rawOldValue) :
rawOldValue;
var newValue =
(valueType == ValueType.Enum) ? rawNewValue?.ToString() :
(valueType == ValueType.Lookup) ? await textLookup.GetTextFromKeyAsync(connection, txn, kp.Key, rawNewValue) :
rawNewValue;
var history = new ColumnHistory()
{
UserName = _user.Name,
Timestamp = _user.LocalTime,
TableName = tableName,
RowId = rowId,
Version = version,
ColumnName = kp.Key,
OldValue = oldValue?.ToString() ?? _nullText,
NewValue = newValue?.ToString() ?? _nullText
};
await _crudProvider.SaveAsync(connection, history, txn: txn);
}
txn.Commit();
}
catch
{
txn.Rollback();
throw;
}
}
}
private async Task<int> IncrementRowVersionAsync(IDbConnection connection, string tableName, long rowId, IDbTransaction txn)
{
var rowVersion = await _crudProvider.GetWhereAsync<RowVersion>(connection, new { tableName, rowId }, txn) ?? new RowVersion()
{
TableName = tableName,
RowId = rowId
};
rowVersion.Version++;
await _crudProvider.SaveAsync(connection, rowVersion, txn: txn);
return rowVersion.Version;
}
private long GetRowId()
{
var idProperty = typeof(TModel).GetIdentityProperty();
var value = idProperty.GetValue(Instance);
return Convert.ToInt64(value);
}
private async Task InitializeAsync(IDbConnection connection)
{
if (_initialized) return;
await DataModel.CreateTablesAsync(new Type[]
{
typeof(ColumnHistory),
typeof(RowVersion)
}, connection);
_initialized = true;
}
}
}