Технология программирования orm реферат

Обновлено: 07.07.2024

Библиотеки ORM существуют для самых разных языков программирования. В общих чертах, технология ORM позволяет проектировать работу с данными в терминах классов, а не таблиц данных. Она позволяет преобразовывать классы в данные, пригодные для хранения в базе данных, причем схему преобразования определяет сам разработчик. Кроме того, ORM предоставляет простой API- интерфейс для CRUD-операций над данными. Благодаря технологии ORM нет необходимости писать SQL-код для взаимодействия с локальной базой данных. [Источник 1]

Содержание

Достоинства

Среди достоинств ORM выделяют:

  • наличие явного описания схемы БД, представленное в терминах какого-либо языка программирования, которое находится и редактируется в одном месте;
  • возможность оперировать элементами языка программирования, т.е. классами, объектами, атрибутами, методами, а не элементами реляционной модели данных;
  • возможность автоматического создания SQL-запросов, которая избавляет от необходимости использования языка для описания структуры БД (Data Definition Language) и языка манипулирования данными (Data Manipulation Language) при проектировании БД и изменении её схемы соответственно;
  • не нужно создавать новые SQL-запросы при переносе на другую систему управления базами данных, поскольку за это отвечает низкоуровневый драйвер ORM.
  • ORM избавляет от необходимости работы с SQL и проработки значительного количества программного кода, который зачастую однообразен и подвержен ошибкам.
  • код, генерируемый ORM гипотетически проверен и оптимизирован, следовательно не нужно беспокоиться о его тестировании;
  • развитые реализации ORM поддерживают отображение наследования и композиции на таблицы;
  • ORM дает возможность изолировать код программы от подробностей хранения данных.

Недостатки

Среди недостатков ORM выделяются:

Альтернативы

Касательно альтернатив технологии ORM, то среди них выделяются:

  • сознательное нарушение нормализации таблиц в реляционной модели, которое, хотя и приводит к избыточности данных наряду с появлением необходимости их синхронизации, обеспечивает преимущество ускорения доступа к данным;
  • подход CoRM (Collection-Relational Mapping — реляционное отображение коллекций), при котором осуществляется объединение разрозненных коллекций объектов с помощью хорошо определенных реляционных взаимоотношений между коллекциями и прототипом которого могут служить документ-ориентированные СУБД (например, MongoDB);

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

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

ORM — это инструмент решения проблемы семантического провала между реляционной и объектной моделями данных. Имеющий, однако, определенные проблемы, которых должны быть лишены его альтернативы, позволяющие вывести объектную сущность приложения из ограничений, накладываемых реляционным хранилищем. [Источник 3]

Пример с использованием FlexORM

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

Используйте библиотеку FlexORM. Это проект с открытым кодом, предоставляющий технологию ORM (Object Relational Mapping, реляционное отображение объектов) разработчикам AIR-приложений.

Определение отображения объектов

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

В следующем примере имеется один класс, определяющий закладку браузера. Он имеет свойства id, name, url и notes:

Тег метаданных [Bindable] уже знаком вам, поскольку определен в ядре плат- формы Flex. Однако теги [Table] , [Column] и [Id] специфичны для библиотеки FlexORM. Тег метаданных [Table] указывает, что помеченный им класс управляется с помощью библиотеки FlexORM. Вы можете указать имя таблицы в качестве аргумента тега метаданных, но это, вообще говоря, необязательно. Тег [Id] определяет поле, используемое в качестве первичного ключа объекта. Библиотека FlexORM предоставляет средства генерирования первичного ключа, так что вам не нужно беспокоиться по поводу определения этого значения. Наконец, тег метаданных [Column] позволяет вам указать имя столбца для соответствующего ему свойства. В большинстве случаев необходимость в этом теге отсутствует. Если он опущен, в качестве имени столбца по умолчанию берется имя свойства.

Использование класса EntityManager

