Стратегии разработки баз данных

В

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

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

Поиск

примечаниеСуществуют два различных метода, с помощью которых в JBuilder можно осуще­ствлять поиск по записям в наборе данных. Один из них предполагает использова­ние компонента JdbNavField, Который находится на закладке More dbSwing палит­ры компонентов. Второй способ связан с применением методов Locate И Lookup Компонента QueryDataSet. Мы по очереди обсудим каждый способ, начав с JdbNavField.

Ни в коем случае не путайте JdbNavField И JdbNavToolBar!

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

JdbNavField Простой в использовании компонент, разработанный компанией Borland, с помощью которого можно осуществлять поиск в строках набора данных. В строковых полях он производит инкрементальный поиск, переходя, по мере ввода значения пользователем, на следующее ближайшее подходящее значение в наборе данных. Например, если пользователь вводит "J", он попадает на первую запись, в которой значение в определенном поле начинается с символа "J". Если пользова­тель вводит "Ja", он попадает на первую запись, где в данном поле содержится зна­чение, начинающееся с "Ja", и т. д.

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

■ Создание примера приложения, взаимодействующего с базами данных, при помощи мастера или инструментов JBuilder.

ВЫВОД Набора Данных B JdbTable.

■ Помещение компонента JdbNavField и определение QueryDataSet в каче­стве значения его свойства dataset.

■ Запуск приложения на выполнение.

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

Компонент JdbNavField имеет свойство CoiumnName, которое можно использо­вать для перемещения фокуса на определенное поле, независимо от того, в каком столбце пользователь выполнил щелчок кнопкой мыши. Если вы будете применять поле CoiumnName, Пользователь потеряет возможность динамически изменять поле, по которому должен осуществляться поиск. Вместо этого, элемент управления будет жестко закодирован на использование выбранного вами поля.

Ниже представлено более подробное описание этапов создания тестовой про­граммы, использующей JdbNavField:

■ Создайте новый проект.

■ Выберите в меню пункт File I New ∣ Data Module. Убедитесь, что опция Invoke Data Modeler отмечена.

■ Находясь в Data Modeler, выберите базу данных jbbook (эта база данных была описана в главе 39).

■ Выберите таблицу HOUSEADDRESS и щелкните на кнопке Сору АН.

■ Выберите в Data Modeler пункт меню File ∣ Save, а затем File ∣ Exit.

■ Выберите в меню пункт File ∣ New ∣ Data Module Application. Для того чтобы со­здать приложение, щелкните на кнопке OK на первой странице мастера.

■ Скомпонуйте свое приложение, после чего через панель проекта выберите из пакета DataModuiei. twotier автоматически сгенерированный компонент HouseAddressUIBean.

■ Переведите HouseAddressUIBean в режим конструирования и удалите элемент управления навигацией, расположенный в верхней части окна приложения.

■ Находясь в палитре компонентов, перейдите на закладку More dbSwing и вы­берите компонент JdbNavFieId. Поместите его в панели структуры на узел this. Поле nav должно занять то место, которое перед этим занимал элемент управ­ления навигацией.

■ Щелкните на кнопке эллипсиса для свойства constraints компонента JdbNavFieId, чтобы вызвать диалоговое окно GridBagLayout. Для свойства fill в нижней части диалогового окна установите значение Both. Закройте диалого­вое окно GridBagLayout. Выберите свойство dataset и установите для него зна­
чение dataset. Выберите свойство CoIumnName и с помощью выпадающего списка установите для него значение NAME.

■ Теперь необходимо настроить JBuilder таким образом, чтобы при щелчке на зеленой кнопке запуска происходил запуск только что созданного приложе­ния. Выберите в меню пункт Project ∣ Project Properties и перейдите на заклад­ку Run. Щелкните на кнопке New и установите DataModuIeITwoTierApp в каче­стве главного класса своей программы.

■ Запустите приложение и введите что-нибудь в компонент JdbNavField. На­пример, попробуйте ввести Sam, как показано на рисунке 43.1.

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

NavTool Это такая программа-пример, в которой может оказаться полезной возможность перетаскивания столбца в новую позицию. Например, на рис. 43.2 по умолчанию столбец HomeState Является последним столбцом набора данных. C по­мощью мыши я расширил и перетащил его, так чтобы он находился рядом со столб­цом Name. Эта возможность встроена в компонент JdbTabie.

Поиск с помощью методов Locate и lookup

Второй способ выполнения поиска в наборе данных связан с использованием метода Locate. Ниже показано объявление этого метода в том виде, в котором оно представлено В Com. Borland. Dx. Dataset. DataSet:

public final boolean locate(readrow rowlocate, int iocateoptions),рис. 43.2. компонент jdbnavtool можно настроить так, что в результате щелчка на каком-нибудь поле в сетке jdbtable будет выбираться соответствующий столбец для осуществления поиска

Рис. 43.1. Использование компонента JdbNavTool Для осуществления поиска по полю NAME Таблицы HouseAddress

Ранее мы уже сталкивались с объектом ReadRow, но теперь мы рассмотрим его го­раздо подробнее. ReadRow Представляет собой класс, разработанный для того, что­бы организовать доступ только для чтения к одной строке из набора данных. Его со­провождает объект ReadWriteRow, который организует доступ, как для чтения, так и для записи.

Большинство методов объекта ReadRow являются методами извлечения значе­ний, специально созданными для работы с каждым из существующих типов, под­держиваемых столбцами набора данных:

Public final byte getByte(int ordinal)

Public final boolean getBoolean(int ordinal)

Public final java. sql. Date getDate(int ordinal) public final int getlnt(int ordinal)

Public final String getString(int ordinal)

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

