This article requires some understanding of LINQ, LAMBDA expressions, and Delegates in C #.
At work, you often encounter scenarios that require a comparison of two sets, such as:
- Page collection data modifications that need to be saved to the database
- Full synchronization of upstream data to the system database
In these scenarios, you need to identify the data that needs to be added, updated, deleted, and because each application is inconsistent with the type of object that needs to be compared, a relatively generic method is written. In this process, the following 2 core concepts need to be understood:
- unique Identity comparison : If the unique identity of two objects is equal, the two objects are considered to represent the same thing in business (secondary attributes are not considered equal).
- Entity comparison : Indicates that two objects are not equal in the business (uniquely identifying equality, secondary attribute equality).
The code examples are as follows:
void Main () {//contrast source set var Source = generatestudent (1, 10000, 1000); Target set var target = generatestudent (5000, 10000, 1000); Unique identification comparison func<student, Student, bool> keycompartor = (s, t) = = S.id = t.id; Entity Equality comparison func<student, Student, bool> entitycompartor = (s, t) = S.id = T.id && s.name.equals (T.nam e) && s.age = = T.age; Added before preparing func<student, student> insertaction = (s) + = {return new Student {Id = S.id, Name = s.name, age = s.age, operation = "Insert"}; }; Pre-update Ready func<student, Student, student> updateaction = (s, t) = = {T.name = s.name; T.age = S.age; T.operation = "Update"; return t; }; Prepare func<student before deletion, student> deleteaction = (t) + = {t.operation = "delete"; return t; }; Remove equal objects removeduplicate (source, Target, Entitycompartor, (S1, S2) = S1. Id = = S2. Id, Keycompartor); Required new collection var insertingstudents = getinsertingentities (source, Target, Keycompartor, insertaction); Collections that need to be updated var updatingstudents = getupdatingentities (source, Target, Keycompartor, Entitycompartor, updateaction); The collection that needs to be deleted var deletingstudents = getdeletingentities (source, Target, Keycompartor, deleteaction); Follow-up service//insertstudents (insertingstudents); Updatestudents (updatingstudents); Deletestudents (deletingstudents);} Set de-heavy private void Removeduplicate<s, t> (list<s> source, list<t> Target, Func<s, T, bool> entity Compartor, Func<s, S, bool> sourcekeycompartor, Func<s, T, bool> keycomportor) {var sameentities = Sourc E.where (s + = target. Exists (t = entitycompartor (S, t))). ToList (); Source. RemoveAll (s = sameentities.exists (S2 = sourcekeycompartor (s, s2))); Target. RemoveAll (t = sameentities.exists (s = keycomportor (S, t))); Gets the collection of objects that need to be added PRIvate list<t> getinsertingentities<s, t> (list<s> source, list<t> Target, Func<s, T, bool> Keycomportor, Func<s, t> insertaction) {var result = new list<t> (); foreach (var s in source) {var t = target. FirstOrDefault (x = Keycomportor (s, x)); if (t = = null) {//does not exist in the target collection, new result is added. ADD (Insertaction (s)); }} return result; Gets the collection of objects that need to be updated private list<t> getupdatingentities<s, t> (list<s> source, list<t> Target, Func <s, T, bool> Keycomportor, Func<s, T, bool> Entitycompartor, Func<s, T, t> updateaction) {var resu lt = new list<t> (); foreach (var s in source) {var t = target. FirstOrDefault (x = Keycomportor (s, x)); if (t! = null &&!entitycompartor (S, t)) {//is present in the target collection, but the secondary property is not equal, the result is updated. ADD (Updateaction (S, t)); }} return result; Get collection of objects to delete private LiSt<t> Getdeletingentities<s, t> (list<s> source, list<t> Target, Func<s, T, bool> KeyCompo Rtor, Func<t, t> deleteaction) {var result = new list<t> (); foreach (Var t in Target) {var s = source. FirstOrDefault (x = Keycomportor (x, t)); if (s = = null) {//exists in the source collection, the result needs to be removed from the target collection. ADD (Deleteaction (t)); }} return result; Randomly generated test set private list<student> generatestudent (int minid, int maxid, int maxnumber) {var r = new Random (); var students = new list<student> (); for (int i = 0; i < MaxNumber; i++) {students. ADD (new Student {Id = R.next (MiniD, maxid), name = $ "Name: {r.next (1, Ten)}", age = R.next (6, 10)}); } return students. GroupBy (s = = s.id). Select (s = = S.first ()). ToList ();} public class student{public int Id {get; set;} public string Name {get; set;} public int Age {get; Set public string operation {get; set;}}
In the example, the source set uses the same object as the target collection, Student
but in practice, the two types can be different, as long as the type of the target collection is eventually returned.
Above is my experience of the collection comparison, only to meet the small data volume of the business scenario, and not in the case of large data volume has been tuned. Here is also a point, if you have a better way, but also hope to enlighten.
Quickly compare two collections with LINQ, LAMBDA expressions, and delegates to find objects that need to be added, modified, deleted