TL;DR
Jeśli to nie DDD to nie traktuj tak tego.
Jeśli to DDD to albo trzymaj tę logikę w metodzie typu Update(...) i zwróć czy trzeba czy nie, albo wstrzyknij do metody. Najlepiej jakby się okazało że dane do zmiany to ValueObjecty i można je ze sobą porównać i to one mają trzymać te logikę.
Pełna odpowiedź:
Nie wiem ile wspólnego z samym DDD ma ten problem, ale ja widzę to tak, proszę popraw mnie jeśli źle zrozumiałem. Pokręcę się trochę na około i dojdę do sedna, w którym teraz jesteś pewnie, ale popraw mnie jeśli gdzieś się mylę w założeniu po drodze. MOże to też innym pomoże rozkminiać takie problemy.
(Pomijam główny system na razie) Jest n systemów(albo mikro/makro serwisów jeśli chcemy myśleć o tym w ten sposób), każdy osobno. Jeden z nich (albo każdy, teraz to nie jest ważne) system odczytuje sobie dane z kolejki - te dane to nie jest encja, ale jakieś DTO. Masz też w tym systemie ... ok nazwijmy to Encje. Twój problem to czy należy tą encję zaktualizować, czy nie. I chcesz to zrobić, przez stworzenie nowej encji w kodzie i wywołać porównanie (nie wiem w jakim języku piszesz) np existin == newone albo existing.Equals(newone).
W takim wypadku, jeśli chcemy operować na encjach i koncepcjach z DDD, jedną z podstawowych cech encji jest to, że można je porównać ze sobą na podstawie samego ID, a nie wartości jakie w tym momencie posiada. Posiadanie w systemie dwóch wersji tego samego agregatu z różnymi wartościami to przepis na katastrofę. Generalnie koncepty takie jak Agregate root i Bounded context są po to, żeby tego uniknąć. To czy należy zaktualizować obiekt w bazie danych jest problemem z dziedziny technicznej, a nie domeny biznesowej. Owszem, logika kiedy należy zaktualizować - to jest biznesowa reguła, ale to co chcesz wykonać brzmi jak stricte techniczne. Niemalże CRUD. Ale to może być tylko ułamek systemu i reszta jest skomplikowana, więc psotaram się nie mieć żądnych założeń i odpowiem w dwóch wersjach:
Więc tutaj zostaje mi zasugerowanie albo czegoś stricte technicznego - nie traktuj tego jako encja w DDD, tylko użyj klasy, która może w zasadzie poosiadać tę logikę porównywania do siebie dwóch instancji. I w zależności od rezultatu zapisz lub nie. Dlaczego nie? Ano tutaj pojawia się argument - bo jeśli ten system rzeczywiście używa DDD i to jest encja w agregacie, to powinieneś mieć dostęp tylko przez agregat. I to jest też coś co pominąłeś w swojej wypowiedzi. Rozumiem że chcesz zaktualizować Encję, jeśli to jednocześnie agregat - to spoko. Jeśli nie pamiętaj, że przez ten agregat powinieneś przejść, bo on wyznacza granice dostępu i manipulacji swoimi wartościami. I to założenie w dalszej części wypowiedzi przyjmę. Założę też, że masz już rozwiązany problem konkurencyjności i nie możesz nadpisać stanu agregatu z innej transakcji. (tutaj znów jest mnóstwo rozwiązań technicznych zależnych od problemu).
Mam wiadomość z kolejki, jakiś serwis w aplikacji ją przetwarza(MessageHandler? któy jest też w kontekście OnionArchitecture serwisem aplikacyjnym), ładuje mi agregat z bazy(czy tam skąd trzeba) i wywołuje sobie na niej metodę Update(nazwa powinna być lepsza, plus tu lista parametrów, albo DTO i później
a) metoda jak trzeba to zaktualizuje co tam chce. Żadnego sprawdzania, nadpisanie wartości. Zapisz i zapomnij. Nie ważne czy zmiany były czy nie. To podejście jest naiwne i sprawdzi się tylko jak tych aktualizacji jest mało. Inaczej niepotrzebnie będzie obciążać system.
b) Jako że chcesz wiedzieć czy zapis jest potrzebny czy nie, tutaj pojawia się problem logiki aplikacji, a nie logiki biznesowej. Teraz chciałbyś wiedzieć na poziomie aplikacji czy chcesz robić update i zapis do bazy, czy nie. I tutaj jesteś, i założyłeś ten wątek.
Metoda z porównaniem i nadpisaniem Equals odpada w przypadku encji. Ale co z value objectami? Value object z definicji nie ma identyfikatora a porównujemy przez wartość. Może Twoja encja posiada Value objecty które możesz porównywać, one powinny posiadać nadpisane Equals, i wtedy mamy agregat który ma ma metodę (nazwa z tyłka, zamiast jednego można przesłać więcej value objectów typ zwracany też można rozbudować) np bool Update(ValueObject produkt) i ona tylko sobie porówna te dwa produkty i zamieni jeśli są inne. Jako rezultat zwróci Ci wartość czy dokonał tej aktualizacji, czy nie. Tutaj poszliśmy na skróty trochę, bo moglibyśmy to rozbić na dwie metody NeedsUpdate i Update, ale myślę że to sobie sam ogarniesz co wolisz.
Jeśli jednak to zdecydowanie nie jest Value object i nie przedstawisz tak tego w swojej domenie... To dalej podejśćie z tymi dwiema metodami (albo jedną) jest OK. I tutaj możesz wstrzyknąć właśnie ten HashCalculator, albo trzymać te logikę w metodzie. To zależy od Twoich preferencji i tego co łatwiej będzie otestować.