GetString(4) ; // Отсчет от нуля, поэтому пятый столбец имеет номер 4

Кроме того, доступ к методам можно осуществлять не только по номеру столбца, но и по его имени. Например, если у вас есть база данных с полями Code, FirstName, LastName, Address И Zip, ВЫ Можете ПОЛУЧИТЬ Доступ К ПОЛЮ FirstName Следующим образом:

String FirstNameGetString("FirstName");

Объект ReadWriteRow, Кроме того, имеет набор методов присвоения значений, соответствующий методам извлечения значений. Объекты ReadRow И ReadWriteRow Способны копировать себя в другую строку. Это приводит к дублированию строки.

К настоящему моменту можно легко понять, как работает метод locate. Вы создае­те и заполняете значения для объекта ReadRow, A DataExpress Пытается найти объект:

Public void IocateField(String colName, String searcħStr)

∕∕ Создание объекта DataRow, Определяющего ту строку,

// Которую Мы Хотим Найти

DataRow datarow = new DataRow(address, colName);

// Вставка Поисковой Строки В DataRow datarow. setstring(colName, searchStr);

// Поиск Новой Строки

Address. locate(datarow, options);

)

В данном примере Address Представляет собой переменную стандартного типа QueryDataSet, Который мы уже много раз обсуждали в предыдущих нескольких гла­вах. В данном примере метод locate по умолчанию находит первый экземпляр строки, содержащей последовательность символов, которую мы ищем. Это опреде­
ляется параметром Options Метода Locate. Содержимое переменной Options Будет обсуждаться далее в этой главе.

Вы могли заметить, что этот код работает с DataRow, А не с ReadRow Или ReadWriteRow. DataRow Является потомком класса ReadWriteRow, Предназначенным для выполнения поиска, вставки и обновления.

Также обратите внимание на то, что в коде при создании DataRow Используется переменная Address Типа QueryDataSet:

DataRow datarow = new DataRow(address, СоIName);

Это необходимо для того, чтобы гарантировать, что строка будет корректно рабо­тать с конкретным набором данных. Если структура набора данных во время выполне­ния программы претерпела изменения, потребуется создать новый экземпляр DataRow.

Вряд ли вы будете удивлены тем, что поиск можно выполняять по нескольким полям:

Public void IocateFirstLasttString firstName, String IastName)

{

// Имя столбца, в котором следует искать String FirstColName = "FNAME";

String IastColName = "LNАМЕ";

// Создание объекта DataRow, Определяющего ту строку,

// которую мы хотим найти

DataRow datarow = new DataRow(address,

New String[] {firstColName, IastColName));

∕∕ Вставка Поисковой Строки В DataRow datarow. setstring(firStColName, firstName); Datarow. setstring(IastColName, IastName);

// Поиск Новой Строки

Address. locate(datarow, options);

)

B этом коде объект DataRow Содержит два столбца. Один предназначен для поис­ка по полю имени, а другой — для поиска по полю фамилии. Это позволяет выпол­нить гораздо более специфический поиск.

Помимо параметра DataRow, Метод Locate Принимает также параметр Option Типа Locate:

interface locate,{
public
public
public
public
public
public
public
static
public
public
static
)
,static final int partial = 0x1;
static final int next = 0x2;
static final int prior = 0x4;
static final int case_insensitive = 0x8;
static final int first = 0x20;
static final int last = 0x40;
static final int fast = 0x80;
final int detail = 0x100;
static final int next_fast = next i fast;
static final int prior_fast = priori fast

,final int start_mask = (first∣last∣next∣prior);

Этот интерфейс в некоторой степени является интуитивным. Например, его первый член, partial, позволяет выполнять поиск по частичному совпадению в строковых столбцах. Например, "Ja" будет соответствовать слову "Java". Кроме того, можно выполнить поиск следующего или предыдущего совпадающего экземп­ляра. Опция fast позволяет использовать значения из предыдущего поиска, что несколько уменьшает время поиска. Опции start_mask и detail предназначены для внутреннего использования механизмом DataExpress. Можно комбинировать поля интерфейса Locate с помощью символа потока |:

Private final static int options = Locate. CASE_INSENSITIVE ∣

примечаниеLocate-FIRST ∣ Locate. PARTIAL;

Интерфейс Locate может стать источником ряда неприятностей. В час­тности, он не включен в компилированную версию dx. jar для версий JBuiIder 6 и JBuiIder 7 (и выше). В результате могут возникнуть сложности при запуске из командной строки программ, использующих этот интерфейс. Одно из решений упомянутой пробле­мы заключается в использовании Archive Builder для создания JAR-файла, включающего соответствующий исходный код. Другое решение состоит в том, чтобы взять код из катало­га src и создать свою собственную версию файла Locate. class. Все эти опции будут об­Суждаться в разделе этой главы, посвященном созданию JAR-файлов с базами данных.

рис. 43.3. поиск данных в таблице addressВ сопровождающих книгу материалах вы найдете программу-пример под назва­нием ElfAddress. Пример кода, рассмотренный нами, был взят как раз из этой программы.

Диалоговое окно поиска программы ElfAddress показано на рис. 43.3. Диало­говое окно, очень похожее на это, присут­ствовало в программе из предыдущей главы.

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

Ниже представлен код из LookupDialog, который вызывает методы, выполняющие поиск:

∕∕ DMod — экземпляр модуля данных

DMod dMod;

If (dlgState = DialogState. FIRST_ONLY)

{

DMod. IocateFirst(jTextFieldFirstName. getText());

}

Else if (dlgState ≈= DialogState. LAST_ONLY)

{

DMod. IocateLast(JTextFieldLastName. getText());

}

Else

{

DMod. IocateFirstLast(JTextFieldFirstName. getText(), JTextFieldLastName. getText());

)

