在工作中,常常碰到须要对照两个鸠合的场景,如:
页面鸠合数据修正,须要保存到数据库
全量同步上游数据到本系统数据库
在这些场景中,须要识别出须要新增、更新、删除的数据,因为每次应用是,须要比较的对象范例不一致,因而写了个相对通用的要领。这个过程当中,须要明白的有以下2个中心观点:
唯一标识比较: 假如两个对象的唯一标识相称,则以为这两个对象在营业上代表同一个东西(次要属性是不是相称暂不斟酌)。
实体比较:示意两个对象在营业是不是是相称(唯一标识相称、次要属性相称)。
代码示例以下:
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; } }
例子中源鸠合与目的鸠合运用了雷同的对象Student
,但实际运用中,二者的范例能够不一样,只需终究返回目的鸠合的范例就能够了。
上面是我对鸠合比较的一点心得,只满足了小数据量的营业情形,并没有在大数据量的情况下做过调优。在这里也算是举一反三,人人如果有更好的方法,还愿望不吝赐教。
以上就是怎样运用LINQ、Lambda 表达式 、托付疾速比较两个鸠合,找出须要新增、修正、删除的对象(附代码)的细致内容,更多请关注ki4网别的相干文章!