В библиотеке FlexORM определен класс EntityManager, который управляет всеми CRUD-операциями для всех классов, находящихся под управлением библиотеки. Этот класс существенно облегчает операции создания, чтения, обновления и удаления экземпляров классов, снабженных тегом [Table] .

Первое, что вы должны сделать, — это корректно настроить класс Entity- Manager. Прежде чем он сможет выполнять какие-либо операции, вы должны будете передать ему экземпляр класса SQLConnection:

В этом коде класс EntityManager конфигурируется на использование файла базы данных bookmarks.db, размещенного в том же каталоге, что и приложение. После установки свойства sqlConnection вы можете выполнять над данными операции CRUD. [Источник 4]

Класс EntityManager позволяет без труда читать элементы указанного типа. Достаточно передать класс, который вы хотите прочитать, методу findAll() класса EntityManager:

Сохранить экземпляр класса с помощью класса EntityManager столь же просто:

Процедура удаления экземпляра выполняется аналогичным образом, но требует от вас указания класса, а также свойства id удаляемого экземпляра:

Создание законченного приложения

Объединив приведенные ранее фрагменты кода, вы можете создать законченное приложение, выполняющее операции CRUD исключительно с использованием класса EntityManager. В следующем примере браузер сохраняет закладки (как бы- ло показано выше). В дополнение к приведенному здесь MXML-файлу вам потре- буется SWC-файл библиотеки FlexORM (поместите его в каталог построения) и класс Bookmark, определенный ранее в этом рецепте (разместите его в пакете vo): [Источник 5]

Объект можно сравнивать с черным ящиком. Фокусник кладет в него платочек, говорит заветное заклинание, и вытаскивает кролика. Так же и мы. Мы можем инициализировать объект, или он сам инициализируется значениями по умолчанию, вызвать нужный метод объекта, и получить результат. Нас мало интересует то, что в нем конкретно происходит, если объект уже достаточно хорошо отлажен. Основная идея объектно-ориентированного подхода заключается в наличие интерфейса, который служит для полиморфного обращения с объектом и его потомками. За счет наличия интерфейса легко достигается повторное использование кода. Многие программисты, переходящие от процедурного программирования к объектно-ориентированному программированию справедливо замечают, что они могут сделать все то же самое и без использования объектов. Объектно-ориентированное программирование - это всего лишь соглашение о правилах построения программ. Вся мощь объектной ориентации раскрывается в крупных проектах, или при написании большого количества однотипных программ, например программ, работающих с базами данных. За счет повторного использования кода достигается простота в работе программиста (накопление опыта), сокращается размер программы (методы объектов одного типа или методы, наследуемые от предков потомками существуют в единственном экземпляре), самодокументируемость, а значит и больше простоты при отладке (объекты описываются в определенном месте программы отдельно от реализации), простота сопровождения программы (не меняя интерфейс объекта, Вы можете изменить реализацию методов) и т.д. Но, это только в идеале. На самом деле достаточно просто извратить постулаты объектной ориентированности. Все зависит от правильности и лаконичности дерева наследования Вашей библиотеки объектов. Нам повезло, Мы можем использовать в своей работе последнее достижение в области объектно-ориентированного программирования - продукт компании Borland-Inprise Delphi.При дальнейшем чтении текста, если Вам будет сразу что-то непонятно, то продолжайте читать дальше. В такой сложной теме трудно последовательно изложить все по порядку, т.к. многие вопросы переплетаются с более сложными и наоборот. По ходу чтения текста, Вы составите полное представление о теме.

Объектно-ориентированное программирование.

Объект в Delphi представляет из себя специальную структуру, которая описывает поля, свойства и методы объекта - class. Предком для всех объектов служит class Tobject. Давайте рассмотрим простой объект.

AmyField: Integer; // Свойство

Procedure SetMyField(Val: Integer); // Процедуразаписисвойствакласса

Constructor Create; // Конструктор

Destructor Destroy; override; // Деструктор

Property MyField: Integer read AmyField write SetMyField; // Свойствокласса