Как вы, вероятно, помните из предыдущей главы, тип Diaiogstate Представляет собой "перечислимый класс", предназначенный для эмуляции перечисляемых ти­пов в Java-программах.

В листинге 43.1 приведен код нескольких методов модуля данных, которые вы­полняют поиск различного рода.

Листинг 43.1. Методы поиска данных в наборе данных. Первые три метода используют метод locate, тогда как четвертый метод обращается к методу lookup

Private final static int options =

Locate. CASE_INSENSITIVE Locate-FIRST Locate. PARTIAL;

Public void IocateField(String colName, String searchStr)

{

∕∕ Создание объекта DataRow, Определяющего ту строку,

// Которую Мы Хотим Найти

DataRow datarow = new DataRow(address, colName);

11 Вставка Поисковой Строки В DataRow datarow. setstring(colName, searchStr);

// Поиск Новой Строки

Address. locate(datarow, options);

>

Public void IocateFirst(String searchStr)

{

IocateField("FNAME", searchStr);

}

∕**

* Поиск строки в наборе данных

*

* Gparam searchStr Искомая строка */

Public void IocateLast(String searchStr)

{

IocateFieldCLNAME", searchStr);

}

∕**

* Найти строку в наборе данных и осуществить переход на эту позицию

*

* Gparam firstName Искомое имя

* Gparam IastName Искомая фамилия */

Public void IocateFirstLast(String firstName, String IastName)

<

∕∕ ИМя столбца, в котором следует искать String FirstColName = "FNAME";

String IastColName = "LNAMEn;

// Создание объекта DataRow, Определяющего ту строку,

// Которую Мы Хотим Найти

DataRow datarow = new DataRow(address,

New String[] (firstColName, IastColName));

∕∕ Вставка Поисковой Строки В DataRow datarow. setstring(firstColName, firstName); Datarow. setstring(IastColName, IastName);

// Поиск новой строки

Address. locate(datarow, options);

У**

* Поиск строки в наборе данных. Данная опция находит строку, но не

* переходит на нее.

*

*

* @param SearchStr Искомая строка */

Ptιblic void IookupFirstLast (String fIrstName, String IastName)

{

// Имя столбца, в котором следует искать String IastColName = "LNAME";

String fIrstColName = ,, FNAME;

// Создание строки, которую следует найти DataRow rowToFind = new DataRow(address,

New String[] {fIrstColName, IastColName));

∕∕ Вставка Поисковых Строк В DataRow rowToFind. setstring(fIrstColName, firstName);

RowToFind. setstring(IastColName, IastName);

// Создание Объекта DataRow, Содержащего Возвращенную Строку DataRow returnRow ≈ new DataRow(address);

// Поиск Новой Строки Со Специальными Опциями Address. lookup(rowToFind, returnRow, options);

// Вывод Результатов

System. out. println("row: ” + returnRow. getString(IastColName) +

", " + ReturnRow.GetString(FirstColName));

примечаниеВы наверняка заметили, что в самом последнем методе я выбросил джокер. На первый взгляд этот метод очень похож на предыдущий, IocateFirstLast. Однако в последнем методе я вызвал Lookup, А не Locate. Различие между ними состоит в том, что Lookup Возвращает копию найденной им строки, не переходя на нее. Ме­тод Locate, Наоборот, не возвращает копию строки, однако перемещает курсор на­бора данных на найденную строку. Метод Locate Следует использовать в тех случа­ях, когда пользователь хочет видеть определенную строку, а метод Lookup Когда необходимо написать код для поиска определенной ячейки, который должен вы­полняться в фоновом режиме.

Курсор базы данных указывает на строку набора данных, выбранную в данный момент. Одно из свойств набора данных в JBuiIder заключается в том, что он поддерживает понятие курсора. Курсор можно перемещать при помощи методов First (), last () F next() HpriorQ.

Подстановки и списки выбора

Я собираюсь перейти к обсуждению инструмента под названием Подстановка (lookup), или Список выбора (picklist).

Подстановка немного похожа на отношение "один ко многим" тем, что она опре­деляет соединение между двумя таблицами на основе определенных полей. Кроме того, в басах данных она является своего рода эквивалентом перечислимого типа. В JBuilder подстановку также называют списком для выбора.

примечаниеКак вы увидите, подстановка является достаточно простым понятием. Основная задача, которую вам предстоит выполнить, не особенно сложна. По не вполне понятным мне причинам, в JBuiIder все сделано так, что использование подстановки в про­грамме является довольно-таки утомительным занятием. По моему мнению, эта сфе­ра — одна из тех, в которых JBuiIder оказался явно не на высоте. Тем не менее, вы може­Те овладеть этим вопросом, если повозитесь с ним какое-то время.

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

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

Хороший

Плохой

Отвратительный

Первое поле таблицы rating потребуется сделать первичным ключом.

В своей главной таблице вам может понадобиться произвести оценку нескольких

Пунктов путем числовой подстановки из таблицы rating:

1

-+-

I

Клинт Иствуд

I

—J__

Blondie

-+-

I

1

2

ɪ

I

_Х_

Ли Ван Клиф

T

I

. _х_

Sentenza

I

_ ɪ

2

3

T

I

Х_

Эли Валлах

I

. —х—

Tuco

T

I

3

4

—г—

I

-+-

Серджио Леоне

I

Director

I

1

В данной таблице четвертый столбец представляет собой столбец подстановок из таблицы rating. Числа в четвертом столбце относятся к строкам таблицы rating. Число 1 соответствует строке со словом "Хороший" и т. д.

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

В общем-то, вторую таблицу можно было бы организовать следующим образом:

1

I

Клинт Иствуд

I

. _Х_

Blondie

I

_Х_

Хороший

2

ɪ

I

_ 4__

Ли Ван Клиф

— —ɪ-

I

._Х_

Sentenza

ɪ

I

-X —

Плохой

3

ɪ

I

4- —

Эли Валлах

I

I

. — X —

Tuco

ɪ

I

.х_,

Отвратительный

4

I

-+-

Серджио Леоне

T

I

Director,

ɪ

I^

.+1

Хороший

Есть три причины, по которым вторая версия слабее первой:

■ Слова "Хороший", "Плохой" и "Отвратительный" занимают больше места, не­жели числа 1, 2 и 3.

■ При вводе значений "Хороший", "Плохой" и "Отвратительный" пользователь может допустить опечатку.

■ В конечном итоге, пользователи могут начать вводить свои собственные кате­гории, например "Отличный" или "Утонченный". (Если вы видели эти филь­мы, то вряд ли сочтете приемлемым применение в отношении них такой ка­тегории, как "Утонченный"!)

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

Проблема с вставкой в таблицу чисел, таких как 1, 2 и 3, заключается в том, что они сами по себе бессмысленны. Это как раз та проблема, которую и призваны раз­решить перечисляемые типы. Если вы свяжете число 1 со словом "Хороший", вы мо­жете просто использовать слово "Хороший" везде, где вам нужно сослаться на число 1. Во многих случаях мнемоника подобного рода может помочь предотвратить пута­ницу. Тем не менее, следует предусмотреть некоторое средство связи числа 1 со сло­вом "Хороший", иначе пользователи попросту запутаются.

Для решения упомянутой проблемы и предназначены поля подстановки: Они делают маленькое чудо, а точнее ловкий трюк, который позволяет одновременно использовать в четвертом столбце этой таблицы и число 1, и слово "Хороший". Да­вайте-ка разберемся, в чем, собственно, дело.

Поле подстановки вставляет выпадающий список значений непосредственно в объект JdbTabie. В данном случае он вставит выпадающий список в четвертое поле таблицы.

Когда пользователь хочет внести изменения в четвертое поле этой таблицы, он может просто выбрать соответствующее значение из выпадающего списка, ко­торый автоматически появляется в самой таблице JdbTable. Вы можете видеть соответствующий пример на рисунке 43.4. Здесь таблица подстановок содержит слова "Неизвестный", "Компакт — диск", "Лента” и т. д., а не "Хороший", "Плохой" и "От­вратительный". Однако сама теория, на которой основана эта технология, остается не­изменной. Вместо того что­бы видеть числа, пользовате­лю предоставляется список строк, из которых он может выбирать.

примечаниеСоздание программы, содержащей подстановки

В этом разделе вы столкнетесь с таблицами и полями, имеющими оди­наковые имена: LOUDNESS, MEDIUM и TYPES. При написании кода здесь все достаточно просто и понятно. Однако при чтении иногда может возникнуть путаница. Я постараюсь указывать особо, когда говорю о поле, а когда о таблице. Также я представлю некото­Рые специальные примеры, которые помогут провести ясное различие между ними.

Для того чтобы создать свою собственную программу подстановки наподобие той, что показана на рис. 43.4, вы можете использовать таблицы album, loudness, medium и types из базы данных jbbook. Процесс создания базы данных jbbook под­робно описан в главе 39. Таблица album содержит список альбомов. В таблице есть три поля подстановки, называющиеся loudness, medium и types. Все они являются полями целочисленного типа (integer). Таблица loudness ("громкость звучания") содержит значения ДЛЯ Подстановки, такие как Peaceful (спокойно), Moderate (умеренно) и Loud (громко). Таблица medium ("носитель") показана на рис. 43.4. Таблица types ("тип") содержит такие значения, как Classical (классика), Jazz (джаз), Folk (народная), New Age (молодежная) и т. д.

Для начала создайте новый элементарный проект и добавьте в него приложение. Выберите в меню пункт File ∣ New DataModuIe и отключите опцию Invoke Data Modeler. Щелкните на кнопке OK для того, чтобы создать модуль данных по умолчанию.

В панели содержимого переместите фокус на модуль данных и перейдите в ре­жим конструирования. В палитре компонентов перейдите на закладку DataExpress и поместите в узел Data Access в панели структуры компоненты Database и QueryDataSet. Присвойте базе данных имя jbbook, а компоненту QueryDataSet — имя queryDataSetAlbum, как показано на рис. 43.5.

Щелкните на кнопке эллипсиса для свойства connection объекта jbbook. Щелк­ните на кнопке Choose Existing Connection (Выбрать существующее соединение) и выберите соединение с базой данных Jbbook, Как описывалось в главах 39 и 42. Вве­дите пароль и протестируйте соединение, как показано на рис. 43.6.

JBiiHder — G:/5r< JavaMlIUrHHkdsAHiUttedI J∕src∕untHled19∕DaVιModule1.jav<ι

file edit search view project run team wizards iools window help
□ is g∖'⅛ `h i> <]`ɔ •••» ⅜ ∙ *
⅜∙ «* &
,Ξj∙¾ ‰ Λ⅛∙,jp untitled19.∣px .s∙<f untitled 19
г r⅛ applicationl java ; & datamoduiei java
∣j⅛ frame1 java
lj £ft..untitledt9.html
,j < ’ «-
untitle... ’
,f# untided1 s-datamoduiei ; ’ ∙□ ut ! ?• '.jmenu ⅛ dataaccess ∣ i i - ♦ myom ! : Γ £5 )bb0q⅛ 
1 . fe Γ
,' ⅛ j] other ■ ~∙ this,∣lue∣vd 3taselalpurr∣,.~j⅜ datamodulei ∣ χ⅛ framel ∣
swing j swing containers ∣ bvenware omaexpress ) cbswing ∣ mor; ju
,u ierydateseta smumulater-jfaise datafile,•1“,⅛⅛sb!⅛s5jds* 1,editable [true
enabledeiete [true
,e∩ablelnsert !τrue,bnahtnupdate ,true,locale,properties j pvents j
source design beanΓuml{⅛ocj history i
рис. 43.5. настройка объектов database и querydataset в простом модуле данных

рис. 43.6. создание соединения с базой данных. вы должны были научиться настраивать существующее соединение в главе 39

fi uucry fχj

Query, ParainetereI

Datatiaee:_______

JjbbOOk ‘ l^…….. "’l""j

SQLBuIrtIer… I Browse Tables .. j

SQLstatement

’SELECT ALBΠH. COPE, AlBUH. ALBUIIrALBOT-TTPES, ALBOT-LOUDHESS/ ALBOT-REDIOTrALBOT-RATlliGrAlBOT. GROUPCODErALBOT-CDDBIDrAt ВОТ. CDDBBAltE FROT ALBOT

Pf Drecutequeiyimmediatelywhenopened

P Place SQLteid In resource bundle

⅛oad options: __________________

{Load all rows _vj

L⅞gggJl uccess

OK I Qancel j Help j

Рис. 43.7. Использование инструментов JBuilder Для создания простого запроса к таблице ALBUM

Выполните щелчок на компоненте queryDataSetAlbum и выберите в инспекторе свойство query. C помощью инструментов создайте оператор select для всех полей таблицы album, как показано на рис. 43.7. Эта операция множество раз описыва­лась в этой книге, поэтому повторяться я не буду.

Теперь необходимо повторить описанный процесс в отношении таблиц LOUDNESS, TYPES И MEDIUM. Поместите на каждую таблицу ПО Объекту QueryDataSet, Назовите их соответствующим образом и выделите в каждой таблице все поля. По­местите все свои запросы в группу ресурсов. Если вы забудете использовать группу ресурсов сразу, просто откройте запрос снова, отметьте соответствующую опцию и щелкните на кнопке OK. По завершении ваш модуль данных должен выглядеть так, как показано на рис. 43.8.

file edit search view protect run team wizards tools window help,dtfβ∙5≥∙β<h ~ * ∙ ⅛ jmf—rɪr 3% %* ъ j»-
stl⅛--1⅛'∙∣Λ'∙i⅛ w<<∣ φ
fclrl sp untitledl,,. - ∙ ×⅛ datamoduiei ∣ x ⅛ framel i
,⅛3 untitledl9.jpx si ⅛f untitled19 ¾. applicationl .java ⅛. datamoduiei .java ⅛ frameijava 4⅛ sqiresjava ⅛s unmled19.html,menu,• ∙ mydm β∣ jbbook
f -h querydataseta!bum
► ∙∣ auerydatasetloudness
► ! i querγdalaseftypes £ ip querydatasetmedium .j other
{■ * this
рис. 43.8.
настройка
модуля данных
для поддержки
таблиц
loudness,
typesu
medium.
обратите
внимание на
панель
структуры

"? Uirilder G /SrrJdva∕AIIUntitleds∕untir∣Bd19∕srr∕ι∣ntιtkdi WfttuMnriiiIfit java

Рис. 43.9. Выбор свойства PickList Для столбца LOUDNESS Из таблицы ALBUM

/sb 'icm fetНаконец-то вся работа по настройке за­вершена, и теперь настало время для опре­деления подстановок. В JBuilder подстанов­ку иногда называют списком выбора. Опре­деление списков выбора происходит не в объектах QueryDataSet, А в столбцах. Дос­туп к столбцам таблицы выполняется в ре­зультате щелчка на знаке "плюс", который на­ходится слева ОТ Компонента QueryDataSet В Панели структуры (см. рис. 43.9).

Выберите свойство pickList, чтобы выз­вать диалоговое окно PickList, показанное на рис. 43.10. Диалоговое окно не настолько простое в использовании. При разборе диа­логового окна PickList учитывайте следую­щие факты:

QueιyDataSelLoudnesfi Dataiype

Show in picklist: quBYOat⅛SeWlhuN

⅛Tf<,W0

A ■

CODE

JNl

Г Iloudnebb

pickllsvlookup dataeel uueiydatasetloudness jjlookupeoluinntoillspiay ne в
г entorceintegdiy
i ok j cancel [ help [
рис. 43.10. заполнение полей в диалоговом окне picklist для установки отношения между таблицами album и loudness, что предоставит пользователю возможность выбирать значения из таблицы loudness
■ Главная таблица и используемый вами столбец уже выделены, потому что вы работаете с полем Loudness Таблицы album. Если вы будете подходить к опе­рации подстановки как к отношению "главный-подчиненный", таблицу album можно рассматривать как главную таблицу, a loudness — как подчинен­ную. Вам не следует указывать таблицу album в этом диалоговом окне, так как вы уже использовали таблицу album для доступа к диалоговому окну. В част­ности, вы использовали столбец loudness таблицы album.

■ В верхней части диалогового окна в поле Picklist/Lookup Dataset указано значе­ние queryDataSetLoudness. Оно представляет собой набор данных, по которо­му необходимо проводить подстановку. Это подчиненная часть отношения.

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

Значения из поля Loudness Таблицы loudness, когда пользователь использу­ет список для выбора. Поэтому отметьте для этой строки таблицы флажок Show in picklist (Показать в списке выбора). Вам также потребуется связать поле code таблицы loudness с полем Loudness Таблицы album. Поэтому используйте вторую строку таблицы для указания на то, что целочисленное поле Code табли­цы LOUDNESS связано С целочисленным полем Loudness Таблицы ALBUM.

■ В нижней части диалогового окна укажите столбец таблицы album, в котором должно отображаться значение по умолчанию из таблицы loudness. Предпо­ложим, что для поля Loudness Таблицы album установлено значение 2, и вы не хотите, чтобы пользователь видел это целочйсленное значение. Вместо этого, вы хотите вывести для него строковое значение из таблицы loudness, связанное с числом 2. В этом поле диалогового окна вы уведомляете JBuilder, какое поле таблицы album вы хотели бы использовать для вывода строкового значения. И Хотя поле Loudness Таблицы ALBUM Имеет тип Integer, "чудеса" технологии списка выбора состоят как раз в том, что этот список заменяет аб­страктные целые числа на строки.

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

Columnl. SetPickList( new PickListDescriptort

QueryDataSetLoudness, new String[] {"CODE"}, new String[] {"LOUDNESS"}, new String[] {"LOUDNESS"}, "LOUDNESS", false));

Приведенные здесь параметры достаточно сложны. Первый параметр представ­ляет собой набор данных, содержащий значения для подстановки. Второй пара­метр — столбец в списке подстановки, для которого создана связь. Например, в таб­лице loudness этим столбцом будет code. Третий параметр представляет собой столбец списка выбора, который содержит значения, выводимые в выпадающем списке. Четвертый параметр — поле главного списка, который будет связан со стол­бцом code в таблице списка выбора. Пятый параметр — имя столбца в списке для выбора, который содержит значение, которое следует отображать в таблице в то вре­мя, когда пользователь не занимается выбором элемента. Последний параметр, на который мы пока не будем обращать внимания, связан с введением в действие огра­ничений по целостности данных, добавляемых в столбцы.

New PickListDescriptort

QueryDataSetTypes, ∕/ Набор данных, содержащий подставляемые значения

New String[] {"CODE"}, // Столбец связей со списком для выбора

New String[] {"LOUDNESS"},// Столбец для вывода в выпадающем списке

New String[] {"LOUDNESS"},// Столбец для вывода значений

"LOUE NESS" , // Столбец из списка для выбора для вывода в таблице

True)) ;

Я считаю, что можно назвать поля в двух таблицах так, как я обозвал их здесь. Однако в этом случае может возникнуть путаница, потому что таблицы имеют те же имена, что и связанные поля. Чтобы было легче понять, позвольте мне продемонст­рировать, как бы все это выглядело, если бы мы устанавливали связь с таблицей good_bad_and_ugly, а не с таблицей loudness:

Create table GOOD_BAD_AND_UGLY

(

GBUCode int NOT NULL,

Description VARCHAR(10),

PRIMARY KEY (GBUCode)

) TYPE=INNODB;

примечаниеInsert into GOOD_BAD_AND_UGLY values (1, "GOOD"); insert into GOOD_BAD_AND_UGLY values (2, "BAD") ; insert into GOOD_BAD_AND_UGLY values (3, "UGLY") ;

Эта таблица должна входить в состав базы данных jbbook. Если она отсутствует, а вы хотите выполнить то, что описано этом разделе, просто откройте базу данных jbbook в инструменте Database Pilot. Перейдите в нем на закладку Enter SQL и введите приведенные выше строки. Щелкните на кнопке Execute (Выполнить). В дан­ном примере я воспользовался конструкцией TYPE=INNODBf которая должна присутство­Вать лишь в случае работы с MySQL.

добавьте в свой пример новый объект типа querydataset. при помощи его свойства query выделите все поля таблицы good_bad_and_ugly, как это имело место в отношении других объектов querydataset.
выберите поле medium таблицы querydatasetalbum. вызовите диалоговое окно picklist и заполните его поля так, как показано на рис. 43.11.
ниже показан код, сгенерированный в результате заполнения полей диалогового окна, показанного на рис. 43.11.
,<?■ plchlfet 
picklisttloohup oatasst iqueiydatasbtl r, ɪf
auetyoatasev datatype snowtn plch∏s⅜ ⅛ueryoataset⅝lbum∣ 
obucode int .r 
description string !√ «none* 
 
lookup columnto display !description 
p enforce integrity 
 ok ] cancel help i

,рис. 43.11. заполнение диалогового окна picklist необходимыми данными

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

Самыми непонятными элементами в PickListDescriptor являются, пожалуй, третий и пятый. Главная идея здесь состоит в том, что можно и не использовать одно и то же поле таблицы для вывода в таблице и для выпадающего списка. Я не знаю, Зачем это может кому-нибудь понадобиться, однако знайте, что такая опция доступна.

Поскольку эта тема довольно-таки не проста, я хочу попытаться объяснить ее, продемонстрировав объявление PickListDescriptor в исходном коде JBuilder:

Public PickListDescriptor (

DataSet pickListDataSet, // Набор данных, содержащий поля подстановки String[] PickListColumnsz // Столбец (столбцы) в подстановке,

// по которому следует производить связь String!] PickListDisplayColumnsz // Столбец (столбцы), которые нужно

// отобразить в выпадающем списке String!] CiestinationColumns, // Столбец (столбцы) главной таблицы,

//в котором нужно выводить данные String IookupDisplayColumnz // Столбец в подстановке, который

// следует показывать в таблице

Boolean enfOrceIntegrity // Использовать ли правила целостности данных?

)

Просматривая эти столбцы, помните, что вы с самого начала знали, какой стол­бец был взят из главной таблицы, и какое поле в главной таблице вы хотели связать с PickListColumns в таблице подстановок. Прочие вопросы, например, почему одни поля называются pickListxxx, а другие — Iookupxxx, я оставляю вам на само­стоятельное изучение.

Введение в JBuilder-объект Column

В следующих нескольких абзацах я познакомлю вас с одним из ключевых поня­тий DataExpress — с классом column (столбец). Столбцы играют ключевую роль в программировании с использованием JDBC, и поскольку DataExpress основан на JDBC, столбцы стали играть важную роль и в инструменте DataExpress.

Изучая столбцы, вы можете полностью разобраться в том, что происходит при создании подстановок. Пока что я лишь продемонстрировал вам часть кода, сгене­рированного в результате работы с PickListDialog. Ниже приведен весь код:

ColumnMedium. SetColumnName("MEDIUM");

ColumnMedium. SetDataType(com. borland. dx. dataset. Variant. INT);

ColumnMedium SetPickList(new PickListDescriptor(QueryDataSetGBUz new String!] {"GBUCODE"}z new String!] {"DESCRIPTION"}, new String!] {"MEDIUM"),

"DESCRIPTION"z

False));

