Как обрабатывать нуль при сравнении равенства значений объектов? - PullRequest
4 голосов
/ 01 декабря 2010

Примечание: я использую C # в качестве примера, но проблема практически та же в Java и, возможно, во многих других языках.

Предположим, вы реализуете объект значения (как в шаблон объекта значения М. Фаулера ), и у него есть некоторое обнуляемое поле:

class MyValueObject
{   
    // Nullable field (with public access to keep the example short):
    public string MyField;
}

Затем, при переопределении Equals (), как вы обрабатываете случай, когда оба объекта-значения имеют свой набор MyFieldобнулить?Они равны или нет?

В C # обработка их как равных кажется очевидной, потому что:

  1. Это поведение Equals () при использовании структуры C #вместо класса и не переопределяют Equals ().

  2. Следующие выражения верны:

    null == null
    object.ReferenceEquals(null, null)
    object.Equals(null, null)
    

Однако в SQL (по крайней мере, на диалекте SQL Server *, NULL = NULL - ложь, тогда как NULL is NULL - истина.

Мне интересно, какая реализация ожидается при использовании преобразователя O / R (в моем случае, NHibernate).Если вы реализуете "естественную" семантику равенства C #, могут ли быть какие-либо побочные эффекты, когда преобразователь O / R сопоставляет их с базой данных?

Или, может быть, в любом случае неправильное использование полей, допускающих значение NULL, в объектах значений?

Ответы [ 3 ]

1 голос
/ 01 декабря 2010

Поскольку ORM знают реляционную модель, они обычно предоставляют способ запроса с использованием семантики SQL.

Например, NHibernate предоставляет оператор is [not] null в HQL и Restrictions.Is[Not]Null в критериях.

Конечно, есть API, в котором эти парадигмы сталкиваются: LINQ.Большинство ORM пытаются делать правильные вещи при сравнении с NULL (то есть, заменяя на is null), хотя в некоторых случаях может иметь проблемы, особенно если поведение не очевидно.

0 голосов
/ 01 декабря 2010

Я думаю, у вас есть две проблемы:

Во-первых, вам нужно знать, равен ли один экземпляр MyValueObject другому экземпляру.

И, во-вторых, как это должно переводиться внастойчивость.

Я думаю, что вам нужно взглянуть на них по отдельности, так как кажется, что вы пытаетесь связать их слишком близко друг к другу, что, как мне кажется, нарушает некоторые принципы DDD - домен не должен знать / заботиться опостоянство.

Если вы не уверены в эффекте null значения MyField, либо (a) он должен вернуть другой тип, отличный от string;(б) сделать так, чтобы он возвращал производную string, такую ​​как EmptyString (или аналогичную реализацию Special Case );(c) или переопределите метод Equals и укажите точно, что это означает, что эти экземпляры равны.

Если ваш ORM не может перевести определенное выражение (которое включает MyValueObject) в SQL, то, возможно, егохорошо, чтобы выполнить более сложную работу на уровне персистентности (пусть сравнение происходит из перевода SQL - да, проблемы с производительностью, которые я знаю, но я уверен, что их невозможно решить), в пользу поддержания чистоты вашей доменной модели.Мне кажется, что решение должно происходить из «что лучше для модели предметной области».

@ Джеймс Андерсон делает хорошую мысль.Зарезервируйте null для состояний ошибки и сбоя.Я думаю Особый случай кажется все более уместным.

0 голосов
/ 01 декабря 2010

Лично я считаю, что если он может быть нулевым (в коде без ошибок), то они должны рассматриваться как равные. Однако, если он не должен быть нулевым (то есть: имя для покупателя или почтовый адрес для доставки), то он никогда не должен быть нулевым.

...