Datei: NDODLL/ChangeLog/ChangeLog.cs
Last Commit (dac62ee)
1 | using NDO.Mapping; |
2 | using System; |
3 | using System.Collections; |
4 | using System.Collections.Generic; |
5 | using System.Data; |
6 | using System.Linq; |
7 | using System.Text; |
8 | using NDO.Configuration; |
9 | |
10 | namespace NDO.ChangeLogging |
11 | { |
12 | ····/// <summary> |
13 | ····/// This class represents changes to objects which can be serialized to an audit log. |
14 | ····/// </summary> |
15 | ····public class ChangeLog |
16 | ····{ |
17 | ········/// <summary> |
18 | ········/// The current objects. |
19 | ········/// </summary> |
20 | ········/// <remarks>This member is public because it should be serialized. Change it only if you know what you're doing.</remarks> |
21 | ········public IDictionary<string,object> current = new Dictionary<string, object>(); |
22 | ········/// <summary> |
23 | ········/// The original objects. |
24 | ········/// </summary> |
25 | ········/// <remarks>This member is public because it should be serialized. Change it only if you know what you're doing.</remarks> |
26 | ········public IDictionary<string,object> original = new Dictionary<string, object>(); |
27 | ········private readonly PersistenceManager pm; |
28 | |
29 | ········/// <summary> |
30 | ········/// Initializes the ChangeLog object. |
31 | ········/// </summary> |
32 | ········/// <param name="pm"></param> |
33 | ········public ChangeLog(PersistenceManager pm) |
34 | ········{············ |
35 | ············this.pm = pm; |
36 | ········} |
37 | |
38 | ········/// <summary> |
39 | ········/// Initializes the ChangeLog from an object |
40 | ········/// </summary> |
41 | ········/// <param name="o"></param> |
42 | ········public void Initialize(object o) |
43 | ········{ |
44 | ············IPersistenceCapable pc = pm.CheckPc( o ); |
45 | |
46 | ············// No changes |
47 | if ( pc. NDOObjectState == NDOObjectState. Hollow || pc. NDOObjectState == NDOObjectState. Persistent) |
48 | ············{ |
49 | ················return; |
50 | ············} |
51 | |
52 | ············DataRow row = pm.GetClonedDataRow( o ); |
53 | |
54 | ············NDO.Mapping.Class cls = pm.NDOMapping.FindClass(o.GetType()); |
55 | |
56 | ············foreach (Field field in cls.Fields) |
57 | ············{ |
58 | ················string colName = field.Column.Name; |
59 | ················object currentVal = row[colName, DataRowVersion.Current]; |
60 | ················object originalVal = row[colName, DataRowVersion.Original]; |
61 | |
62 | ················if (!currentVal.Equals( originalVal )) |
63 | ················{ |
64 | ····················original.Add( field.Name, originalVal ); |
65 | ····················current.Add( field.Name, currentVal ); |
66 | ················} |
67 | ············} |
68 | |
69 | ············var objRelationChanges = pm.RelationChanges.Where( ce => ce.Parent.NDOObjectId == pc.NDOObjectId ).GroupBy(ce=>ce.RelationName).ToList(); |
70 | ············if (objRelationChanges.Count > 0) |
71 | ············{ |
72 | var relStates = pm. CollectRelationStates( pc, row ) ; |
73 | ················foreach (var group in objRelationChanges) |
74 | ················{ |
75 | ····················string fieldName = group.Key; |
76 | ····················object fieldValue = (from rs in relStates where rs.Key.FieldName == fieldName select rs.Value).SingleOrDefault(); |
77 | ····················var relCurrent = new ObjectIdList(); |
78 | ····················if (fieldValue is IList l) |
79 | ····················{ |
80 | ························foreach (IPersistenceCapable item in l) |
81 | ························{ |
82 | ····························relCurrent.Add( item.NDOObjectId ); |
83 | ························} |
84 | ····················} |
85 | ····················else |
86 | ····················{ |
87 | ························if (fieldValue != null) |
88 | ····························relCurrent.Add( ( (IPersistenceCapable) fieldValue ).NDOObjectId ); |
89 | ····················} |
90 | |
91 | ····················// Make a copy |
92 | ····················var relOriginal = relCurrent.Clone(); |
93 | |
94 | ····················// In order to get the original array, we remove added objects |
95 | ····················// and add removed objects |
96 | ····················foreach (var changeEntry in group) |
97 | ····················{ |
98 | ························if (changeEntry.IsAdded) |
99 | ························{ |
100 | ····························var oid = changeEntry.Child.NDOObjectId; |
101 | ····························if (relOriginal.Contains( oid )) |
102 | ································relOriginal.Remove( oid ); |
103 | ························} |
104 | ························else |
105 | ························{ |
106 | ····························relOriginal.Add( changeEntry.Child.NDOObjectId ); |
107 | ························} |
108 | ····················} |
109 | ····················original.Add( fieldName, relOriginal ); |
110 | ····················current.Add( fieldName, relCurrent ); |
111 | ················} |
112 | ············} |
113 | ········} |
114 | |
115 | ········/// <summary> |
116 | ········/// Gets a serializable clone of the object, in which all ObjectId objects are replaced by ShortIds. |
117 | ········/// </summary> |
118 | ········/// <returns></returns> |
119 | ········public ChangeLog SerializableClone() |
120 | ········{ |
121 | ············ChangeLog result = new ChangeLog(this.pm); |
122 | ············result.current = new Dictionary<string, object>( this.current ); |
123 | ············result.original = new Dictionary<string, object>( this.original ); |
124 | ············foreach (var kvp in result.current.ToList()) |
125 | ············{ |
126 | ················if (result.current[kvp.Key] is ObjectIdList oidList) |
127 | ················{ |
128 | ····················result.current[kvp.Key] = oidList.ToStringList(); |
129 | ················} |
130 | ············} |
131 | ············foreach (var kvp in result.original.ToList()) |
132 | ············{ |
133 | ················if (result.original[kvp.Key] is ObjectIdList oidList) |
134 | ················{ |
135 | ····················result.original[kvp.Key] = oidList.ToStringList(); |
136 | ················} |
137 | ············} |
138 | ············return result; |
139 | ········} |
140 | |
141 | ········/// <summary> |
142 | ········/// Serializes the ChangeLog to a string using the IChangeLogConverter implementation |
143 | ········/// </summary> |
144 | ········/// <returns></returns> |
145 | ········public override string ToString() |
146 | ········{ |
147 | ············var changeLogConverter = pm.ConfigContainer.Resolve<IChangeLogConverter>(); |
148 | ············if (changeLogConverter == null) |
149 | ················throw new Exception( "Can't serialize the ChangeLog. Please register an implementation of IChangeLogConverter" ); |
150 | |
151 | ············return changeLogConverter.ToString( SerializableClone() ); |
152 | ········} |
153 | ····} |
154 | } |
155 |
New Commit (a932b6c)
1 | using NDO.Mapping; |
2 | using System; |
3 | using System.Collections; |
4 | using System.Collections.Generic; |
5 | using System.Data; |
6 | using System.Linq; |
7 | using System.Text; |
8 | using NDO.Configuration; |
9 | |
10 | namespace NDO.ChangeLogging |
11 | { |
12 | ····/// <summary> |
13 | ····/// This class represents changes to objects which can be serialized to an audit log. |
14 | ····/// </summary> |
15 | ····public class ChangeLog |
16 | ····{ |
17 | ········/// <summary> |
18 | ········/// The current objects. |
19 | ········/// </summary> |
20 | ········/// <remarks>This member is public because it should be serialized. Change it only if you know what you're doing.</remarks> |
21 | ········public IDictionary<string,object> current = new Dictionary<string, object>(); |
22 | ········/// <summary> |
23 | ········/// The original objects. |
24 | ········/// </summary> |
25 | ········/// <remarks>This member is public because it should be serialized. Change it only if you know what you're doing.</remarks> |
26 | ········public IDictionary<string,object> original = new Dictionary<string, object>(); |
27 | ········private readonly PersistenceManager pm; |
28 | |
29 | ········/// <summary> |
30 | ········/// Initializes the ChangeLog object. |
31 | ········/// </summary> |
32 | ········/// <param name="pm"></param> |
33 | ········public ChangeLog(PersistenceManager pm) |
34 | ········{············ |
35 | ············this.pm = pm; |
36 | ········} |
37 | |
38 | ········/// <summary> |
39 | ········/// Initializes the ChangeLog from an object |
40 | ········/// </summary> |
41 | ········/// <param name="o"></param> |
42 | ········public void Initialize(object o) |
43 | ········{ |
44 | ············IPersistenceCapable pc = pm.CheckPc( o ); |
45 | |
46 | ············// No changes |
47 | if ( pc. NDOObjectState == NDOObjectState. Hollow) |
48 | ············{ |
49 | ················return; |
50 | ············} |
51 | |
52 | ············if (pc.NDOObjectState != NDOObjectState.Persistent) |
53 | ············{ |
54 | ················DataRow row = pm.GetClonedDataRow( o ); |
55 | |
56 | ················NDO.Mapping.Class cls = pm.NDOMapping.FindClass(o.GetType()); |
57 | |
58 | ················foreach (Field field in cls.Fields) |
59 | ················{ |
60 | ····················string colName = field.Column.Name; |
61 | ····················object currentVal = row[colName, DataRowVersion.Current]; |
62 | ····················object originalVal = row[colName, DataRowVersion.Original]; |
63 | |
64 | ····················if (!currentVal.Equals( originalVal )) |
65 | ····················{ |
66 | ························original.Add( field.Name, originalVal ); |
67 | ························current.Add( field.Name, currentVal ); |
68 | ····················} |
69 | ················} |
70 | ············} |
71 | |
72 | ············var objRelationChanges = pm.RelationChanges.Where( ce => ce.Parent.NDOObjectId == pc.NDOObjectId ).GroupBy(ce=>ce.RelationName).ToList(); |
73 | ············if (objRelationChanges.Count > 0) |
74 | ············{ |
75 | var relStates = pm. CollectRelationStates( pc ) ; |
76 | ················foreach (var group in objRelationChanges) |
77 | ················{ |
78 | ····················string fieldName = group.Key; |
79 | ····················object fieldValue = (from rs in relStates where rs.Key.FieldName == fieldName select rs.Value).SingleOrDefault(); |
80 | ····················var relCurrent = new ObjectIdList(); |
81 | ····················if (fieldValue is IList l) |
82 | ····················{ |
83 | ························foreach (IPersistenceCapable item in l) |
84 | ························{ |
85 | ····························relCurrent.Add( item.NDOObjectId ); |
86 | ························} |
87 | ····················} |
88 | ····················else |
89 | ····················{ |
90 | ························if (fieldValue != null) |
91 | ····························relCurrent.Add( ( (IPersistenceCapable) fieldValue ).NDOObjectId ); |
92 | ····················} |
93 | |
94 | ····················// Make a copy |
95 | ····················var relOriginal = relCurrent.Clone(); |
96 | |
97 | ····················// In order to get the original array, we remove added objects |
98 | ····················// and add removed objects |
99 | ····················foreach (var changeEntry in group) |
100 | ····················{ |
101 | ························if (changeEntry.IsAdded) |
102 | ························{ |
103 | ····························var oid = changeEntry.Child.NDOObjectId; |
104 | ····························if (relOriginal.Contains( oid )) |
105 | ································relOriginal.Remove( oid ); |
106 | ························} |
107 | ························else |
108 | ························{ |
109 | ····························relOriginal.Add( changeEntry.Child.NDOObjectId ); |
110 | ························} |
111 | ····················} |
112 | ····················original.Add( fieldName, relOriginal ); |
113 | ····················current.Add( fieldName, relCurrent ); |
114 | ················} |
115 | ············} |
116 | ········} |
117 | |
118 | ········/// <summary> |
119 | ········/// Gets a serializable clone of the object, in which all ObjectId objects are replaced by ShortIds. |
120 | ········/// </summary> |
121 | ········/// <returns></returns> |
122 | ········public ChangeLog SerializableClone() |
123 | ········{ |
124 | ············ChangeLog result = new ChangeLog(this.pm); |
125 | ············result.current = new Dictionary<string, object>( this.current ); |
126 | ············result.original = new Dictionary<string, object>( this.original ); |
127 | ············foreach (var kvp in result.current.ToList()) |
128 | ············{ |
129 | ················if (result.current[kvp.Key] is ObjectIdList oidList) |
130 | ················{ |
131 | ····················result.current[kvp.Key] = oidList.ToStringList(); |
132 | ················} |
133 | ············} |
134 | ············foreach (var kvp in result.original.ToList()) |
135 | ············{ |
136 | ················if (result.original[kvp.Key] is ObjectIdList oidList) |
137 | ················{ |
138 | ····················result.original[kvp.Key] = oidList.ToStringList(); |
139 | ················} |
140 | ············} |
141 | ············return result; |
142 | ········} |
143 | |
144 | ········/// <summary> |
145 | ········/// Serializes the ChangeLog to a string using the IChangeLogConverter implementation |
146 | ········/// </summary> |
147 | ········/// <returns></returns> |
148 | ········public override string ToString() |
149 | ········{ |
150 | ············var changeLogConverter = pm.ConfigContainer.Resolve<IChangeLogConverter>(); |
151 | ············if (changeLogConverter == null) |
152 | ················throw new Exception( "Can't serialize the ChangeLog. Please register an implementation of IChangeLogConverter" ); |
153 | |
154 | ············return changeLogConverter.ToString( SerializableClone() ); |
155 | ········} |
156 | ····} |
157 | } |
158 |