Имена классов принято начинать с буквы T, но это просто соглашение, а не правило. Вы можете назвать Ваш объект как хотите. Однако, буква Т в начале имени класса - это правило хорошего тона. Далее, указывается, что этот класс является потомком от Tobject. Если Вы запишите TmyClass = class, то все равно ваш класс будет потомком от Tobject. Далее, идет закрытая часть интерфейса класса. Здесь объявляются свойства и методы класса, которые будут доступными только из методов этого же класса, и будут недоступными для других классовых методов и из других модулей программы. При наследовании класса, потомок тоже не будет иметь доступа к закрытой части интерфейса. Иногда, такое поведение класса неудобно. Например, при большом количестве обращений к списку данных одного класса из другого через открытую часть интерфейса, при каждом обращении, возможно, будут проверяться допустимые границы индекса списка. Это правильно, но может значительно замедлить работу программы, поэтому было бы неплохо иметь возможность для ограниченного числа классов или функций разрешить доступ к закрытой части, чтобы они могли обращаться к свойствам класса, объявленным в закрытой части. Возможно, Вы писали на С++ и знаете, что там такие классы и функции называются друзьями. В Delphi эта возможность реализуется через объявление дружественных классов и функций в одном модуле программы, т.е. все друзья должны быть объявлены в одном модуле. Далее, идет защищенная часть. Она отличается от закрытой тем, что из потомка класса, Вы можете иметь доступ к этой части. Далее, идет открытая часть интерфейса. Здесь Вы можете объявить свойства и методы класса, которые будут доступны для других классов, процедур и функций. Есть еще одна часть интерфейса - published (опубликованная). Эта часть имеет место у потомков от Tcomponent. Delphi использует эту часть интерфейса в инспекторе объектов. При доступе к классу во время выполнения программы, эта часть ничем не отличается от public. Здесь имеет смысл объявлять свойства и события класса. Все свойства и события будут доступны из инспектора объектов, и Вы сможете редактировать их во время разработки. Чтобы работать с классом, Вы должны объявить переменную объектного типа этого класса, затем инициализировать ее вызовом конструктора.

TmyClass = class(TObject) // Объявлениекласса

AmyClass: TmyClass; // Объявление переменной класса

AmyClass:=TmyClass.Create; // Вызов конструктора, обратите внимание на то, что вызывается конструктор// TmyClass.Create, а не AmyClass.Create

Классы в Delphi могут создаваться только в динамической памяти, поэтому все переменные объектного типа - это указатели на экземпляр класса в динамической памяти. Типичное имя конструктора - Create, типичное имя деструктора - Destroy. Придерживайтесь этого правила, если нет особой необходимости в обратном.

Инициализация и разрушение объектов

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

constructor Create(AOwner: TComponent); override; // перегружаемконструкторпредка

Constructor TmyClass.Create(AOwner: TComponent);

Inherited Create(Aowner); // Вызов конструктора предка

… // Дальнейшая инициализация объекта

Если имя конструктора предка совпадает с именем потомка, то можно сократить запись при вызове конструктора предка в конструкторе потомка:

Constructor TmyClass.Create(AOwner: TComponent);

Inherited (Aowner); // Вызов конструктора предка

… // Дальнейшая инициализация объекта

Для уничтожение объекта служит деструктор. Деструктор объявляется с помощью зарезервированного слова destructor, после которого идет имя деструктора. Деструктор ничего не возвращает и не имеет параметров. Я советую Вам вместо прямого вызова деструктора использовать метод Free. Этот метод есть у всех классов в Delphi, т.к. наследуется от Tobject. Этот метод сначала проверяет неравенство указателя на класс nil, а затем только вызывает Destroy. Это более безопасный способ уничтожить объект.unit MyUnit;

constructor Create(AOwner: TComponent); override; // перегружаемконструкторпредка

destructor Destroy; override // Перегружаемдеструкторпредка

Inherited Destroy; // Вызов деструктора предка, для уничтожение закрытых полей предка

Инкапсуляция

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

AmyField: Integer; // Объявление поля целого типа

