Сохранение неизменяемых объектов в реляционной базе данных - PullRequest
4 голосов
/ 05 августа 2011

Я видел, как некоторые объектно-ориентированные эксперты советуют, чтобы доменные объекты (POCO) были неизменяемыми.

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

Но, скажем, я сохраняю реляционную БД с помощью ORM - как определить, какие свойства сохранить, и как восстановить объект домена на основе данных в базе данных?

Например, скажем, я хочу записать этот объект в базу данных:

class User
{
    private string _emailAddress;

    public User(string emailAddress, string password)
    {
       // ... generate hash & seed
       _emailAddress = emailAddress;
    }

    public string PasswordHash { get; private set; }

    public string PasswordSeed { get; private set; }

    public bool ValidatePassword(string password)
    {
       // validate it against the stored hash
    }
}

В приведенном выше примере я хочу сохранить состояние объекта и получить его позже. Это означает хранение PasswordHash, PasswordSeed и EmailAddress.

Но структура класса не позволяет мне сделать это.

  • PasswordHash и PasswordSeed - я могу их сохранить, но что произойдет, когда я захочу прочитать их обратно из базы данных и восстановить объект? Там нет параметров конструктора, чтобы передать их, и я даже не могу построить объект без них, потому что должен быть указан «пароль», и я не знаю, какой был оригинальный пароль. Я не могу установить свойства «PasswordHash» или «PasswordSeed», потому что они «закрытый набор».

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

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

Видите, я хотел сохранить пароль в виде хэша / семени и скрыть адрес электронной почты по причине. Я хотел навязать определенный рабочий процесс объектам моего домена.

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


Основная проблема, по-видимому, заключается в том, что реляционные базы данных не имеют понятия инкапсуляции. Каждый столбец в таблице является «общедоступным», а каждое значение - «изменяемым».

Значит ли это, что мне нужно полностью исключить реляционное отображение, если я хочу иметь неизменную модель предметной области? Или есть какая-то известная стратегия для обхода этого, о которой я просто еще не знаю?

Ответы [ 4 ]

3 голосов
/ 05 августа 2011

Прежде всего - неверно утверждение, что доменные объекты должны быть неизменяемыми.
Только значение объектов должно быть неизменным. Скорее всего, пользователь является субъектом.

Обычно ORM использует некоторые приемы, чтобы обойти эту проблему.

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

NHibernate заставляет отображаемые объекты иметь защищенные конструкторы без аргументов, все свойства и методы должны быть переопределены. С помощью этого конструктора объект создается «пустым», а состояние устанавливается через переопределенные свойства.

1 голос
/ 05 августа 2011

Частные поля тоже можно сериализовать - см. http://msdn.microsoft.com/en-us/library/system.serializableattribute.aspx

В вашем случае вы хотите сериализовать значения в БД, а также прочитать их обратно ...Есть несколько способов сделать это, например:

  • Реализовать 2 статических метода в качестве члена класса, которые могут получить доступ ко всем внутренним / частным полям и, таким образом, сериализовать и реконструировать любое поле в классе

  • Реализовать некоторый интерфейс для сериализации / десериализации, который можно использовать в качестве параметра статического метода для уменьшения зависимости между процессом сериализации / десериализации и классом

РЕДАКТИРОВАТЬ - согласно комментариям:

В статических методах вы можете свободно выбирать, какие поля сохранять в БД и как (двоичный файл, XML или один столбец на поле и т. Д.).Просто реализуйте свой интерфейс сериализации / десериализации соответствующим образом.

0 голосов
/ 06 августа 2011

Я бы порекомендовал вам отделить слой вашего домена от слоя данных. Другими словами:

  1. Создайте класс слоя данных , который соответствует непосредственно столбцам вашей таблицы User со всеми открытыми получателями / установщиками, конструктором без параметров и без поведения.
  2. Создать класс доменного уровня , который имеет поведение (т. Е. Методы), не содержит общедоступных сеттеров (если это возможно, чтобы избежать анти-паттерна Модель анемического домена *1011*) и минимальные публичные добытчики.
  3. Создайте класс сопоставления для сопоставления между ними.
  4. (Необязательно, но хорошо, если это приложение большего размера.) Убедитесь, что только класс домена (или в идеале его интерфейс) доступен для внешнего мира. Классы картографирования и данных не предназначены для общего пользования, поэтому не раскрывайте их.

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

0 голосов
/ 05 августа 2011

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

Вот базовый пример того, как это сделатьэто: http://blog.kowalczyk.info/article/Serialization-in-C.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...