The content of this article is about how to use LINQ, Lambda expressions, and delegates to quickly compare two collections and find out the objects that need to be added, modified, and deleted (with code). It has certain reference value. , friends in need can refer to it, I hope it will be helpful to you.
At work, I often encounter scenarios where two collections need to be compared, such as:
Page collection data modification needs to be saved to the database
Fully synchronize upstream data to the system database
In these scenarios, it is necessary to identify the data that needs to be added, updated, and deleted, because each application is, The types of objects that need to be compared are inconsistent, so I wrote a relatively general method. In this process, there are two core concepts that need to be understood:
Unique identification comparison: If the unique identifications of two objects are equal, the two objects are considered to be equal. The objects represent the same thing in business terms (whether the secondary attributes are equal is not considered yet).
Entity comparison: Indicates whether two objects are equal in business (unique identifiers are equal, secondary attributes are equal).
The code example is as follows:
void Main() { // 对比源集合 var source = GenerateStudent(1, 10000, 1000); // 目标集合 var target = GenerateStudent(5000, 10000, 1000); // 唯一标识比较 Func<Student, Student, bool> keyCompartor = (s, t) => s.Id == t.Id; // 实体相等比较 Func<Student, Student, bool> entityCompartor = (s, t) => s.Id == t.Id && s.Name.Equals(t.Name) && s.Age == t.Age; // 新增前准备 Func<Student, Student> insertAction = (s) => { return new Student { Id = s.Id, Name = s.Name, Age = s.Age, Operation = "Insert" }; }; // 更新前准备 Func<Student, Student, Student> updateAction = (s, t) => { t.Name = s.Name; t.Age = s.Age; t.Operation = "Update"; return t; }; // 删除前准备 Func<Student, Student> deleteAction = (t) => { t.Operation = "Delete"; return t; }; // 去掉相等对象 RemoveDuplicate(source, target, entityCompartor, (s1, s2) => s1.Id == s2.Id, keyCompartor); // 需要新增的集合 var insertingStudents = GetInsertingEntities(source, target, keyCompartor, insertAction); // 需要更新的集合 var updatingStudents = GetUpdatingEntities(source, target, keyCompartor, entityCompartor, updateAction); // 需要删除的集合 var deletingStudents = GetDeletingEntities(source, target, keyCompartor, deleteAction); // 后续业务 // InsertStudents(insertingStudents); // UpdateStudents(updatingStudents); // DeleteStudents(deletingStudents); } // 集合去重 private void RemoveDuplicate<S, T>(List<S> source, List<T> target, Func<S, T, bool> entityCompartor, Func<S, S, bool> sourceKeyCompartor, Func<S, T, bool> keyComportor) { var sameEntities = source.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))); } // 获取需要新增的对象集合 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) { // 目标集合中不存在,则新增 result.Add(insertAction(s)); } } return result; } // 获取需要更新的对象集合 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 result = new List<T>(); foreach (var s in source) { var t = target.FirstOrDefault(x => keyComportor(s, x)); if (t != null && !entityCompartor(s, t)) { // 目标集合中存在,但是次要属性不相等,则更新 result.Add(updateAction(s, t)); } } return result; } // 获取需要删除的对象集合 private List<T> GetDeletingEntities<S, T>(List<S> source, List<T> target, Func<S, T, bool> keyComportor, 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) { // 源集合中存在,目标集合中需要删除 result.Add(deleteAction(t)); } } return result; } // 随机生成测试集合 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, 10)}", 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 collection and the target collection use the same object Student
, but in actual use, both The types can be different, as long as the type of the target collection is finally returned.
The above is my experience on collection comparison. It only meets the business scenario of small data volume and has not been tuned in the case of large data volume. This can be regarded as a good idea. If you have a better way, I hope you can give me some advice.
The above is the detailed content of How to use LINQ, Lambda expressions, and delegates to quickly compare two collections and find objects that need to be added, modified, or deleted (code attached). For more information, please follow other related articles on the PHP Chinese website!