Procedure SetMyField(Val: Integer); virtual; // Объявление процедуры для записи значения свойства

Property MyField: Integer read AmyField write SetMyField; // объявлениесвойства

Здесь мы видим, что свойство MyField является целым типом. Оно доступно для чтения и записи, т.к. объявлены методы read и write. Процедура, организующая запись значения объявлена в секции protected для того, чтобы в случае необходимости, Вы могли перегрузить ее в потомке. На самом деле значение свойства хранится в поле AmyField класса. Если Вы не объявите метода write, то свойство станет доступным только по чтению, аналогично и с методом read. К слову говоря, поля для хранения значения свойства может и не быть, главное, чтобы были объявлены методы доступа к нему. Для примера, класс, реализующий интерфейс доступа к свойствам дисплея, мог бы иметь свойства ширина и высота в пикселях. Вам не обязательно хранить эти значения, т.к. можно вызвать стандартную функцию Windows и узнать ширину и высоту экрана, тем более, что в процессе работы эти значения могут меняться при переключении в другой режим. Методы записи и чтения свойства подчиняются жестким правилам. Так для чтения свойства, Вам необходимо объявить функцию без формальных параметров, возвращающую значение того же типа, что и свойство. Для записи значения, Вам необходимо объявить процедуру с одним параметром того же типа, что и свойство. Если в качестве метода для записи или чтения свойства Вы указываете имя поля для хранения значения свойства, то это аналогично прямому доступу к этому полю. При компиляции такого способа обращения к свойству, код будет оптимизирован, поэтому это не повлечет никаких дополнительных расходов ресурсов компьютера. Обычно, такой метод обращения к полю применяют для чтения. Методы доступа к полям класса могут выполнять дополнительную работу при переустановке значения поля класса. Так, при установке свойства Ttable.Active в true производится чтение данных из таблицы базы данных на жестком диске, несколько раз меняется состояние объекта, посылаются события связанным объектам, вызываются обработчики делегированных событий, которые пишет программист, и только потом переустанавливается значение свойства в true. Для присвоения свойству значения по умолчанию, используется ключевое слово default, например:

property Visible: boolean read Avisible write SetVisible default true;Это значит, что при запуске программы, компилятор установить это свойство в true. Однако я настоятельно рекомендую Вам устанавливать значение свойств по умолчанию в конструкторе класса.Вы можете иметь индексированные свойства. Вот пример реализации такого класса.

AmyList: Tlist; // Контейнеруказателей

Function GetMyList(Index: Integer): Pointer; // Функциядоступапочтению

Procedure SetMyList(Index: Integer; Val: Pointer); // Процедурадоступапозаписи

Property MyList[Index: Integer]: Pointer read GetMyList write SetMyList; // Объявлениеиндексированногосвойства

Здесь мы видим, что свойство MyList индексированно - это элемент списка указателей. В квадратных скобках Вам нужно указать список индексов и их типов. В общем случае, индексом может быть даже строка символов. Далее идет тип свойства и методы записи и чтения. Функция чтения должна иметь список формальных параметров со всеми индексами свойства и возвращать значение того же типа, что и свойство. Процедура записи должна иметь список формальных параметров со всеми индексами свойства и параметр для передачи устанавливаемого значения того же типа что и свойство. Большое значение имеет последовательность указания индексов и обязательность передачи значения свойства в процедуре записи последним в списке формальных параметров. Если индексированное свойство является основным и обращение именно к нему производится чаще остальных, то можно объявить его как default, тогда не нужно указывать имя свойство для доступа к нему, например:

AmyList: Tlist; // Контейнеруказателей

Function GetMyList(Index: Integer): Pointer; // Функциядоступапочтению

Procedure SetMyList(Index: Integer; Val: Pointer); // Процедурадоступапозаписи

Property MyList[Index: Integer]: Pointer read GetMyList write SetMyList; default; // Объявлениеиндексированногосвойствапоумолчанию

MyClass [3]:=AnyObject; // Аналогично MyClass.MyList[3] ]:=AnyObject;