ColumnMedium. SetTableName("ALBUM");

CoIum! Medium. SetServerColumnName("MEDIUM");

ColumkiMedium. SetSglType (4) ;

При работе с отдельным столбцом QueryDataSet, JBuilder часто будет создавать экземпляр столбца самостоятельно, как показано на рис. 43.12. Можно сказать, что JBuilder создал объект Column Вместо вас, так как слово medium в панели структуры стоит в скобках.

На рис. 43.12 я переименовал столбец, сменив его имя с column2 на CoIumnMedium. Я также присвоил свойству caption значение Medium. По умолчанию оно содержало имя отображаемого поля из таблицы подстановок. В данном случае этим именем было Description.

примечаниеГлядя на сгенерированный код, вы можете увидеть, что был вызван метод SetTableName Для того, чтобы связать столбец с конкретной таблицей. Метод SetColumnName Использовался для выбора столбца из таблицы, которую использует объект Column. SetServerColumnName Это столбец в главной таблице на сервере баз данных, который будет использоваться для обновления этого столбца. Если это поле не установлено, вместо него будет использовано значение свойства ColumnName.

Также определен и тип данных столбца. Обратите внимание на то, что базы данных MySQL будут "выражать недовольство", если вы попытаетесь связать поле Типа INT с полем типа SMALLINT в таблице подстановки.

