Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2003.10.27;
Скачать: [xml.tar.bz2];

Вниз

Зацените дурацкое решение   Найти похожие ветки 

 
kaif   (2003-10-07 18:01) [0]

Метод Insert наследников DataSet вставляет запись перед текущей записью в наборе. При наборе накладной пользователю привычнее вставлять запись в конец набора, то есть использовать метод Append. Тем более, что наборы в накладных бывают не столь уж обширные.
Однако компонент DBNavigator умеет делать только Insert, как впрочем и DBGrid при нажатии клавиши <Insert> именно инсертит, а не аппендит, к сожалению.
Желая использовать стандартный DBNavigator и ища приемлемое практическое решение этой проблемы я написал такой обработчик для события AfterInsert компонента IBDataSet:

var
lock_insert: boolean;

procedure TStockInForm.qryDetailAfterInsert(DataSet: TDataSet);
begin
if not lock_insert then
begin
lock_insert := True;
qryDetail.Cancel; //отменяем режим вставки
qryDetail.Append; //вставляем в конец набора
end;
lock_insert := False;
end;

Переменная lock_insert предотвращает рекурсивный бесконечный вызов.

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

Кто что может сказать?


 
Anatoly Podgoretsky   (2003-10-07 18:13) [1]

Для большинства баз данных, нет такого понятия, как физический номер записи, исключение dBase/FoxPro
А уж для IB6 совсем нет этого понятия, при выборке непредсказуема последовательность записей (без упорядочивания) одна и таже выборка в разные моменты времени может выдать разные последовательности.

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

Если тебе нужны позиции в накладной, то введи поле номер позиции.


 
Johnmen   (2003-10-07 18:13) [2]

Пока читал пост, до кода, мне тоже пришло такое решение, т.е. подменять, где надо, инсерт на аппенд. В том же гриде можно просто обработать клаву...:) и по кл.инсерт сделать Append.
Может и в навигаторе можно перехватить нажатие (не знаю не работал с ним).
По поводу кода - думаю, нормально.
:)


 
Johnmen   (2003-10-07 18:15) [3]

>Anatoly Podgoretsky © (07.10.03 18:13)

Нет, здесь дело несколько в другом...:)


 
Sandman25   (2003-10-07 18:20) [4]

Insert не является Virtual, поэтому переписать его не получится.
В данных условиях Ваше решение самое лучшее ИМХО.


 
Anatoly Podgoretsky   (2003-10-07 18:25) [5]

Johnmen © (07.10.03 18:15) [3]
А уточнить, а то я в недоумении?


 
Sandman25   (2003-10-07 18:26) [6]

[5] Anatoly Podgoretsky © (07.10.03 18:25)

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


 
Anatoly Podgoretsky   (2003-10-07 18:28) [7]

Может быть, ну тогда мой пост недействителен.


 
MsGuns   (2003-10-07 18:31) [8]

1. DBNavigator - полный отстой (с месяца 2 назад я подробно описывал большинство его недостатков, главный из которых - корявость и негибкость визуализации)

2. Нельзя однозначно заменять Insert на Append, т.к. юзеру иногда надо именно вставить запись между двумя смежными. Лучше всего иметь 2 кнопки: "Новая перед", "Новая после". Или даже 3 ("Новая в конце"). Это решает все проблемы удобства интерфейса редактирования документов (выделено специально для АП)

3. Проблема последовательности записей в документе не есть такая праздная как многим представляется. Некоторые документы (к примеру, счета-фактуры) заполняются внешними контрагентами вручную и ни о какой упорядоченности по наименованию, цене и т.д. речи итти не может. Упорядоченность типа "как Маше было удобно". Но трабла в том, что частенько ее-то и надо сохранить в БД ! И я лично понимаю того юзера, который вынужден с карандашом в руках сверять электронную накладную с ее бумажным оригиналом (самому приходилось не раз, как вспомню-так вздрогну !)
Я ничего лучшего не придумал, как ввести в таблицу фактуры (к примеру) доп.поле "Ordering", в которое записываю № записи внутри курсора (фактуры). Алгоритм его определения несколько замудрен, но работает ! А вот если б кто мне показал пример эффективного алгоритма определения этого самого номера по двум смежным, я б был в большом долгу (свой алгоритм я оптимальным не считаю).


 
Sandman25   (2003-10-07 18:36) [9]

> алгоритма определения этого самого номера по двум смежным

Что имеется в виду?


 
Vlad   (2003-10-07 18:38) [10]

>MsGuns © (07.10.03 18:31) [8]
Алгоритм достаточно несложен.
Если данные хранить в таблице в иерархическом виде (т.е. ID,PARENT_ID).
Тогда, если тебе нужно вставить запись между двумя другими, достаточно в следующей записи поменять ссылку на родительскую запись.
Оракл легко позволяет работать с иерархическими таблицами, в IB c этим конечно более проблемно, но тем не менее можно.


 
Sandman25   (2003-10-07 18:42) [11]

1. пробежаться по всем записям dataset и увеличить nomer на 1, если он больше вставляемого.
2. вставить нужную запись.


 
MsGuns   (2003-10-07 18:47) [12]