Значение инкапсуляции в объектно-ориентированном программировании трудно переоценить. Чего стоит хотя бы то, что в Delphi к 100% полей классов доступ организован через свойства.

Наследование

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

Constructor Create(Val: Integer); virtual;

Constructor Create(Val: Integer); override; // Перегрузиликонструктор

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

Поля, свойства и методы секции public не имеют ограничений на видимость.

Поля, свойства и методы секции private, доступны только в методах класса и в функциях, объявленных в том же модуле, где и класс.

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

При описании потомков, Вы можете изменять область видимости методов и свойств. Можно расширять область видимости, но не сужать. Т.е. если есть свойство в секции private, вы можете сделать его public, но не наоборот. Вот пример расширения области видимости:

property MyField: Integer read AmyField;

Property MyField; // Только упомянули его в другой секции и он поменял область видимости.

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

procedure MyMethod(Val: Integer); virtual; abstract;

Статические методы и поля в объектах-потомках перекрываются одинаково: Вы можете без ограничений перекрывать старые имена и при этом изменять тип методов, т.к. при перекрытии будет создано новое поле или метод с тем же именем. Перекрытый метод предка доступен в потомке через зарезервированное слово inherited.Type

procedure MyMethod(Val: Integer);

…procedure TmySunClass.MyMethod(Val: Integer);begin

inherited MyMethod; // Метод предка без параметров, а метод потомка уже с параметром, т.е. мы поменяли тип процедуры.

По умолчанию все методы - статические, поэтому их адреса известны уже на стадии компиляции, они будут вызываться при выполнении программы самым быстрым способом. Виртуальные и динамические методы описываются с помощью специальных директив virtual или dynamic. Эти методы могут быть перекрыты в потомке одноименными методами, имеющими тот же тип.

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

Полиморфизм

Указателю на экземпляр объектного типа может быть присвоен адрес любого экземпляра любого из дочерних типов. При обращении к свойствам и методам через этот указатель будет доступен именно экземпляр, адрес которого был присвоен, а не предок. Это и есть полиморфизм. Т.е. Вы можете иметь доступ к потомку через указатель объектного типа предка. Рассмотримпример:

Что такое ORM?
ORM или Object-relational mapping (рус. Объектно-реляционное отображение) — это технология программирования, которая позволяет преобразовывать несовместимые типы моделей в ООП, в частности, между хранилищем данных и объектами программирования. ORM используется для упрощения процесса сохранения объектов в реляционную базу данных и их извлечения, при этом ORM сама заботится о преобразовании данных между двумя несовместимыми состояниями. Большинство ORM-инструментов в значительной мере полагаются на метаданные базы данных и объектов, так что объектам ничего не нужно знать о структуре базы данных, а базе данных — ничего о том, как данные организованы в приложении. ORM обеспечивает полное разделение задач в хорошо спроектированных приложениях, при котором и база данных, и приложение могут работать с данными каждый в своей исходной форме.


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

Преимущества и недостатки использования
Использование ORM в проекте избавляет разработчика от необходимости работы с SQL и написания большого количества кода, часто однообразного и подверженного ошибкам. Весь генерируемый ORM код предположительно хорошо проверен и оптимизирован, поэтому не нужно в целом задумывается о его тестировании. Это несомненно является плюсом, но в тоже время не стоит забывать и о минусах. Основной из них — это потеря производительности. Это происходит потому, что большинство ORM предназначены для обработки широкого спектра сценариев использования данных, гораздо большего, чем любое отдельное приложение когда-либо сможет использовать. Вопрос о целесообразности использования ORM по большому счету затрагивается только в больших проектах, которые сталкиваются с высокой нагрузкой, здесь приходится выбирать что более приоритетно — удобство или производительность? Конечно, работа с БД посредством грамотно написанного SQL-кода будет намного эффективнее, но не стоит забывать и о таком параметре, как время — то, что с легкостью пишется с использованием ORM за неделю, можно реализовывать ни один месяц собственными усилиями. Кроме того, большинство современных ORM позволяют программисту при необходимости самому задавать код SQL-запросов. Без сомнений, для небольших проектов использование ORM будет куда более оправдано, чем разработка собственных библиотек для работы с БД.