Мы более подробно поговорим об объектах типа Column Позже в этом разделе. Пока что вам нужно знать лишь то, что JBuilder всегда создает объект типа Column Для каждого поля таблицы. Однако если вы должны произвести определенные диск­ретные операции над полем или таблицей, JBuilder поможет создать явный объект типа Column. Создание явного экземпляра объекта типа Column Не требует допол­нительного расхода памяти или ресурсов. JBuilder уже создал объекты типа Column Для каждого поля вашей таблицы. Идея заключается в том, что наличие явного эк­земпляра объекта типа Column Дает возможность выполнить настройку поведения столбца.

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

Можно сказать, что объект типа Column Был создан, бросив взгляд на исходный код метода jbinit. Однако второй момент кроется в скобках, в которых находится имя столбца в панели содержимого. Скобки означают, что был создан явный экзем­пляр объекта типа Column.

Восстановление программы

Чтобы завершить программу, удалите подстановку для таблицы good_bad_and_ugly. Создайте новые подстановки для таблиц medium и types. Когда все будет готово, ваше приложение должно иметь такой же вид, как было показано ранее в этой главе, на рис. 43.4.

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

Упаковка программы в JAR-файл или в исполняемый файл

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

Причина важности этой темы заключается в том, что в JBuilder код приложений, взаимодействующих с базой данных,

