DAO дизайн и структура данных - PullRequest
2 голосов
/ 22 декабря 2011

В моем Java-приложении я хочу реализовать уровень абстракции для операций с базой данных.Я не хочу связывать свое приложение с какими-либо базами данных (реализация может быть произвольной: SQL, XML, на основе документов, куча некрасивых текстовых файлов и т. Д.)

Между сущностями много связейв большинстве случаев отношение 1-ко-многим.

Обновление и отказ от ответственности: хотя примеры просты, они являются лишь частью всей более сложной модели, у которой есть реальные шансы невписывается в модель ORM / SQL (как из-за большого количества данных: ~ несколько миллиардов записей при нормализации по отношениям, так и из-за различной природы данных).Здесь я спрашиваю о реализации простых отношений, но это не значит, что они составляют единственную проблему приложения.

Упрощенный пример следующий:

public class Vehicle {
    String mark;
    String model;
    String registrationId;
}

public class Depot {
    String name;
    String address;
}

Каждоеиз этих объектов есть свой собственный интерфейс DAO:

public interface VehicleDAO {
    List<Vehicle> getVehicles();
    Vehicle getVehicleByRegistrationId(String registrationId);
}

public interface DepotDAO {
    List<Depot> getDepots();
    Depot getDepotByName(String name);
}

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

И вот интересная часть приходит.Отношение между депо и транспортным средством 1-ко-многим.Поэтому я должен реализовать эти отношения как в своих классах сущностей, так и в методах DAO.

Сейчас у меня есть два подхода к этому:

  • place List<Vehicle> свойство внутри DepotКласс и заполнить его всякий раз, когда я выбираю Depot экземпляр (с возможными улучшениями ленивых выборки).Таким образом, интерфейсы DAO не изменяются.
  • вводит специальные идентификаторы для Depot и Vehicle, так что классы сущностей получают дополнительные целочисленные свойства int id;, и мы добавляем метод в DAO List<Vehicle> getVehiclesForDepot(int depotId).Этот подход может быть улучшен путем введения специальных классов для идентификаторов вместо простых целых чисел.

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

1 Ответ

1 голос
/ 22 декабря 2011

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

// load object of DAO type T
<T> load(id)
// load objects of DAO type T
List<T> load(List<id>)
// load all objects of DAO type T
List<T> find()
// load multiple objects of DAO type T
List<T> find(relation)

и т. Д., Если вы используете согласованный тип id (например, long), вы можете определить interface, охватывающий ваши базовые методы.

Чтобы загрузить отношения, у вас есть несколько вариантов, которые лучше всего зависят от вашего использования объектов и их отношений:

  • сделать List<T> атрибутом держателя данных и заполнить его как часть load()

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

  • сделать List<T_id> атрибутом держателя данных и заполнить его как часть load()

Это работает для умеренного количества отношений, используемых вместе с load(List<id>) методами для доступа к связанным сущностям.

Для больших объемов данных, поскольку вы упоминаете, что это основная часть проблемы, которую вы пытаетесь решить, вы можете разделить отношения немного дальше и использовать методы DAO, такие как:

// retrieve related entity id's for this DAO T
List<id> loadIds(T)

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

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

// fill entity relations for T2 to this DAO tyoe T
void fill(T2)

Метод T::fill() будет использовать геттеры на T2 для получения данных, необходимых для определения связанных сущностей (или их id) для загрузки, и один или несколько сеттеров для хранения этой информации в T2 объект держателя данных.

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

...