Рассказать всем Twitter Facebook Delicious StumbleUpon E-Mail


Warning: count(): Parameter must be an array or an object that implements Countable in /var/www/u0420283/data/www/internetka.in.ua/wp-includes/class-wp-comment-query.php on line 405

Свежие записи

Поиск

Рубрики

Метки

Реклама

Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.

Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.

Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.

Donec in mi a arcu cursus commodo non ut metus. Nunc id eros ut augue consequat tempus ut non ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Integer pretium, erat sit amet scelerisque euismod, purus lectus convallis dui, eget imperdiet sapien est ut magna. Nullam elementum, tortor vitae pulvinar mattis, orci neque porta tortor, a feugiat nisi lacus quis diam. Ut gravida augue id est rutrum elementum. Mauris eget felis dolor. Phasellus ante ante, porttitor sit amet lobortis ut, suscipit id neque. Fusce hendrerit dolor nec odio eleifend in auctor enim cursus. Nullam fermentum pretium risus, in hendrerit nulla cursus sit amet. Fusce eu tempus elit. Ut tortor velit, aliquam in ornare vel, feugiat sed nibh. Donec fringilla est id odio lacinia vulputate. Donec nulla urna, congue sit amet pretium non, dictum at orci. Fusce neque sem, fermentum eu tempus nec, mattis venenatis sem. Proin scelerisque velit tristique urna mattis adipiscing. Proin mattis faucibus facilisis. Integer non lacus ac ligula accumsan convallis quis molestie erat. Curabitur imperdiet vestibulum vulputate. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris lacus ligula, hendrerit eget suscipit in, sollicitudin nec dui. Suspendisse euismod, lorem pretium gravida rhoncus, enim quam facilisis orci, nec volutpat nisi dolor id lacus. Proin dolor arcu, rutrum eget hendrerit vel, pharetra id elit. Nullam porta euismod suscipit. Pellentesque malesuada consequat sem, et auctor magna aliquam gravida. Nullam blandit dignissim iaculis. Suspendisse non diam nec augue scelerisque iaculis. Nam id dui sed lorem vulputate rhoncus eget eu tellus. In sit amet nisi nunc. Fusce sed aliquet sem. Aliquam sit amet metus metus.

Объектно-реляционное отображение. ORM-фреймворки. Загрузка по требованию как шаблон проектирования. Способы расширения классов-сущностей. Внедрение в байт-код. Загрузка полей и свойств сущностей в detached состоянии. Механизм пакетной выборки.

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 07.07.2012
Размер файла 1,1 M

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

СОДЕРЖАНИЕ

ВВЕДЕНИЕ

На сегодняшний день в подавляющем большинстве случаев для хранения данных используются реляционные базы данных. В приложениях на языке Java для взаимодействия с базами данных, используется интерфейс JDBC, который предоставляет минимальный функционал для исполнения запросов к базе данных на языке SQL и обработки их результатов. JDBC может оперировать с БД в терминах строк, таблиц и отношений, однако в таком виде с данными на уровне приложения работать чаще всего неудобно. Проще, когда эти данные представлены в виде объектов и связей между ними. Задача отображения структуры объектов модели предметной области (с которой программист работает на уровне приложения), на реляционную модель данных (с которой работают реляционные базы данных), решается в рамках объектно-реляционного отображения (object-relational mapping, ORM). Логика этого отображения может быть реализована с использованием различных фреймворков объектно-реляционного отображения (ORM-фреймворков), при этом создается эффект “виртуальной объектной базы данных”, взаимодействие с которой, осуществляется не в терминах таблиц, строк и отношений, а в терминах объектов и связей между ними. Использование ORM-фреймворков ограждает разработчика от написания большого количества однообразного и подверженного ошибкам кода, а также от особенностей конкретной реляционной базы данных, тем самым, во многом упрощая разработку более гибких и проще расширяемых приложений. Но даже с использованием ORM-фреймворков разработчик не может полностью абстрагироваться от некоторых особенностей реализации объектно-реляционного отображения.

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

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

