Стратегии могут быть нетривиальные. Например, время с лагом менее 5 минут считается одинаковым.
На мой взгляд, явные стратегии в боевом коде читаются и тестируются легче, чем эвристический тест, выставляющий разные значения полей.
Для победы над ошибками сетевого плана, когда одна и та же транзакция передаётся несколько раз, можно использовать ключ идемпотентности, но он не поможет для решения проблемы незначащих изменений.
Это тоже решение. Если атрибута не повешено, то можно падать при старте приложения, например. Вполне валидное решение. Проблема может быть только в том, что атрибутов может быть много и код будет сложно читать. Я не очень люблю аспекты, но это уже вопрос вкуса.
1. Потому что Equals используется нашим ORM (linq to sql) для определения, одна и та же сущность перед ним или нет. Переопределение Equals кодом, который не соответствует сравнению PK сущностей приведет к тому, что ORM перестанет работать :(
2. Не каждое свойство одинаково участвует в определении эквивалентности. Некоторые свойства не сравниваются вообще (например, даты). Некоторые свойства сравниваются сложным образом, как линии. В простом случае можно сгенерировать код при старте приложения. Но это делает код сложнее, например для дебага. Код, который написан в статье, можно дебажить, рефлексия используется только для проверки.
1. Неймконвеншн будет не статически проверяться, мне, если честно, не очень нравится
2. Можно ошибиться в том, что не вызвать такой метод в IsEquivalent
3. В чём именно проще поддержка? В предложенном варианте со стратегиями именно поддержка проще, потому что нужно просто реализовать интерфейс.
4. Научить IsEquivalent ругаться можно, но лучше делать это не в рантайме, а при инициализации приложения. Тогда и с производительностью не будет проблем.
Решение в лоб: давайте напишем код, который при поступлении нового изменения заказа будет среди уже существующих изменений того же заказа искать точно такое же
Вот это разве не то, что вы предлагаете? IsEquivalent — метод класса OrderHistoryItem, то есть сделано, как вы и предлагаете: реализована эквивалентность записей, которые нужно сравнивать. Проблема в поддержке этой эквивалентности.
Visitor — хороший паттерн, но проблемы начинаются, когда нужно расширять количество обходимых классов в другой сборке, отличной от сборки, в которой определен сам Visitor. Тогда в этих наследниках приходится ожидать один тип Visitor'а и делать cast к наследнику, определенному в этой сборке, что не очень приятно. В такой ситуации уже удобнее бывает просто сделать Dictioary<Type, Action>. С таким подходом потеряем в производительности и возможно в читабельности (хотя и не факт, если такой подход используется часто в кодовой базе), зато получим больше гибкости.
Есть ещё решение, которое конечно совсем не серебряная пуля, но в некоторых ситуациях вполне реально: удалить суррогатный ключ. О нём не думаешь сразу, но мы, когда столкнулись с переполнением IDENTITY, поняли, что можем вообще выкинуть суррогатный ключ и ничего не потеряем. Так и сделали и довольны :)
Может конечно возникнуть вопрос, зачем он был изначально :)
У нас на работе все примерно одного возраста, компания всего 60 человек, все друг друга знают, и общаемся друг с другом мы исключительно на ты :)
Это — одна из прелестей небольшой компании, конечно)
Возможно многие просто используют, например, хранимые процедуры для работы из приложения с БД. Не говорю, что это плохо, у всех разные архитектурные принципы. Кому-то важна поддерживаемость кода, кому-то — например скорость. Кто-то просто не решает задачи, где может понадобиться переиспользование кода генерации запросов.
Что касается темы статьи, то мы используем нашу же разработку Mindbox Expressions, в которой есть метод ExpandExpressions, делающий то же самое, только интерфейс чуть поприятнее :-)
Так же есть LINQKit, в котором есть AsExpandable, позволяющий примерно то же самое.
Так и где там пример? Там пара компонентов и всё. Как мне понять, что делает ваш генератор документации, не запуская npm run docs-dev самостоятельно? :)
А какой смысл в такой подборке? Предполагается, что читатель прокликает все утилиты, чтобы понять, что каждая из них делает? Их тут 143 и по названию можно понять дай бог в 10%. Почему бы не добавить хотя бы краткое описание для каждой утилиты?
Ну мне показалось, что переписывать статью ради этого не стоит. Как раз наоборот: тем, кому такой язык комфортен, будет более комфортно читать.
Да ладно вам, в каждой компании какой-то свой диалект. Меня вот бесит слово "совещание")
На мой взгляд, явные стратегии в боевом коде читаются и тестируются легче, чем эвристический тест, выставляющий разные значения полей.
2. Не понял вопрос.
Да, я об этом немного упомянул
2. Не каждое свойство одинаково участвует в определении эквивалентности. Некоторые свойства не сравниваются вообще (например, даты). Некоторые свойства сравниваются сложным образом, как линии. В простом случае можно сгенерировать код при старте приложения. Но это делает код сложнее, например для дебага. Код, который написан в статье, можно дебажить, рефлексия используется только для проверки.
2. Можно ошибиться в том, что не вызвать такой метод в IsEquivalent
3. В чём именно проще поддержка? В предложенном варианте со стратегиями именно поддержка проще, потому что нужно просто реализовать интерфейс.
4. Научить IsEquivalent ругаться можно, но лучше делать это не в рантайме, а при инициализации приложения. Тогда и с производительностью не будет проблем.
Вот это разве не то, что вы предлагаете? IsEquivalent — метод класса OrderHistoryItem, то есть сделано, как вы и предлагаете: реализована эквивалентность записей, которые нужно сравнивать. Проблема в поддержке этой эквивалентности.
Может конечно возникнуть вопрос, зачем он был изначально :)
Это — одна из прелестей небольшой компании, конечно)
Что касается темы статьи, то мы используем нашу же разработку Mindbox Expressions, в которой есть метод ExpandExpressions, делающий то же самое, только интерфейс чуть поприятнее :-)
Так же есть LINQKit, в котором есть AsExpandable, позволяющий примерно то же самое.