Что делает этот код
IEnumerable<Boat> newBoats = updatedBoats.Where(c=> oldBoats.Any(d =>d.GetId() != c.GetId()).ToList()
примерно означает: «дайте мне все обновленные лодки, чей идентификатор не соответствует хотя бы одному из старых идентификаторов лодок». Это не то, что вы хотите. Логика, которую вы хотите, это «дать мне все обновленные лодки, чей ID не совпадает ни с одним из старых идентификаторов лодок», и это правильно указано @zeroef:
var newBoats = updatedBoats.Where(u => !oldBoats.Any(o => o.GetId() == u.GetId()));
// This is O(o * n) for # of old boats * # of updates that are new boats, and something like O((o/2)*n) for # of old boats * number of updated old boats
Тем не менее, обратите внимание на мой комментарий. Это было бы более эффективно реализовано с использованием HashSet<T>
:
// This is O(n) for # of updated boats
var newBoatIds = new HashSet<Int32>(updatedBoats.Select(b => b.GetId()));
// This is O(n) for # of old boats
newBoatIds.ExceptWith(oldBoats.Select(b => b.GetId()));
Это значительно уменьшает количество вложенных итераций, и вы увидите разницу, если у вас много лодок (и особенно если у вас много новых лодок в вашем обновлении).
Подход HashSet работает для идентификаторов, но вы можете также заставить его работать для самих сущностей, если вы реализуете Equals () и GetHashcode () в классе Boat, используя идентификатор для сравнения.