Чтобы исключить подобное неэффективное поведение системы используется подход, при котором момент загрузки определенных полей объекта откладывается до той поры, пока их значение не будет необходимо. Этот подход носит название “lazy loading” (“отложенная загрузка”, “ленивая загрузка” или “загрузка по требованию”) и позволяет минимизировать количество обращений к базе данных.

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

1. ОПИСАНИЕ ПРЕДМЕТНОЙ ОБЛАСТИ

1.1 Объектно-реляционное отображение. ORM-фреймворки

Подход, при котором логика хранения данных отделена от логики непосредственного использования этих данных, распространен уже давно. Такое разделение позволяет разработчикам в каждой области сосредоточиться на предмете своей специальности, помогая разрабатывать и поддерживать масштабные системы проще и быстрее. С другой стороны, более сложным становится аспект взаимодействия этих двух компонент.

В подавляющем большинстве случаев, сегодня, для хранения данных, используются реляционные базы данных. Для взаимодействия Java-приложений с БД используется интерфейс JDBC, реализуемый разработчиками соответствующих баз данных. Через этот интерфейс, разработчик конечного приложения может осуществлять SQL-запросы к базе данных и обрабатывать их результаты, то есть оперировать с данными в том виде, в котором они представлены в базе данных, в терминах таблиц, строк и отношений (relations). Java же, как язык объектно-ориентированный, предполагает работу в рамках модели предметной области (domain model) в терминах объектов и связей между ними. Механизм объектно-реляционного отображения (object-relational mapping, ORM), связывает базы данных с концепциями объектно-ориентированных языков программирования таким образом, что создается эффект “объектной базы данных”, с которой можно взаимодействовать на уровне приложения в терминах объектов и связей.

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

Далее представлены три самых широко используемых на сегодняшний день Java ORM-фреймворка. Вместе они предоставляют во многом схожий функционал, но каждый реализует его по-своему. Каждый из них сейчас основан на проекте с открытым исходным кодом (open source).

1.1.1 Hibernate

Из всей тройки наиболее широко распространен и имеет самое большое сообщество разработчиков. Разрабатывается JBoss community под эгидой Red Hat. Поставляется вместе с JBoss Application Server.

1.1.2 EclipseLink

Разрабатывается сообществом Eclipse Foundation. Основан на исходных кодах проекта TopLink 11g, переданных в открытое пользование компанией Oracle. Является эталонной реализацией (reference implementation) JPA 2.0, и поставляется вместе с сервером приложений GlassFish.

1.1.3 OpenJPA

Под этим именем (OpenJPA) часть кода была пожертвована Apache Software Foundation проектом Kodo, который помимо JPA также реализовывал спецификацию JDO.

1.1.4 Java Persistence API

Каждый из вышеописанных фреймворков реализует спецификацию Java Persistence API -- стандарт взаимодействия с базами данных в приложениях на Java SE и Java EE.

JPA как технология, обеспечивает объектно-реляционное отображение простых Java объектов (POJO) и предоставляет API для сохранения, получения и управления такими объектами. Первая версия JPA разрабатывалась как часть спецификации EJB3 и увидела свет с выходом Java EE 5 в 2006 году.

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

Спецификация JPA в себя включает:

? Набор программных интерфейсов (API), позволяющий организовать взаимодействие с JPA провайдером.

? Платформенно-независимый объектно-ориентированный язык запросов Java Persistence Query Language (JPQL).

? Метаданные, с помощью которых определяются основные правила отображения объектов Java на таблицы реляционной БД. Для описания этих правил используются либо XML файлы, либо аннотаций Java 5.

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

Помимо этого каждый из JPA провайдеров (даже EclipseLink, который сейчас носит статус Reference Implementation для JPA 2.0) предоставляет расширенный функционал для работы со специфическими особенностями различных схем баз данных.

