Аннотация:
Как обеспечить единообразную работу с данными, хранящимися в БД (DBase, Interbase, MS SQL Server и т.п.), и с другими, в частности, с локальными данными программы? В статье рассматривается создание потомка TDataSet для организации "виртуальной" БД на базе произвольного источника данных.
Специалист — это варвар, невежество которого не всесторонне :)
Я обнаружил ошибку в Вашем коде. Она проявляется таким
образом — если сразу после запуска тестового проекта
вставить новую запись, то происходит AV.
Если же сначала отредактировать запись или додавить Append'ом, то последующие
Inset'ы проходят нормально.
Это связано с ошибкой при создания нового буфера.
Буфер для новой записи не инициализируется и его поля RecordIndex и BookmarkFlag указывают в никуда. Поэтому при обновлении данных на экране (для грида) и происходи AV.
Лечится простой доработкой:
function TMyDataSet.AllocRecordBuffer: PChar;
begin
GetMem(result,sizeof(TRecordBuffer));
PRecordBuffer(Result)^.RecordIndex := 0;
PRecordBuffer(Result)^.BookmarkFlag := bfCurrent;
end;
Максим, я не разобрался, как в GetFieldData выводить Null значения в предложенной схеме.
Помогла простая переделка:
FPerformGetFieldData:procedure (Index:integer; Field: TField; out Data) of object;
заменил на
FPerformGetFieldData:function (Index:integer; Field: TField; out Data): Boolean of object;
Если значение поля NULL, то результат будет False.
... По ушам лупит "начальство" ...
Re: Использование DB Controls без базы данных
От:
Аноним
Дата:
10.10.03 05:05
Оценка:
Здравствуйте, Максим Гумеров.
Заинтересовался вашей статьей и решил попробовать Вашего наследника TDataSet.
При этом столкнулся с ошибкой при отображении даты.
Как правильно поместить значение даты в Data?
У меня такой код
TDateTime(Data) := TMyRecord(List[Index]).Date;
вызывает ошибку
---------------------------
Debugger Exception Notification
---------------------------
Project Project1.exe raised exception class EConvertError with message ''0.37904' is not a valid timestamp'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------
Нашел, что ошибка возникает здесь:
function NativeToDateTime(DataType: TFieldType; Data: TDateTimeRec): TDateTime;
var
TimeStamp: TTimeStamp;
begin
case DataType of
ftDate:
begin
TimeStamp.Time := 0;
TimeStamp.Date := Data.Date;
end;
ftTime:
begin
TimeStamp.Time := Data.Time;
TimeStamp.Date := DateDelta;
end;
else
try
TimeStamp := MSecsToTimeStamp(Data.DateTime); // Попадает сюдаexcept
TimeStamp.Time := 0;
TimeStamp.Date := 0;
end;
end;
Result := TimeStampToDateTime(TimeStamp); // и здесь возникает ошибка end;
function TimeStampToDateTime(const TimeStamp: TTimeStamp): TDateTime;
asm
PUSH EBX
{$IFDEF PIC}
PUSH EAX
CALL GetGOT
MOV EBX,EAX
POP EAX
{$ELSE}
XOR EBX,EBX
{$ENDIF}
PUSH EAX
CALL ValidateTimeStamp // Вот тут вот
POP EAX
MOV ECX,[EAX].TTimeStamp.Time
MOV EAX,[EAX].TTimeStamp.Date
SUB EAX,DateDelta
IMUL [EBX].IMSecsPerDay
OR EDX,EDX
JNS @@1
SUB EAX,ECX
SBB EDX,0
JMP @@2
@@1: ADD EAX,ECX
ADC EDX,0
@@2: PUSH EDX
PUSH EAX
FILD QWORD PTR [ESP]
FDIV [EBX].FMSecsPerDay
ADD ESP,8
POP EBX
end;
Voobshe-to, ya ne uveren, chto eto dolznho rabotat' kak zadumano. K sozhaleniyu, Delphi na etoy moey mashine ne stoit — burzhui poka ofis ne predostavili. Pridetsya gadat'.
Chto takoe "Data", kakoy u nego tip, gde ono nahoditsya? Ne sozdaetsya li pri TDateTime(Data) novaya lokalnaya peremennaya (to est' tuda li proishodit prisvaivanie, kuda nado, to est v Data). I gde proishodit prisvaivanie, v kakoy funczii?
Nu i potom — sama data-to pravilnaya? Naprimer, kakaya vyzyvaet oshibku?
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Re[3]: Использование DB Controls без базы данных
От:
Аноним
Дата:
10.10.03 08:44
Оценка:
Здравствуйте, Slicer [Wirkwood]
Сама дата правильная. Создается как Now.
Но не работает с любой, какую я только не пробовал.
Параметр Data — нетипизированный. вот функция.
Если прочитаете статью, про которую идет речь, то в исходниках найдете метод GetFieldData.
Вот как он выглядит у меня:
procedure TMyData.GetFieldData(Index: integer; Field: TField; out Data);
begin
if @Data = nil then Exit;
case Field.FieldNo of
1:strpcopy(@Data,TMyRecord(List[Index]).Name);
2:strpcopy(@Data,TMyRecord(List[Index]).EMail);
3: Integer(Data) := TMyRecord(List[Index]).Num;
// 4: System.Move(TMyRecord(List[Index]).Date, Data, sizeof(TDateTime));
// 4: Comp(Data) := TimeStampToMSecs(DateTimeToTimeStamp(TMyRecord(List[Index]).Date));
4: TDateTime(Data) := TMyRecord(List[Index]).Date;
end;
end;
С Integer все, как ни странно, работает. Чем TDateTime отличается? Ведь это же простой Double.
А Data — это просто буфер , куда TDataSet данные закачивает, как я понимаю, для отображения.
Хотя, возможно, я не прав.
Nado podumat'. No bez Delphi pod rukoy trudno. Mozhet, poka kto drugoy otvetit?
A vy proverte, kstati, sovpadaet li data iz TMyRecord(...) s toy, kotoraya prihodit v "TimeStamp := MSecsToTimeStamp(Data.DateTime);" v pole Data.DateTime.
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Re[5]: Использование DB Controls без базы данных
От:
Аноним
Дата:
10.10.03 10:49
Оценка:
Проверил. Да и раньше проверял.
Сюда передается дата в виде 37904.607452, что соответствует DateTimeToStr(Date.DateTime) = 10.10.2003 14:34:16
после этого метода
TimeStamp := MSecsToTimeStamp(Data.DateTime)
в TimeStamp содержится TimeStamp(Time: 37905; Date:0), что уже странно.
Сама функция на asm, поэтому я в ней ничего не понимаю.
И потом при вызове
Result := TimeStampToDateTime(TimeStamp)
генерится сообщение
---------------------------
Debugger Exception Notification
---------------------------
Project Project1.exe raised exception class EConvertError with message ''0.37905' is not a valid timestamp'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------
что, видимо правильно, т.к. у меня значение даты округлилось до целых и записалось в поле TTimeStamp.Time почему-то.
Хотя авто в статье явно пишет, что для полей с типом ftDateTime используется тип TDateTime.
В общем, так я ничего и не понял, в чем же дело. Кстати, если кто будет пробоват это пример с TDBGridEh,
то имейте в виду, при вызове метода TField.IsNull валится AV, поэтому в методе GetFieldData надо вставит строку
if @Data = nil then Exit, Это связано с тем, что в качестве параметра Data передается nil.
А сам Exception возникает в другом месте — в функции strlcopy, поэтому сначала непонятно, что случилось.
Кстати, это замечание и автору. Надо-бы подправить примерчик.
Re[6]: Использование DB Controls без базы данных
От:
Аноним
Дата:
10.10.03 11:17
Оценка:
Хм, Максим, извините.
Никак не возьму в привычку смотреть профиль участника.
По нику вас не опознал, т.к. это мои первые посты здесь.
Nichego strashnogo
V obshem, primer peresmotryu, kak doberus' do Delphi. A vot naschet TDateTime eto ya otkuda-to vzyal, vidimo, iz ishodnikov VCL. Tak chto ya ne vinovat Da i po kodu pervoy privedennoy vami funczii ponyatno, chto v 3-em variante on hochet poyuzat' i date, i time, a predydushie 2 varianta sootvetstvovali ftDate i ftTime. V chem oshibka, ne znayu, no ved' data-to prihodit pravilnaya, a exception vyletaet uzhe ne v moem kode...
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, <Аноним>, Вы писали:
А>Проверил. Да и раньше проверял.
А>Сюда передается дата в виде 37904.607452, что соответствует DateTimeToStr(Date.DateTime) = 10.10.2003 14:34:16
А>после этого метода
А>
А>TimeStamp := MSecsToTimeStamp(Data.DateTime)
А>
А>в TimeStamp содержится TimeStamp(Time: 37905; Date:0), что уже странно. А>Сама функция на asm, поэтому я в ней ничего не понимаю.
Вообще-то надо исполльзовать DateTimeToTimeStamp.
Калабухов А.В.
Re[7]: Использование DB Controls без базы данных
От:
Аноним
Дата:
23.10.03 04:58
Оценка:
Здравствуйте, kavlad.
Я тоже так думаю, но ребята из Borland думают иначе .