Java JDBC — ResultSet и инкапсуляция. Много полей, слишком много сеттеров и геттеров для управления. Есть ли лучшая техника?

Я пишу программу Java, которая читает файл базы данных и показывает записи на экране графического интерфейса, используя JDBC и ResultSet. Файл базы данных содержит сотни полей. Это означает, что если я разделю обработку графического интерфейса и базы данных в двух файлах классов и использую инкапсуляцию, у меня будут сотни методов установки и получения (по одному для каждого поля). Есть ли лучший способ сделать это?

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

Спасибо, я ценю вашу помощь.


person Gil    schedule 08.05.2014    source источник
comment
Почему у вас сотни столбцов в таблице базы данных? Нужно ли нормализовать?   -  person Dawood ibn Kareem    schedule 09.05.2014
comment
Если в таблице буквально сотни полей, значит, кто-то действительно ошибся при проектировании базы данных.   -  person mortsahl    schedule 09.05.2014
comment
Если вы не можете изменить схему, по крайней мере, не сопоставляйте таблицу с уникальным классом Java. Я уверен, что некоторые столбцы должны быть сгруппированы внутри другого класса (например, Пользователь - Адрес...)   -  person JB Nizet    schedule 09.05.2014
comment
Рассматривали ли вы возможность использования Hibernate?   -  person Dawood ibn Kareem    schedule 09.05.2014
comment
Ух ты! Отличный выход. Спасибо за все Ваши ответы. Я рассмотрю все предложения подробно, как только смогу. А пока просто добавлю, что я не разрабатывал базу данных и не могу изменить исходный файл (он исходит от машины IBM as400 - языки Cobol/RPG). Также нужны все поля в файле и записей много. Разбиение файла на более мелкие приведет к проблемам с производительностью, поскольку JDBC, по-видимому, занимает больше времени для открытия разных файлов, чем для чтения одного большого файла. Разве создание новых классов не будет иметь ту же проблему, что и необходимость управлять слишком большим количеством сеттеров и геттеров (в разных классах)?   -  person Gil    schedule 09.05.2014
comment
@DavidWallace, потому что это может быть устаревшая база данных конца 80-90-х годов (обычно построенная на IBM AS-400 или Informix), которую необходимо поддерживать и которая не имеет никаких правил нормализации. Например, мне пришлось поддерживать приложение для таблицы Customer, где у клиента могло быть до 10 детей (здесь очень большие семьи), поэтому для каждого ребенка было как минимум 4 поля (действительно плохой дизайн, но его нельзя изменить).   -  person Luiggi Mendoza    schedule 09.05.2014


Ответы (3)


Один из способов — просто сохранить каждую строку в Map.

Для этого вы можете получить имена столбцов, используя ResultSetMetaData (ключ = имя столбца), или вы можете просто получить значения столбцов, используя индекс столбца (ключ = индекс). ResultSet может справиться с этим обоими способами.

Тогда ваш результат будет выглядеть как структура List<Map>.

person Leo    schedule 08.05.2014
comment
Интересно. Позвольте мне видеть, если я понимаю. Я бы загрузил ResultSet в карту (которая является частной), создал сеттер и геттер для этой карты и получил доступ к данным, используя индекс столбца (ключ = индекс) в другом классе? Спасибо за ваш ответ, кстати. - person Gil; 09.05.2014
comment
@ user3618243 сделайте это, и сначала он будет работать хорошо, а затем решите проблемы с обслуживанием в будущем. Лучшим вариантом является использование платформы ORM, которая облегчает эти проблемы. - person Luiggi Mendoza; 09.05.2014
comment
@LuiggiMendoza, конечно, ORM лучше для обслуживания, но я предполагаю, что у пользователя есть таблица с сотнями столбцов, вероятно, сгенерированная какой-то ERP (так что это не его / ее вина, что она не нормализована - может быть, он / она просто может это не исправить). С сотнями столбцов я действительно не думаю, что это имеет НАСТОЛЬКО БОЛЬШУЮ разницу, если у вас есть 200 геттеров + сеттеры, потому что никто не будет писать 100 геттеров, вместо этого все будут использовать отражение. Карта будет работать точно так же без накладных расходов на отражение. - person Leo; 09.05.2014
comment
Вы можете написать свои собственные сопоставители столбцов в jpa, чтобы облегчить это и иметь несколько геттеров/сеттеров для этих столбцов. Кроме того, я уже работал с обоими этими подходами, и использование сотен геттеров/сеттеров было намного лучше, чем использование подхода Map. - person Luiggi Mendoza; 09.05.2014
comment
Я согласен с вами в том, что создание bean-компонентов JPA обеспечит безопасность типов, потому что у вас есть 1 тип на столбец. За исключением этого, ему/ей придется перебирать столбцы с помощью отражения. Для более сложных приложений / если это будет использоваться в нескольких местах, ORM может быть подходящим вариантом. Но если он / она просто хочет быстрое и грязное решение, чтобы просто получить данные из БД один раз, для нескольких и локализованного использования, я думаю, что карта достаточно хороша. Опять же, вопрос был о том, как избежать геттеров и сеттеров. Для меня он / она может использовать карту или чередовать байт-коды для генерации этих геттеров во время компиляции. - person Leo; 09.05.2014
comment
Я просматриваю все предложения и отвечу как можно скорее. Я просто объявлю, что не проектировал базу данных и не могу изменить исходный файл (он исходит от машины IBM as400 - языки Cobol/RPG). Спасибо! - person Gil; 10.05.2014

Как уже упоминалось, если ваша БД буквально содержит сотни полей, значит, что-то пошло не так во время проектирования.

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

ID | FirstName | MiddleName | Surname | Gender | Age | HairColor | EyeColor | BuildingNO | StreetName | City | State | PostCode | Country | CarMake | CarPlate | etc...

Я бы создал класс для Person, Address, Car и поместил бы в эти классы запросы, которые будут извлекать информацию из базы данных, относящуюся к этому конкретному объекту.

поэтому в классе Person у меня было бы что-то вроде этого

public class Person {
   private FirstName;
   private MiddleName;
   private Surname; 

   appropriate query here and plug the whole object into a list - so you will end up with a List of Objects 'Person' with relevant data in it. 
   /* Setters and Getters */

то же самое для другого адреса класса

public class Address {


public class Car {

Надеюсь, вы поняли, что я имею в виду

person Maciej Cygan    schedule 08.05.2014
comment
Это был мой первый порыв, и я попробовал нечто подобное. Все выглядело нормально, пока я не столкнулся с проблемой производительности. JDBC, по крайней мере в этом случае (JDBC.as400), требует намного больше времени для доступа к файлу (open/clsoe), чем для его чтения. Наличие нескольких классов, обращающихся к файлу несколько раз, приведет к неприемлемому времени загрузки. Если вы планируете работать в Интернете или через VPN, забудьте об этом. Наличие нескольких классов также означало бы необходимость управлять не только сеттерами и геттерами, но и самими классами. Я был бы в порядке с этим, если бы не производительность. Спасибо!. - person Gil; 09.05.2014
comment
@Gil Хм, хорошо, в таком случае, если вы не можете разделить это, может быть, что вы можете сделать (но это будет очень грязное решение, это опустить сеттеры и геттеры - напишите один большой запрос и извлеките все поля из БД за один раз в простые переменные - person Maciej Cygan; 09.05.2014

Я реализовал стратегию карты, предложенную Лео. Хотя это не единогласное решение, я могу использовать его немедленно, и я думаю, что это довольно хорошая альтернатива. Это не только позволяет избавиться от лишних сеттеров и геттеров, но вы также можете создать ArrayList (или любую другую коллекцию) для динамического хранения каждого поля. Нет необходимости знать имя экземпляра каждого списка, потому что вы можете получить к ним доступ с помощью ключа карты (ключ = имя столбца), что позволяет избежать необходимости кодировать список для каждого поля. Я действительно считаю, что это большое преимущество. Затем можно преобразовать каждое поле прямо в строку (или в любой другой тип), что сделает код компактнее.

Например:

Класс LoadBigFile подключается к базе данных и загружает содержимое файла на карту.

Что-то вроде этого (обратите внимание: это всего лишь очень расплывчатый пример, иллюстрирующий, что можно сделать):

    Class LoadBigFile{

       private HashMap<String, ArrayList<String>> filemap = new HashMap<String,ArrayList<String>>();

       ////// ...Code to connect to database and load the file contents into the map

       ////// Setter and getter for the map:

       public void setFileMap(HashMap<String, ArrayList<String>> filemap){this.filemap=filemap;}
       public HashMap<String, ArrayList<String>> getFileMap(){return this.filemap;}

    }

Затем в классе вы собираетесь использовать данные (распаковать карту):

      LoadBigFile loadBigFile = new LoadBigFile();
      String customer = loadBigFile.getFileMap().get("CUSTOMER").get(iterator));

ПРИМЕЧАНИЕ. Я не буду рассказывать об итераторе, потому что это будет не по теме. Все, что я могу сказать, это то, что это работает.

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

Спасибо вам всем. Я надеюсь, что этот вопрос поможет другим энтузиастам Java.

person Gil    schedule 12.05.2014