Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений на С++ (1158635), страница 77
Текст из файла (страница 77)
Модель такжеподразумевает наличие операторов для генерации новых таблиц на базестарых: именно таким способом пользователи могут манипулировать даннымии получать информацию из базы" [12].Рассмотрим для примера базу данных склада с радиоэлектроннымитоварами, на котором хранятся резисторы, конденсаторы и микросхемы.Каждый тип продукции в соответствии с предыдущей диаграммой классовобладает уникальным идентификационным номером и описательным именем.Например:productsproductIddescription00817350081736389104390740009074001Resistor, 10 ае 1/4 wattResistor, 10 ае 1/4 wattCapacitor, 100 pF7400 1С quad NAND74LS00 1С quad HANDМы видим таблицу с двумя столбцами, каждый из которыхпредставляет определенный атрибут. В данном случае порядок, в которомрасположены строки (столбцы), не важен; количество строк не ограничено, нокаждая из них должна быть уникальной.
Первый столбец, productID, являетсяпервичным ключом, то есть он может быть использован для однозначнойидентификации детали.Товары поступают от поставщиков; информация о каждом из нихдолжна содержать уникальный идентификатор поставщика, имя компании, ееадрес, и, возможно, телефонный номер. Таким образом, можно составитьследующую таблицу:SuppliersSupplierIDCompanyAddressTelephone00056Interstate Supply2222 Fannin,806-555-0036Amarillo, TX03107Interstate Supply3320 Scott, Santa408-555-3600Clara, CA78829Universal Products 2171 Parfet Ct,303-555-2405Lakewood, CDsupplierID - первичный ключ в том смысле, что им можно однозначноидентифицировать поставщика. Отметим, что все строки в этой таблицеуникальны, однако у двух из них имя поставщика одинаково.Различные поставщики предлагают различные продукты по различнымценам, поэтому мы можем организовать также таблицу стоимости продуктов.Она содержит текущую цену для каждой комбинации товар/поставщик:PricesproductID008173500817350156999777509868896559074001SupplierID031077882978829031070005603107Price$0.10$0.09$367.75$10.69$0.09$1.75В этой таблице нет простого первичного ключа.
Для однозначнойидентификации строк мы должны использовать комбинацию ключейproductID и supplierID. Ключ, образуемый из значений различных столбцов,называется составным. Заметьте, что мы не включили в эту таблицу названиядеталей и поставщиков - это было бы излишним; данную информацию можноотыскать по значениям полей productID и supplierID в таблицах товаров ипоставщиков. Поля productID и supplierID называются внешними ключами,так как они представляют первичные ключи других таблиц.На рис. 10-5 представлена структура классов, соответствующая этимтаблицам. Здесь, для обозначения записей, которые имеют смысл только всовокупности с записями из других таблиц, мы используем ассоциацию сатрибутом. Первичные ключи таблиц заключены в квадратные скобки.Рис.
10-5. Ассоциация с атрибутамиДалее, мы можем проверить состояние склада с помощью таблицы,содержащей количество всех имеющихся в наличии продуктов:InventoryProductIdQuantity008173510000097890200001569993477750984668896551907400192Эта таблица показывает, что объектно-ориентированное представлениеданных системы может отличаться от их представления в базе данных. Всхеме, представленной на рис. 10-4, quantity является атрибутом классаProductRecord, a здесь, в целях обеспечения быстродействия, мы решилиразместить quantity в отдельной таблице.
Дело в том, что, как правило,описание товара (description) модифицируется очень редко, в то время какколичество (quantity) меняется постоянно по мере того, как со складаотгружаются товары и на склад прибывают новые грузы. Для оптимизациидоступа к количеству товара разумнее выделить его в отдельную таблицу.Данная деталь реализации системы, как следует из рис. 10-4, не будетвидна клиентам нашего приложения. Класс productRecord создает иллюзиютого, что quantity является его частью.Самой очевидной и в то же время наиболее важной цельюпроектирования базы данных является построение такой схемы размещенияданных, при которой каждый факт хранится в одном и только в одном месте.При этом не происходит дублирования информации, упрощается процессвнесения изменений в базу данных и поддержания ее целостности(согласованности и правильности данных).
Достигнуть цели не всегда бываетлегко (оказывается, что это и не всегда нужно). Тем не менее, в нашем случаеданное свойство будет очень желательным.Для достижения этой цели (важной, но не единственной [13]) быларазработана специальная теория нормализации. Нормализация есть свойствотаблицы; если таблица удовлетворяет определенным условиям, то мы говоримчто она имеет нормальную форму.
Существует несколько уровнейнормализации, каждый из которых базируется на предыдущем [14]:• Первая нормальная форма (1NF) Каждый атрибут представляетсобой атомарное значение (неразложимые атрибуты).• Вторая нормальная форма (2NF) Таблица приведена в 1NF, и приэтом каждый атрибут целиком и полностью зависит от ключа (функциональнонезависимые атрибуты).• Третья нормальная форма (3NF) Таблица приведена в 2NF, и приэтом ни один из атрибутов не предоставляет никаких сведений о другоматрибуте (взаимно независимые атрибуты).Таблица в третьей нормальной форме "содержит свойства ключа, весьключ и ничего кроме ключа" [15].Все рассмотренные таблицы находятся в 3NF.
Существуют еще болеевысокие уровни нормализации, в основном связанные с многозначнымифактами, но в данном случае они не имеют для нас большого значения.Для того, чтобы связать воедино объектно-ориентированную схему иреляционную модель, иногда нам приходится сознательно нарушатьнормализацию таблиц, внося в них определенную избыточность. При этомнам придется прилагать специальные усилия для поддержания синхронизацииизбыточных данных, однако взамен мы получаем возможность более быстрогодоступа к данным, что для нас важнее.SQLПри работе с объектно-ориентированной моделью, где данные иформы поведения соединены воедино, пользователю может понадобитьсяосуществить ряд транзакций с таблицами.
Он, например, может захотетьдобавить в базу нового поставщика, исключить из нее некоторые товары илиизменить количество имеющегося в наличии товара. Может также появитьсянеобходимость сделать различные выборки из базы данных, например,просмотреть список всех продуктов от определенного поставщика илиполучить список товаров, количество которых на складе недостаточно илиизбыточно с точки зрения заданного нами критерия.
Может, наконец,понадобиться создать исчерпывающий отчет, в котором оцениваетсястоимость пополнения запасов до определенного уровня, используя наименеедорогих поставщиков. Подобные типы транзакций присутствуют почти вкаждом приложении, использующем реляционную базу данных. Длявзаимодействия с реляционными СУБД разработан стандартный язык - SQL(Structured Query Language, язык структурированных запросов). SQL можетиспользоваться и в интерактивном режиме, и для программирования.Самой важной конструкцией языка SQL является предложениеSELECT следующего вида:SELECT <attribute> FROM<relation> WHERE <condition>Для того чтобы, например, получить коды продуктов, чей запас наскладе меньше 100 единиц, можно написать следующее:SELECT PRODUCTID, QUANTITY FROMINVENTORY WHEREQUANTITY < 100Возможно создание и более сложных выборок.
Например такой, гдевместо кода товара фигурирует его наименование:SELECT NAME, QUANTITY FROMINVENTORY, PRODUCTSWHERE QUANTITY < 100 ANDINVENTORY.PRODUCTID =PRODUCTS.PRODUCTIDВ этом предложении присутствует связь, позволяющая как быобъединять несколько отношений в одно. Данное предложение SELECT несоздает новой таблицы, но оно возвращает набор строк. Одна выборка можетсодержать сколь угодно большое число строк, поэтому мы должны иметьсредства для доступа к информации в каждой из них.
Для этого в языке SQLвведено понятие курсора, смысл которого схож с итерацией, о которой мыговорили в главе 3. Можно, например, определить курсор следующимобразом:DECLARE С CURSORFOR SELECT NAME, QUANTITYFROMINVENTORY, PRODUCTSWHEREQUANTITY < 100ANDINVENTORY.PRODUCTID - PRODUCTS.PRODUCTIDЧтобы открыть эту выборку, мы пишемOPEN СДля прочтения записей выборки используется оператор FETCH:FETCH С INTO NAME, AMOUNTИ, наконец, после того, как работа завершена, мы закрываем курсор;CLOSE сВместо использования курсора можно пойти другим путем: создатьвиртуальную таблицу, где содержатся результаты выборки. Такая виртуальнаятаблица называется представлением.
С ним можно работать как с настоящейтаблицей. Создадим, например, представление, содержащее наименованиетовара, имя поставщика и стоимость:CREATE VIEW V (NAME, COMPANY, COST)AS SELECT PRODUCTS.NAME, SUPPLIERS.COMPANY,PRICES.PRICE FROMPRODUCTS, SUPPLIERS, PRICES WHEREPRODUCTS.PRODUCTID . PRICES.PRODUCTID ANDSUPPLIERS.SUPPLIERID - PRICES.SUPPLIERIDИспользование представлений предпочтительнее, так как онопозволяет создавать различные представления для различных клиентовсистемы. Поскольку представления могут существенно отличаться отнизкоуровневых связей в базе данных, гарантируется некоторая степеньнезависимости данных.