1.2 Загрузка по требованию, как шаблон проектирования

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

Объектная модель приложения и реляционная модель базы данных должны обмениваться данными и несовпадение схем, делает эту задачу нетривиальной. Не всегда загрузка одного объекта предполагает выполнению одного SQL-запроса. Более того, как правило, объекты модели тесно связаны между собой, поэтому загрузку данных в память следует организовать таким образом, чтобы при загрузке интересующего вас объекта из базы данных автоматически извлекались и другие связанные с ним объекты. Это значительно облегчает жизнь разработчика, которому в противном случае необходимо организовывать загрузку всех связанных объектов вручную. [1. c.220]

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

Для решения этой проблемы и одновременной минимизации влияния на объекты, расположенные в памяти, слой отображения использует шаблон lazy loading ("ленивая загрузка" или "загрузка по требованию"), согласно которому, процесс загрузки прерывается на определенном моменте, оставляя соответствующую метку в структуре объектов. Это позволяет загрузить необходимые данные только тогда, когда они действительно понадобятся. [1. c.220]

Согласно [1] существует четыре основных способа реализации механизма загрузки по требованию:

? Lazy Initialization ("ленивая инициализация" или "инициализация по требованию")

? Virtual Proxy ("виртуальный прокси-объект")

? Value Holder ("контейнер значения" или "диспетчер значения")

? Ghost ("призрак" или "фиктивный объект")

Рисунок 1. Загрузка по требованию.

Самый простой из них -- инициализация по требованию (Lazy Initialization). Основная идея данного подхода заключается в том, что при попытке доступа к полю выполняется проверка, не содержит ли оно значение null. Если это так, соответствующий метод доступа (get-метод) загружает значение поля и лишь затем, возвращает его значение. Данный подход, однако, может быть использован только в том случае, если поле является самоинкапсулированным, то есть если доступ к такому полю осуществляется только посредством get-метода даже в рамках самого класса.

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

Виртуальный прокси-объект (Virtual Proxy) имитирует объект, являющийся значением поля, однако в действительности ничего в себе не содержит. В этом случае загрузка реального объекта будет выполнена только тогда, когда будет вызван один из методов виртуального прокси-объекта. Преимуществом виртуального прокси-объекта является то, что он "выглядит" как реальный объект, который должен находиться в данном поле. Тем не менее, это не настоящий объект, и если этого не учитывать (например, при реализации метода equals()) можно столкнуться с проблемой идентификации.

Описанных проблем можно избежать, если использовать шаблон, который носит название “контейнер значения” или "диспетчер значения" (Value Holder). Контейнер значения -- это объект, который играет роль оболочки для какого-нибудь другого объекта. Чтобы получить значение базового объекта, необходимо обратиться за ним к контейнеру значения. При первом обращении контейнер извлекает всю необходимую информацию из базы данных. Этот способ имеет ряд недостатков. Во-первых, класс должен знать о наличии контейнера значения, а во-вторых, теряются преимущества строгой типизации.

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

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

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

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

1.3 Java EE и Spring

Веб-приложения на Java для своей работы требуют наличия определенного окружения. Это может быть либо контейнер сервлетов (Tomcat, Jetty и др.), либо сервер приложений (Glassfish, JBoss AS и др.). Выбор того или другого из вариантов продиктован, во многом, масштабом приложения и необходимостью использования определенных сервисов. Контейнер сервлетов предоставляет лишь базовый набор сервисов и библиотек, которые доступны внутри приложения, и отлично подойдет для малых приложений, не создающих большого трафика. Корпоративные системы большого масштаба предъявляют к системе более серьезные требования. Например, такие системы часто используют для своей работы несколько физических серверов. Работая в рамках сервера приложений, разработчик получает такие сервисы как кластеризация, отказоустойчивость и балансировка нагрузки прямо “из коробки”, и может сфокусироваться только на реализации бизнес-логики приложения.

Читайте также: