![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#31
|
||||
|
||||
|
Цитата:
Цитата:
Выше в теме я почти ответил на вопрос про книги и знания. Даже не уверен, что читал где-то, а не вывел самостоятельно. Это математика, в ней всё просто, -- недостающее можно вывести и самому. А чтобы теория не расходилась с практикой, достаточно помнить, что все теории делятся на верные и неполные. Цитата:
Цитата:
![]() |
|
#32
|
||||
|
||||
|
Я поймал волну. Осталось совсем чуть-чуть. Вопрос:
Как реализовать вызов из диалога другого диалога? Ведь в той же 1c можно вызвать справочник товаров или клиентов, для заполнения соответствующих полей основного документа? Получается Основная форма -> Диалог оформления Документа -> Диалог выбора клиента (или товаров, или ещё Бог знает чего) Это ж как нужно пробрасывать DataSet'ы с главной формы?) И отклоняясь от темы. Насколько адекватно создавать одинаковые ADOTable на разных формах с одной и той же Таблицей внутри? Или ADOQuery с одним и тем же запросом. Вообще у меня сложилось впечатление, что ADOTable =(тождественно) ADOQuery(Select * from TableName) P.S. Есть одна новость по поводу первичной задачи "добавлять" с возможностью отмены и при этом ещё Master-Detail связь держать. Если организовать вот такой алгоритм: (при этом LockType оставить ltOptimistic): Код:
procedure TFormMain.dxBarLargeButton1Click(Sender: TObject);
begin
Connection.BeginTrans;
try
with TFormTicketDialog.Create(Self) do
try
Execute(Tickets)
finally
Free;
end;
Connection.CommitTrans;
except
on E: Exception do
Connection.RollbackTrans;
end;
end;Код:
Connection.CommitTrans; Только тогда на mrOK нужно повесть CommitTrans, а на mrCancel RollbackTrans. Вместо Post и Cancel. Я прав? Последний раз редактировалось Uniq!, 17.10.2013 в 14:16. |
|
#33
|
||||
|
||||
|
Цитата:
Если справочники считаются временными сущностями, их наборы данных хранятся прямо в диалогах и создаются/уничтожаются по мере надобности вместе с самими диалогами. В этом случае списки клиентов на главной форме и в диалогах могут выводиться разными наборами данных. На то и СУБД, в конце концов. Если же перечитывание справочников при каждом вызове диалога считается затратной операцией, придумывается что-то вроде диспетчера ресурсов, разделяющего однажды прочитанные данные между многими вызовами диалогов. В простом случае в роли диспетчера может выступить и модуль данных, и даже глобальная переменная. Развитие идет по спирали, и осознанное использование спорных инструментов -- сознательный выбор, пусть даже они и были признаны "плохими" на предыдущем шаге. Инструменты ведь не бывают плохими или хорошими, они всего лишь инструменты. Сравни свои теперешние знания о глобальных переменных и модулях данных с культом карго, который был раньше. ![]() Если вместо "проброса" справочников сделать объект "окружение", в его роли вполне может выступить модуль данных с дополнительными публичными методами по принципу Execute, если нужно. Цитата:
|
|
#34
|
||||
|
||||
|
Прошла уже куча времени, а я опять сталкиваюсь с проблемой заполнения связанных таблиц.
И всё также адекватного решения с Commit и RollBack не нашёл. Продолжаю поиски. Гвоздь вбит именно там, где необходимо присвоить подчинённым данным ещё "незаCommit'ченый" ID главной записи. google: транзакции и связанные таблицы в ADO |
|
#35
|
|||
|
|||
|
Смотрю я на все это и думаю, а парень то изобретает велосипед.
Возьми Delphi, Firebird, IBExpert, FIBPlus и забудь про изврат, которым ты занимаешься. |
|
#36
|
||||
|
||||
|
Почему велосипед? Вы сейчас предлагаете четырехлетний проект перевести на другой движок бд. Я молчу про то, что база уже около 8гигов весит, и все прекрасно работает без подвисаний. меня лишь внутреннее устройство приложения не радует.
Слабо представляю как вышеупомянутые средства помогут решить вопрос присвоения в дочернюю таблицу autoinc Id из родительской. |
|
#37
|
|||
|
|||
|
Был у меня проект, который я пару лет делал на парадоксе, как только узнал про FB, сразу понял, что проект нужно переводить на него.
Очень рекомендую ознакомится с возможностями FB. Очень простой и мощный язык хранимых процедур. Независимые от транзакций генераторы (id в вашем случае). Возможность создавать любые внешние функции. Наличие триггеров, позволяет возложить всю логику и поддержание целостности на сервер. И много еще чего. FIBPlus умеет кэшировать изменения и генерировать ID еще до того, как данные попадут на сервер, а значит вы можете без проблем создать запись в мастер таблице, узнать ее ID еще до коммита, и присвоить этот ID дочерним таблицам. Но этого вам делать не придется, FIB все сделает за вас. Но в данном случае ID генерируется правильно, в рамках механизма заложенного FB, для всех пользователей он будет уникальный. Посмотрите примеры использования FIBPlus. Просто я смотрю, как вы стараетесь, ищете решения, но все уже давно придумано, просто вам нужно освежить свои знания, пересмотреть подход... На своем опыте, хочу сказать, что после замарочек с парадоксом, я освоил работу с FB буквально за месяц и был несказанно рад, оно действительно того стоит. Последний раз редактировалось kaakaa, 04.09.2014 в 11:33. |
| Этот пользователь сказал Спасибо за это полезное сообщение: | ||
Uniq! (04.09.2014)
| ||
|
#38
|
||||
|
||||
|
Цитата:
|
|
#39
|
|||
|
|||
|
Как я понимаю, мы имеем один документ и много изделий связанных с ним.
Нужно, чтобы добавление/изменение нескольких изделий происходили в рамках одной транзакции. Если записи будут коммититься в разных транзакциях, возможно ситуация, когда другой пользователь сделает запрос к документу, но увидит не все связанные с ним изделия. ВАРИАНТЫ: Как можно решить эту проблемму: 1) Кэшировать изменения/вставку. После того как пользователь закончил ввод, он нажимает кнопку сохранить и все данные коммитятся в рамках одной транзакции. Если датасет не умеет кэшировать данные, можно сделать прослойку в виде временной таблицы, вы делали это через MemTable. Но при коммите прийдется использовать last_insert_id( ) чтобы получить id мастера. 2) Проблема получения ID мастер таблицы актуальна. Вероятно, решить ее в рамках мускула можно вставкой записи без подтверждения транзакции и выполнив last_insert_id( ). Это предположение, его я не проверял. Зная ID мастер-записи, вы можете добавлять записи в дечернюю таблицу в рамках активной транзакции в которой была выполнена вставка мастер-записи. Если пользователь захочет все отменить, он просто откатит транзакцию. Если захочет все применить, он ее прокоммитит. Пока транзакция не подтверждена, другие пользователи не видят записи, которые были в ней созданы. Недостатком этого подхода можно считать длинную WRITE транзакцию, которая косвенно может блокировать часть данных. Однако, это плохой тон. Последний раз редактировалось kaakaa, 04.09.2014 в 12:56. |
| Этот пользователь сказал Спасибо за это полезное сообщение: | ||
Uniq! (08.09.2014)
| ||
|
#40
|
||||
|
||||
|
kaakaa, реализовал пока следующим образом:
создал хранимку такого вот вида: Код:
DELIMITER $$
USE `pawnshop`$$
DROP PROCEDURE IF EXISTS `ItemAdd`$$
CREATE PROCEDURE `ItemAdd` (
IN aTicketID INT,
IN aInfo VARCHAR(32),
IN aStandard INT,
IN aFullWeight DECIMAL(10,2),
IN aInsWeight DECIMAL(10,2),
IN aPriceP1g DECIMAL(10,2),
OUT aNewID INT
)
BEGIN
INSERT INTO `items` (
TicketID,
iInfo,
iStandard,
iFullWeight,
iInsWeight,
iPriceP1g
)
VALUES
(
aTicketID,
aInfo,
iStandard,
aFullWeight,
aInsWeight,
aPriceP1g
) ;
SET aNewID = @@Identity ;
END $$
DELIMITER ;Внутри программы с главной формы зову модальную форму, и перед этим открываю транзакцию: (внутрь отдаю Connection, чтоб там уже с ним связать AddTicketCom: TADOStoredProc) Код:
procedure TFormMain.btnAddTicketClick(Sender: TObject);
begin
TicketsView.BeginUpdate;
with TFormTicketNew.Create(Application) do
try
Connection.BeginTrans;
if AddTicket(Connection) then
Connection.CommitTrans
else
Connection.RollbackTrans;
finally
Free;
end;
TicketsView.EndUpdate;
end;Внутрь самой процедуры AddTicket: Код:
function TFormTicketNew.Execute(iConnection: TADOConnection): boolean;
begin
AddTicketCom.Connection := iConnection;
while not Result do
begin
Result := ShowModal = mrOk;
if VarIsNull(edParamPerson.EditValue) then
begin
MessageBox(Handle, pChar('Вы не указали информацию о Клиенте.'),
pChar('Неверные сведения'), MB_ICONERROR or MB_OK);
edParamPerson.SetFocus;
Result := false;
Continue;
end;
if VarIsNull(edParamLoan.EditValue) then
begin
MessageBox(Handle, pChar('Вы не указали информацию о Ссуде.'),
pChar('Неверные сведения'), MB_ICONERROR or MB_OK);
edParamLoan.SetFocus;
Result := false;
Continue;
end;
end;
AddTicket.Parameters.ParamByName('PawnshopID').Value := 1;
AddTicket.Parameters.ParamByName('StatusID').Value := 1;
AddTicket.Parameters.ParamByName('iNo').Value := 10000;
AddTicket.Parameters.ParamByName('iStartDate').Value := Date;
AddTicket.Parameters.ParamByName('iEndDate').Value := IncDay(Date, 29);
AddTicket.Execute;
// использую вот это AddTicket.Parameters.ParamByName('NewID').Value; для дальнейшего добавления в подчинённую таблицу
end;Не могу никак организовать логику: у меня есть проверки на заполненные поля. Если поле не заполнено, форма не должна уничтожаться (т.е. нужен While цикл) и при этом ещё нужно как-то обрабатывать когда модальную форму просто закрывают) Конструкция пока видится ... не видится ![]() Последний раз редактировалось Uniq!, 08.09.2014 в 13:05. |
|
#41
|
|||
|
|||
|
Смотри TForm.OnCloseQuery.
В этом обработчике ты определяешь, были сделаны изменения в данных или нет. Классика обработки: 1) Пользователь закрывает форму (нажимает кнопку закрыть и т.п.); 2) Диалог сохранения данных; 3) Пользователь не хочет сохранять данные, тогда ROLLBACK; 4) Пользователь хочет сохранять данные, тогда проверка и если все ОК, то COMMIT. Последний раз редактировалось kaakaa, 08.09.2014 в 13:23. |