saiectanarcmvelkm
the unique characteristics oftha selected archive type are displayed below.
arcħ∣ve⅞φβ: ctwt3hhhhhhhhh * ` description:
appiicanon archives are simitar to basic archives, but include a special mainciass manifest entry used by the lava -iar <jamame>': command-line launcher for java applications your appllca*1on⅛ main class is automatically derived itom the main class specified: in the default runtime configuration.
рис. 43.13. подготовка к созданию jar-файла, который будет содержать разработанное вами приложениеОснован на использовании файлов Dx. jar И DbSwing. jar, Которые не являются стандартными элементами JDK. В частности, эти два JAR-файла созданы компанией Borland. Нам нужно выбрать необходимый код этих JAR-файлов и поместить его в один JAR-файл, в котором будет на­ходиться и главный код вашей про­граммы.

Сначала выберем в меню пункт Wizards ∣ Archive. Установите в поле Archive Туре значение Application, как показано на рис. 43.13.

Щелкните на кнопке Next и заполните вторую страницу мастера, как показано на рис. 43.14. Присвойте узлу нового архива осмысленное имя, которое бы выводи­лось в панели проекта. Например, в данном случае можно ввести Create Lookup Jar File (то бишь, "Создание JAR-файла с подстановками"). Выберите имя для JAR-фай — ла, который вы хотите создать. Скорее всего, вам понадобится сжать содержимое JAR-файла, и вы, вероятно, не хотите проходить вновь и вновь долгий процесс со­здания JAR-файла при каждой компиляции.

Щелкните на кнопке Next и выберите опцию Always include all classes and resources (Всегда включать все классы и ресурсы). Иногда можно сохранить немного места, указав отдельные пакеты, которые необходимо включить. Тем не менее, в данном случае проще всего будет упаковать все.

Щелкните на кнопке Next и выберите опцию Always include all classes and resources для DataExpress, dbSwing и вашего драйвера базы данных, как показано на рис. 43.15. Вам потребуется повторить эту операцию трижды, по одному разу для каждого JAR файла. Проведение операции для драйвера базы данных в некоторых случаях может оказаться ненужным, например, когда вы используете ODBC-драй­вер для связи с Access. Обычно можно сберечь место на диске, если включить толь­ко требуемые классы и все известные ресурсы, но я советую, чтобы вы, по крайней мере, вначале, выбирали все, а лишь затем сужали фокус.

v∣' archive builder * slep z of 7,specty the (he to be creeled by the archmnq proceπ the wizard will use the settings on ihlfe and subsequent pages to create a new pro∣ect node tħ,⅛l represents the archiving process. vou ten change archiving settings at anytime by bringing up the properties dialog itom the archive node's context menu.
type: application
marne (create lookup jar file
f∣le: jojsrcjavamliuntltiedshintitledi a∕untttled192 jar - _
Γ^ compress the con∣eπls of the archive
j7 atways create archive when building the project
,рис. 43.14. определение имени jar- файла, имени его узла в панели проекта, что совершенно не зависит от вашего желания создавать архив при каждой компиляции и от необходимости установки сжатия,next»,рис. 43.15. ссылка на код взаимодействия с базами данных, разработанный компанией
borland, а также на код соответствующего драйвера
,juchiw ihrild*ι strp 4 of ?,finish

примечаниеЕсли вы планируете запускать свою программу лишь на той машине, на которой она была разработана, вам не нужно включать файлы dχ.jar, dbSwing. jar и SQL-драйвера в создаваемый JAR-файл. Более того, если вы распространяете набор приложений, проще будет оставить dx. jar, dbSwing. jar и SQL-драйвер в виде отдель­Ных файлов, а не помещать их во множество JAR-файлов.

На шаге 5 мастера оставьте предлагаемые по умолчанию значения, связанные с включением и созданием файла манифеста. На шаге 6 выберите опцию Use the main class specified in the default run time. Это относится к классу, который вы выбрали на закладке Run диалогового окна Project Properties.

Начиная с версии JBuilder 7, шаг 7 мастера позволяет производить упаковку про­екта в исполняемый файл, ориентированный на конкретную платформу. На рис. 43.16 вы можете увидеть, что я упаковал проект в приложение с графическим интер­фейсом пользователя для Windows. Этот шаг может оказаться полезным для тех, кто не привык работать с JAR-файлами.

Щелкните на кнопке Finish. В панели проекта рядом с пунктами Applicationljava, Frameljava и т. д. должен появиться новый узел. Щелкните на этом узле правой кнопкой мыши и выберите в контекстном меню либо пункт Маке, либо пункт Rebuild.

887
1,053,047
2,898
1,132,919
4/14/02 9:38 4/14/02 12:04 4/14/02 10:08 4/14/02 12:04 υntitledl9.html untitledl9.jar untitledl9.jpx untitledl9w.ехе

Чтобы запустить свою программу, перейдите в окно командной строки и набери­те либо dir, либо Is в корневом каталоге своего проекта:

Файл Untitledl9W. exe Можно запустить непосредственно как стандартный ис­полняемый файл Windows. Чтобы запустить JAR-файл, введите в командной строке

Следующее:

Java — jar untitledl9.jar

рис. 43.16. новая возможность, появившаяся в jbuilder 7, которая позволяет упаковать проект в исполняемый файл

Если переменная окружения path содержит каталог Bin Вашего комплекта JDK, любая из этих команд должна привести к запуску вашего приложения. В своих ехе — файлах компания Borland предпринимает некоторые дополнительные действия, ко­торые иногда могут привести к тому, что ваш код найдет JDK или JRE, не отражен­ные в переменной path.

Прежде чем распространять свой код, вам следует протестировать его на "чис­той" машине, чтобы убедиться, что он не зависит от каких-нибудь файлов, которые каким-то образом попали в ваш путь классов. Вы можете поступить проще, устано­вив путь классов равным пустой строке, но я все же советую использовать "чистую" машину, прежде чем распространять свой код. Под "чистой" я подразумеваю такую машину, на которой не установлен JBuilder или какие-либо другие файлы, исполь­зуемые во время разработки. Вы также можете попробовать произвести настройку установок своего архива, чтобы узнать, можно ли создать JAR-файл или исполняе­мый файл меньших размеров.

Для того чтобы вы могли понять, как все работает, я покажу вам, какие размеры имеют JAR — и ехе-файлы, если вы используете файлы d×. Jar, Dbswing.Jar И свой SQL-драйвер в виде отдельных файлов:

4/14/02 12:15 4/14/02 12:15 4/14/02 12:155,112 υntitledl9.jar
4,039 unti tledl9.jpx
84,984 untitledl9W. exe

Вот оно как! JAR-файл уменьшился в размерах с 1 000 Кб до 5 Кб. Четко видно, что вы платите немалую цену за помещение инструментов взаимодействия с базами данных непосредственно в проект. Однако в ряде случаев этот способ распростране­ния проекта, взаимодействующего с базами данных, окажется наиболее простым. Помните то, о чем я говорил выше: если вы распространяете набор приложений, вы можете сохранить немалое дисковое пространство, если будете распространять фай­лы Dχ. jar, dbSwing. jar И свой SQL-драйвер в виде отдельных JAR-файлов. C дру­гой стороны, если вам нужно доставить на компьютер назначения только один файл, тогда имеет смысл воспользоваться методами, описанными здесь.

Резюме

В данной главе вы ознакомились с информацией, касающейся поиска данных в наборе данных и выполнения подстановок. В конце главы вы также увидели, как производить упаковку своего приложения, взаимодействующего с базами данных, в отдельный JAR-файл. Небольшой раздел был посвящен объекту типа Column, кото­рый будет рассмотрен более подробно в главах 44 и 45.

чарли калверт

Глава 44

Каммвмимпмиаимимимим^^

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *