Где я должен хранить поля виртуальных / вычисляемых / сложных объектов в моих моделях? - PullRequest
1 голос
/ 23 февраля 2010

У меня есть модели, соответствующие таблицам базы данных. Например, класс House имеет столбцы «color», «price», «square_feet», «real_estate_agent_id».

Мне очень часто хочется отображать имя агента, когда я отображаю информацию о доме. В результате класс моего дома имеет следующие поля:

class House {
  String color;
  Double price;
  Integer squareFeet;
  Integer realEstateAgentId;

  String realEstateAgentName;
}

Я имею в виду realEstateAgentName как виртуальное поле, так как оно извлекается из внешней таблицы (объединение по real_estate_agent_id).

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

В других случаях я обнаруживаю, что делаю что-то вроде этого:

class House {
  String color;
  Double price;
  Integer squareFeet;
  Integer realEstateAgentId;

  RealEstateAgent realEstateAgent;
}

Как видите, я храню фактический объект, соответствующий идентификатору, который хранится в таблице House.

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

У меня есть несколько вопросов:

Из двух методов, которые я смешивал и сопоставлял, какой из них лучше? Я склоняюсь к сохранению id + объекта, а не вытаскиваю только свойства из постороннего объекта, которые, я думаю, могут мне понадобиться. Из двух это кажется более «правильным». Но это не идеально, потому что во многих случаях у меня нет необходимости увлажнять весь посторонний объект, и это может привести к неоправданной растрате ресурсов или не будет осуществимо из-за количества данных или количества объединений, которые требовать, когда у меня нет никакой пользы для всей вводимой информации. Учитывая, что это так, это кажется плохим выбором дизайна, потому что у меня будет много пустых полей, которые на самом деле не равны нулю в моей базе данных, но они так в памяти просто потому, что их не нужно было заполнять - теперь я должен отслеживать, какие из них я заполнил.

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

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

Является ли эта разочаровывающая нечистота моих моделей / классов чем-то, с чем мне просто нужно смириться, или существуют шаблоны, которые решают эту проблему, имея какое-то подклассификация форка или родителя / потомка, где каждый находится " чистый "объект, а другой плоский, как база данных?

РЕДАКТИРОВАТЬ : Я ищу предложения по дизайну, а не конкретные платформы ORM, такие как Hibernate / nHibernate / и т.д. Конкретный язык, на котором я работаю, не имеет решения ORM для моей языковой версии, которой я доволен, и примеры были Java-esque, но это не то, на чем написан мой исходный код.

Ответы [ 3 ]

0 голосов
/ 23 февраля 2010

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

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

class House {
    String color;
    Double price;
    Integer squareFeet;
    RealEstateAgent realEstateAgent;
    // getters, setters,...
}

House house = (House) session.load(House.class, new Long(123));
// at this point, house refers to a proxy object created by Hibernate
// in the background - no house or agent data has been loaded from DB
house.getId();
// house still refers to the proxy object
RealEstateAgent agent = house.getRealEstateAgent();
// house is now loaded, but agent not - it refers to a proxy object
String name = agent.getName(); // Now the agent data is loaded from DB

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

0 голосов
/ 23 февраля 2010

Hibernate, самый популярный инструмент ORM в экосистеме Java, обычно позволяет вам сделать это:

class House {
 String color;
 Double price;
 Integer squareFeet;
 RealEstateAgent realEstateAgent;
}

Это переводит в DB-таблицу, которая выглядит следующим образом: дом (id, цвет, цена, squareFeet, real_estate_agent_id)

Если вам нужно напечатать имя агента, вы просто пройдете по графу объектов:

house.getRealEstatAgent().getName()

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

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

0 голосов
/ 23 февраля 2010

LINQ to SQL использует ID + Object, и он работает хорошо. Я предпочитаю эту модель, так как она наиболее гибкая. Hibernate может сделать то же самое. Одна из проблем, с которой вы столкнетесь, - глубокая загрузка: когда вы на самом деле загружаете объект, а не только идентификатор? И LINQ to SQL, и Hibernate загружаются медленно и дают вам контроль над этой проблемой.

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

Здесь действительно не происходит нечистоты. Проблема в том, что вы пытаетесь представить абстракцию данных, которые являются отношениями, объектно-ориентированным способом. Чтобы обойти трудности такого развития, более масштабные проекты переходят на Domain Driven Design, где базовые данные абстрагируются в логические группы репозиториев. Мышление в таблицах в качестве классов может быть проблематичным для крупномасштабных решений.

Только мои 2 цента.

...