1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . ComponentModel . DataAnnotations ;
4
+ using System . Linq ;
5
+ using System . Reflection ;
6
+
7
+ namespace MiniORM
8
+ {
9
+ internal class ChangeTracker < T >
10
+ where T : class , new ( )
11
+ {
12
+ private readonly List < T > allEntities ;
13
+ private readonly List < T > added ;
14
+ private readonly List < T > removed ;
15
+
16
+ public ChangeTracker ( IEnumerable < T > entities )
17
+ {
18
+ this . added = new List < T > ( ) ;
19
+ this . removed = new List < T > ( ) ;
20
+
21
+ this . allEntities = CloneEntities ( entities ) ;
22
+ }
23
+
24
+ public IReadOnlyCollection < T > AllEntities => this . allEntities . AsReadOnly ( ) ;
25
+
26
+ public IReadOnlyCollection < T > Added => this . added . AsReadOnly ( ) ;
27
+
28
+ public IReadOnlyCollection < T > Removed => this . removed . AsReadOnly ( ) ;
29
+
30
+ public void Add ( T item ) => this . added . Add ( item ) ;
31
+
32
+ public void Remove ( T item ) => this . removed . Add ( item ) ;
33
+
34
+ private List < T > CloneEntities ( IEnumerable < T > entities )
35
+ {
36
+ var clonedEntities = new List < T > ( ) ;
37
+
38
+ PropertyInfo [ ] propertiesToClone = typeof ( T ) . GetProperties ( )
39
+ . Where ( pi => DbContext . allowedSqlTypes . Contains ( pi . PropertyType ) )
40
+ . ToArray ( ) ;
41
+
42
+ foreach ( var entity in entities )
43
+ {
44
+ var clonedEntity = Activator . CreateInstance < T > ( ) ;
45
+
46
+ foreach ( var property in propertiesToClone )
47
+ {
48
+ var value = property . GetValue ( entity ) ;
49
+ property . SetValue ( clonedEntity , value ) ;
50
+ }
51
+
52
+ clonedEntities . Add ( clonedEntity ) ;
53
+ }
54
+
55
+ return clonedEntities ;
56
+ }
57
+
58
+ public IEnumerable < T > GetModifiedEntities ( DbSet < T > dbset )
59
+ {
60
+ var modifiedEntities = new List < T > ( ) ;
61
+
62
+ var primaryKeys = typeof ( T ) . GetProperties ( )
63
+ . Where ( pi => pi . HasAttribute < KeyAttribute > ( ) )
64
+ . ToArray ( ) ;
65
+
66
+ foreach ( var proxyEntity in this . AllEntities )
67
+ {
68
+ var primaryKeyValues = GetPrimaryKeyValues ( primaryKeys , proxyEntity ) . ToArray ( ) ;
69
+
70
+ var entity = dbset . Entities
71
+ . Single ( e => GetPrimaryKeyValues ( primaryKeys , e )
72
+ . SequenceEqual ( primaryKeyValues ) ) ;
73
+
74
+ var isModified = IsModified ( proxyEntity , entity ) ;
75
+ if ( isModified )
76
+ {
77
+ modifiedEntities . Add ( entity ) ;
78
+ }
79
+ }
80
+
81
+ return modifiedEntities ;
82
+ }
83
+
84
+ private bool IsModified ( T proxyEntity , T entity )
85
+ {
86
+ var monitoredProperties = typeof ( T ) . GetProperties ( )
87
+ . Where ( pi => DbContext . allowedSqlTypes . Contains ( pi . PropertyType ) ) ;
88
+
89
+ var modifiedProperties = monitoredProperties
90
+ . Where ( pi => ! Equals ( pi . GetValue ( entity ) , pi . GetValue ( proxyEntity ) ) )
91
+ . ToArray ( ) ;
92
+
93
+ var isModified = modifiedProperties . Any ( ) ;
94
+
95
+ return isModified ;
96
+ }
97
+
98
+ private static IEnumerable < object > GetPrimaryKeyValues ( PropertyInfo [ ] primaryKeys , T proxyEntity )
99
+ {
100
+ return primaryKeys . Select ( pk => pk . GetValue ( proxyEntity ) ) ;
101
+ }
102
+ }
103
+ }
0 commit comments