Подтвердить что ты не робот

DDD: первичные ключи (идентификаторы) и ORM (например, NHibernate)

Почему считается, что у OK есть поле Id в объектах домена? Я видел несколько решений, которые предоставляют базовый класс Id и Id на основе GetHashCode/Equals.

Мое понимание модели домена заключается в том, что она должна содержать только вещи, связанные с доменом. Хотя в редких случаях (отслеживаемые заказы) идентификаторы имеют смысл, большую часть времени они не предоставляют ничего, кроме простого способа ссылки на объекты в DB/on UI.

Я также не вижу преимуществ Equals/GetHashCode, так как реализация Identity Map должна гарантировать, что ссылочное равенство равно. Идентификатор равенства в любом случае.

Странно, я не могу легко найти то, что другие люди думают по этому вопросу, поэтому я спрашиваю его здесь. Каково общее мнение об использовании идентификаторов, не связанных с доменом, в объектах домена? И есть ли какие-либо проблемы с NHibernate, если я не добавляю идентификаторы в свои объекты домена?

UPDATE:

Спасибо за ответы.

Некоторые из них предполагают, что идентификатор - единственный способ для ORM выполнить обновление БД. Я не думаю, что это так. ORM уже отслеживает все сущности, загруженные из БД, поэтому он должен легко получить идентификатор внутри, когда ему это нужно.

ОБНОВЛЕНИЕ 2:

Ответ на правосудие и аналогичные вопросы: Что делать, если у нас есть веб-приложение и нужен способ ссылки на объект между сеансами? Как edit/resource/id?

Ну, я вижу это как особую потребность в ограниченном пользовательском интерфейсе/среде, а не в необходимости модели домена. Для этого сценария достаточно иметь сервис приложений или репозиторий с методом GetIdentitity (в соответствии с методом Load (identity)).

4b9b3361

Ответ 1

Я просто могу поговорить о NHibernate. Там вам нужно поле для первичного ключа, это зависит от вас, если вы берете бизнес-данные (не рекомендуется) или суррогатный ключ без каких-либо деловых целей.

Типичные сценарии:

  • значение автоинкремента, генерируемое базой данных
  • guid, созданный NHibernate
  • guid, созданный бизнес-логикой

Существует большое преимущество иметь уникальный идентификатор.. Когда вы передаете свой объект вокруг, например, клиенту и обратно на сервер, вы не можете полагаться на идентификатор памяти. У вас может быть даже несколько экземпляров в памяти одного и того же бизнес-экземпляра. Бизнес-экземпляр идентифицируется идентификатором.

Сравнение на основе Id - это вопрос вкуса. Лично мне нравится простой и надежный код, а сравнение на основе идентификаторов просто и надежно, в то время как глубокое сравнение всегда немного рискованно, подвержено ошибкам, не поддается контролю. Таким образом, вы в конечном итоге получаете оператор ==, сравнивающий идентификатор памяти и Equals, сравнивающий идентификатор бизнеса (и базы данных).

NHibernate - это менее интрузивный способ сопоставить модель класса с реляционной базой данных, которую я знаю. В нашем крупном проекте у нас есть первичные ключи и свойства версии (они используются для оптимистической блокировки). Вы можете утверждать, что это навязчиво, потому что оно не используется для бизнес-логики.

NH не требует наличия этих свойств. (однако для этого требуется одно из свойств в качестве первичного ключа.) Но учтите:

  • Это просто работает лучше, например. пессимистическая блокировка возможна только с соответствующим свойством,
  • быстрее: int id работает лучше во многих базах данных, чем другие типы данных
  • и проще: использование свойств со смыслом для бизнеса не рекомендуется по нескольким причинам.

Итак, зачем делать вашу жизнь труднее, чем нужно?


Изменить: Просто прочитайте документацию и обнаружили, что NHibernate выполняет не свойство id в постоянном классе! Если у вас нет указателя, вы не можете использовать некоторые функции. Рекомендуется иметь его, он просто упрощает вашу жизнь.

Ответ 2

Как правило, у вас не будет одной настоящей модели домена. Вы будете иметь бесчисленные параллельные и последовательные сеансы, которые должны быть скоординированы, и каждая из них содержит в себе собственную миниатюрную изолированную транзакционную модель домена. У вас не будет одинаковых экземпляров объектов между двумя одновременными или между двумя последовательными сеансами. Но вам нужно будет каким-то образом убедиться, что вы можете перемещать информацию из одной сессии в другую.

Примером, конечно, является пара URL/resource/list и /resource/show/id URL (соответствующая соответствующей паре действий контроллера в asp.net mvc). Переходя от одного к другому, есть два полностью независимых сеанса, но им нужно общаться (через HTTP и браузер) друг с другом.

Даже без использования базы данных объекты вашей модели домена по-прежнему будут нуждаться в какой-то форме, поскольку у вас все еще будет множество миниатюрных изолированных моделей домена, а не одна истинная модель домена; и вы будете иметь все эти модели домена в независимых сеансах одновременно и один за другим.

Идентичность объекта не достаточна, поскольку объекты не совпадают между сеансами, хотя базовые концептуальные объекты, которые они представляют, являются одним и тем же объектом.

Ответ 3

В Nh вы не можете использовать ссылочное равенство для отдельных экземпляров. Это заставляет вас использовать NH в клиентах, которые хотели бы использовать это поведение (на мой взгляд, это правильное поведение, NH не зависит от магии!).

В веб-приложениях или на основе сеанса, где вы можете перейти на db в рамках одного ISession, я думаю, что я прав, говоря, что вы можете положиться на ссылочное равенство. Но в сценарии смарт-клиента, или, более конкретно, в любом сценарии, в котором два ISessions делят экземпляр (один загружается из или добавляется в db, затем передается ко второму), вам нужно поле (-ы) db id, хранящееся вместе с экземпляр.

второй сеанс ниже не знал, что экземпляр, который он передал, уже вставлен и требует обновления, и даже если вы изменили его на обновление, я предполагаю, что я прав, думая, что он не собирается знать идентификатор базы данных класса.

class SomeEntityWithNoId
{
public  blah etc {}
}

class dao
{

void DateMethod()
{
var s1 = sessionFactory.OpenSession();
var instance = new SomeEntityWithNoId();
instance.Blah = "First time, you need to insert";
s1.Save(s1); //now instance is persisted, has a DB ID such as identity or Hilo or whatever
s1.close();
var s2 = sessionFactory.OpenSession();
s2.Blah = "Now update, going to find that pretty hard as the 2nd session won't know what ID to use for the UPDATE statement";

s2.Update(instance); //results in boom! exception, the second session has no idea *how* to update this instance.




}
}

Если вас беспокоит поле (и) идентификатора, которое вы считаете правильным в мышлении, в значительной степени бесполезно для чего-либо, кроме проблем с сохранением, вы можете сделать их частными, поэтому, по крайней мере, это поведение и семантика инкапсулируются. Вы можете обнаружить, что этот подход вносит некоторые трения в TDD.

Я думаю, что вы правильно относитесь к картам ID по NH. Если экземпляр является переходным, когда он впервые подключен к сеансу, ваш тип не должен хранить свой идентификатор базы данных в поле. Я думаю, что сессия будет знать, как управлять этим отношением с db. Я уверен, что вы можете опробовать тест, чтобы доказать это поведение, p

Ответ 4

Вы должны иметь это так или иначе, чтобы ORM мог вернуться в базу данных для выполнения обновлений; Я предполагаю, что он может быть закрытым и скрытым в базовом классе, но этот вид нарушает концепцию POCO.

Ответ 5

Предполагая, что ваш идентификатор является вашим основным ключом, вы не сможете сохранить данные обратно в БД без него.
Что касается equals и GetHashCode, то они предназначены для упорядочения в списках, где вы создаете пользовательский порядок.

Спасибо за ответы.

Некоторые из них предполагают, что идентификатор - единственный способ для ORM выполнить обновление БД. Я не думаю, что это так. ORM уже отслеживает все сущности, загруженные из БД, поэтому он должен легко получить идентификатор внутри, когда ему это нужно.

Я был бы очень удивлен, если бы это было так. Обычно он создает оператор insert только из свойств, которые вы определили.

Ответ 6

Нет другого способа получить один и тот же объект без идентификации. Например, люди имеют номер социального страхования или личный код или что-то уникальное, и мы можем идентифицировать их им.

Вы можете использовать естественную идентификацию, но это подвержено ошибкам.

Просто переименуйте идентификатор в идентификатор. Он выглядит лучше в модели домена.

Сущности называются объектами, поскольку они имеют идентификатор.

Ответ 7

Я обычно включаю Id в домен в качестве базового класса Entity. Я не знаю другого способа использовать ORM.

Объект в домене уже уникален по своей ссылке, использование идентификатора для определения уникальности/равенства на самом деле не так уж и отличается на практике. До сих пор я не сталкивался с серьезным побочным эффектом этого подхода.

Ответ 8

Вы также можете использовать несколько полей для установления идентификатора, называемого составными ключами. Это потребует больше работы с вашей стороны.

Узнайте о них здесь