Как говорит Кен, без образца кода вам сложно помочь. Поэтому я не смогу ответить на ваш вопрос напрямую, но с помощью нескольких указателей вы, возможно, сможете понять это сами. Итак, я попробую научить вас ловить рыбу. ;)
У меня есть неплохой опыт работы с TClientDataSet в Delphi 3 и 6. Я сомневаюсь, что все так сильно изменилось. Кроме того, я собираюсь больше сосредоточиться на методах, которые помогут вам двигаться в правильном направлении.
Во-первых, убедитесь, что вы компилируете с помощью Debug DCU, чтобы можно было получить точки останова в коде VCL. Не бойтесь читать и проходить через этот код - это отличный способ учиться. Кроме того, вы сможете увидеть ошибки Borland / CodeGear / Embarcadero во всей их уродливой красе.
Я предполагаю, что у вас уже включена функция Stop on Exceptions (поэтому вы знаете, что конкретно получаете ошибки AV).
Сделай свой тест. Когда вы получите свой AV, вы, вероятно, выйдете в DbClient.pas (или, возможно, в одном из модулей более низкого уровня).
Пройдите по стеку вызовов в поисках места, в котором вы находитесь в части try блока try..except, который либо поглощает исключение, либо замыкается на другой обработчик, а затем проглатывает его.
ПРИМЕЧАНИЕ. DbClient.pas изобилует несколькими экземплярами следующего плохого кода:
except //swallowing or squashing exceptions is
end; //very dangerous and should be avoided.
except
//short-circuiting to Application.HandleException (usually informs the user)
//but is not much better. The point is the rest of the program up the
//call-stack remains blissfully unaware that something went wrong.
Application.HandleException(Self);
Action := raAbort;
end;
Боковой комментарий: Просто потому, что это сделала Borland, не означает, что это хорошая практика. Вы и многие другие получили и будете обожжены этим.
Как только вы это найдете, вы на полпути. Теперь вы знаете, почему вам не сообщают об антивирусной программе.
Теперь где-нибудь в коде, который является частью этого стека вызовов, будет ключ к пониманию того, как вы должны обрабатывать ошибку. Вы также можете разместить точку останова немного раньше в коде VCL, чтобы можно было пройти через нее, чтобы увидеть последовательность событий, ведущих к исключению. Поскольку вы специально упомянули AV (нарушение прав доступа), ищите объекты, которые ссылаются на nil.
Один из примеров того, что может быть причиной проблемы, приведен в следующем фрагменте из D5 DbClient.pas.
FOnReconcileError(DataSet, E, UpdateKind, Action);
finally
E.Free;
end;
except
Application.HandleException(Self);
Action := raAbort;
end;
Из вышеизложенного видно, что в определенных ситуациях требуется реализовать обработчик событий OnReconcileError. Без этого dll не будет выполнять обратный вызов в приведенный выше фрагмент кода, и многие ошибки незаметно прячутся под ковер, заставляя вас чесать голову.
Мой опыт работы с TClientDataSet показывает, что вам нужно было сделать несколько небольших дополнительных вещей, чтобы использовать его правильно. В документации это было не особо очевидно. Хотя, как только вы выяснили все детали, которые вы должны были делать, примеры того, как их делать, стали немного лучше.
К сожалению, моя память немного нечеткая относительно того, что все это было. Итак, это очень приблизительное руководство, в котором, вероятно, совсем немного отсутствует.
- Рассмотрите возможность использования обработчика событий OnReconcileError.
- Рассмотрите возможность реализации объекта UpdateProvider.
- Вы упомянули, что используете его как набор данных в памяти, поэтому вы, вероятно, правильно используете CreateDataSet. Но если я правильно помню, у вас было 2 варианта указания полей, и некоторые из атрибутов более мелких деталей были немного придирчивыми.
- Несвязанный совет: будьте осторожны с длиной ваших строковых полей, TClientDataSet использовался (и может все еще) заполнять память аналогично коротким строкам.
РЕДАКТИРОВАТЬ
Основываясь на дополнительной информации в вопросе и используя метод, описанный выше, вы получаете ошибку EDatabaseError, создаваемую следующим методом.
procedure TIntegerField.SetAsString(const Value: string);
var
E: Integer;
L: Longint;
begin
if Value = '' then Clear else
begin
Val(Value, L, E);
if E <> 0 then DatabaseErrorFmt(SInvalidIntegerValue, [Value, DisplayName]);
SetAsInteger(L);
end;
end;
Выше по стеку вызовов вы получаете следующий метод, который подсказывает, как решить проблему.
procedure TField.SetEditText(const Value: string);
begin
if Assigned(FOnSetText) then FOnSetText(Self, Value) else SetText(Value);
end;
Кроме того, если вы проследите за стеком вызовов вплоть до нажатия клавиши, вы заметите, что набор данных NO или код сетки вообще не задействован.
Причина, по которой ваши попытки обработать ошибку в OnPost error не сработали, заключается в том, что вы не приближаетесь к попытке опубликовать свою запись. Вы получаете ошибку проверки поля, и место для ее обработки находится в поле.
Возвращаясь к подсказке, как решить эту ошибку - вам нужно будет реализовать событие OnSetText для поля.
ОДНАКО я бы не советовал это делать. Стандартное поведение вполне приемлемо! Пользователь получает сообщение об ошибке, объясняющее, что он сделал не так, и он получает возможность исправить это и повторить попытку. Если они передумают, они могут нажать Escape и отменить редактирование.
person
Disillusioned
schedule
06.06.2012
Table1.Active := True
CreateDataSet
уже делает это (вы можете проверить значение сразу после вызоваCreateDataSet
). Даже если это не причина вашей проблемы, нет смысла снова делать его Активным! В лучшем случае это пустая трата времени. - person Disillusioned   schedule 07.06.2012