>Sandman25 © (07.10.03 18:36) [9]
>Что имеется в виду?

Запись i-я Запись i+1-я Запись новая
------------------------------------------------
23 26 24 (25)
1 2 1.9 (1.1)
1.1 1.2 1.19 (1.11)

>Vlad © (07.10.03 18:38) [10]
>Если данные хранить в таблице в иерархическом виде (т.е. ID,PARENT_ID).

Иерархия для линейного множества линейных объектов ? Речь идет о последовательности строк документа, необходимой только для визуального отображения. И больше абсолютно ни для чего !
Т.е. это самое поле Ordering не используется нигде кроме оператора ORDER BY или индекса. НИГДЕ И НИКОГДА ! Это чисто клиентская проблема. Причем здесь иерархические данные в БД ?


 
MsGuns   (2003-10-07 18:51) [13]

>Sandman25 © (07.10.03 18:42) [11]

Я так делал скубентом, когда лабы сдавал. А если строчек 200 (Редко, но бывает) ? А если табла - парадокс и юзается 15 челами ? А слетит на перенумерации ? Да мне совесть не позволит лепить такую лабуду.


 
Vlad   (2003-10-07 18:52) [14]

>Иерархия для линейного множества линейных объектов
Именно линейного множества.
Год назад у меня была задача показывать в гриде некие данные, причем так, чтоб пользователь мог перетаскивать мышкой строки на ту позицию, которую ему нужно. Естественно, при close/open позиция должна сохраняться. Я тоже много изобретал, и такой способ ка ты использовал, но в конце концов пришел к иерархическому хранению, как ты говоришь, линейного множества.
Работало все четко и красиво.


 
Sandman25   (2003-10-07 18:53) [15]

Я так понимаю, что номер имеет тип real или BCD? Иначе бы сортировка не работала.

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


 
kaif   (2003-10-07 18:53) [16]

2 Anatoly Podgoretsky © (07.10.03 18:13) [1]
Я знаю, как работает SQL. Проблема у меня в другом.

2 Johnmen © (07.10.03 18:13) [2]
Спасибо! Именно Ваше мнение я очень ждал услышать и рад, что Вы находите решение приемлемым.

2 MsGuns © (07.10.03 18:31) [8]
Вы совершенно правы. Последовательность записей в счетах фактурах имеет огромное значение, так как часто менеджеры по телефону, обсуждая те или иные вопросы, отыскивают позиции в портянках, длиной более 200 строк их именно по номеру позиции.
Но я пишу пример "простейшего" склада в виде примера. И мне достаточно решить проблему с добавлением в конец. Перед посылкой строки у меня генерится первичный ключ подчиненной таблицы документа (поле N). Таким образом, так как при SELECT я запрашиваю ORDER BY N, то порядок будет всегда одинаков, как при вводе, так и при выводе. Нумерацию я делаю в вычисляемом поле просто выводя RecNo. Чтобы "дырка" не возникла в RecNo после удаления строки, переоткрываю весь набор.
Вставку в середину документа не планирую вообще. Максимум, что я использую, это перестановка соседних строк внутри документа относительно друг друга (обмен ключами N через третье состояние, равное минус N). Кстати, все это очень неплохо работает с помощью кнопочек "вверх" "вниз" в реальных приложениях. В примере я перестановку показывать не буду. И так там много сложного материала.
В общем, я чувствую, что я нашел достаточно оптимальное и не очень сложное решение. Хотя дурацкое, конечно. :)


 
Sandman25   (2003-10-07 18:55) [17]

Delta, Nomer1, Nomer2: real;
...
Delta := 10;
repeat
Delta := Delta/10;
NewNomer := Nomer1 + Delta;
until NewNomer < Nomer2;


 
MsGuns   (2003-10-07 19:13) [18]

>Sandman25 © (07.10.03 18:55) [17]
Я с этого начинал когда-то ;)) Типа метод добавления разряда ?

Недостаток (при вставке нескольких подряд, как они (Машки) часто делают):

1 2 > 1.1
1.1 2 > 1.11
1.11 2 > 1.111
....
Через относительно небольшое кол-во вставок происходят понятные проблемы с погрешностью.

У меня так
1 2 > 1.9
1 1.9 > 1.8
...
1 1.1 > 1.09
1 1.09 > 1.08
...

Работает безотказно ! С учетом женской психологии и некоторой мамы ;))


 
Johnmen   (2003-10-08 00:24) [19]

>kaif ©

Ашот, если мне не изменяет память, мы с тобой давно на "ты" :)

>MsGuns © (07.10.03 18:31) [8]

> А вот если б кто мне показал пример эффективного алгоритма
>определения этого самого номера по двум смежным

Предлагаю простой, понятный и эффективный алгоритм.
Каждая вновь добавленная запись отстоит от последней (по этому самому номеру N, где N - integer) на 1000000 (1 млн). Номер вновь вставляемой = ближайшее целое среднеарифметического соседних.

>...я б был в большом долгу

Все, Серега, ты попал :))))))))))))))))))))))))

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


 
kaif   (2003-10-08 01:04) [20]

2 Johnmen © (08.10.03 00:24) [19]
Ашот, если мне не изменяет память, мы с тобой давно на "ты" :)

Извини, засиделся в "Потрепаться". :)
...у меня манера в том форуме всегда использовать "Вы".

Каждая вновь добавленная запись отстоит от последней (по этому самому номеру N, где N - integer) на 1000000 (1 млн).

А что там всего 2000 новых записей намечается?
Я как бы не спорю (боюсь), но просто... интересно


 
Johnmen   (2003-10-08 01:10) [21]

>kaif © (08.10.03 01:04) [20]

:)))

Это для примера 1 млн. Можно и 100 000.
Лично я не видел счетов-фактур на количества более 1 тыс.
Кстати, не 2000, а 4000 :)


 
kaif   (2003-10-08 01:14) [22]

2 Johnmen © (08.10.03 01:10) [21]

Так это о счет-фактуре речь шла... Я думал, о дереве каком-то плоском и испугался. А integer всего до 2000 потянет, если только отрицательные числа не использовать. Кстати, а есть ли такой CAST в IB, чтобы типа usigned integer получился? Типа от нуля и выше и так до 4*10^9 ?


 
Johnmen   (2003-10-08 01:24) [23]

>kaif © (08.10.03 01:14) [22]

>А integer всего до 2000 потянет, если только отрицательные числа не использовать.

Да. Это я погорячился ;-)

>... а есть ли такой CAST в IB

Да вроде неоткуда ему там взяться...:)
А если версия позволяет и есть желание, то можно и int64.


 
Deniz   (2003-10-08 07:30) [24]

Мож я не так понял, но если требуется вставить № между 1 и 2( как в примере MsGuns © (07.10.03 19:13) [18]), можно сделать чуть по другому(если конечно логика позволяет) 2-мя операциями:
update Table set
N = N + 1
where N >=2
Insert into Table(N) values (2)
Где N - № записи в документе по порядку, у меня такой алгоритм работает


 
Alexandr   (2003-10-08 08:05) [25]

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


 
Sandman25   (2003-10-08 10:20) [26]

[18] MsGuns © (07.10.03 19:13)

Да нет, у меня тоже будет все нормально.

1 2 > 1.1
1.1 2 > 1.2
1.2 2 > 1.3
...
1.9 2 > 1.91

А вообще я тоже делаю как [24] Deniz © (08.10.03 07:30)
И проблем с точностью не бывает :)

Способ [19] Johnmen © (08.10.03 00:24) тоже хорош, но только если не нужно эти идентификаторы отображать для пользователя.
И есть небольшое ограничение - нельзя добавлять log(2)N записей между двумя соседними. При N=100000 нельзя добавлять больше 16 записей.


 
Жук   (2003-10-08 10:24) [27]


> Deniz © (08.10.03 07:30) [24]

"Очень правильная постановка вопроса !"(с) :-)))


 
Sandman25   (2003-10-08 11:02) [28]

[13] MsGuns © (07.10.03 18:51)

Сначала не заметил это сообщение.

Если пользователей много, и все они редактируют один документ, то без проблем все равно не обойдется. Простейший случай - после последнего пункта двое пользователей одновременно добавляют строку. Строку второго пользователя добавлять после строки первого пользователя или до?

Если в документе 200 строк, ничего страшного - отключаем все гриды, и обработчики, и за пару миллисекунд все записи изменены.


 
Johnmen   (2003-10-08 11:04) [29]

>Sandman25 © (08.10.03 10:20) [26]
>И есть небольшое ограничение ...

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


 
Sandman25   (2003-10-08 11:07) [30]

[29] Johnmen © (08.10.03 11:04)

Наксолько я понимаю, при использовании int54 невозможно подобрать N так, чтобы можно было сделать больше чем 64 вставки подряд.


 
Sandman25   (2003-10-08 11:08) [31]

[29] Johnmen © (08.10.03 11:04)

Наксолько я понимаю, при использовании int64 невозможно подобрать N так, чтобы можно было сделать больше чем 64 вставки подряд.


 
Johnmen   (2003-10-08 11:27) [32]

>Sandman25 © (08.10.03 11:08) [31]

Я так понимаю, что не больше 63
:)


 
Sandman25   (2003-10-08 11:36) [33]

[32] Johnmen © (08.10.03 11:27)

Может и так. Я много об этом не думал :)



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2003.10.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.015 c
1-89369
Piero
2003-10-15 20:32
2003.10.27
Непонятная ошибка компилятора


6-89429
SergP
2003-08-31 14:55
2003.10.27
Как в прокси правильно сделать фильтрацию содержимого?


14-89543
Delirium^.Tremens
2003-10-08 11:33
2003.10.27
Смазка для ворот


7-89583
Александр2030
2003-08-15 10:38
2003.10.27
Рабочий стол


14-89537
stone
2003-10-08 15:14
2003.10.27
Клавиша Shift снимет защиту от копирования CD :)





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский