Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / как задать конструктор записи по умолчанию? / 19 сообщений из 19, страница 1 из 1
15.08.2020, 21:53
    #39990137
GrigoriyFomin
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
Всем доброго вечера. Разбираюсь с методами записей - вещь вельми удобная и интересная, начал использовать ее для работы с БД. Но вот не могу разобраться. У меня уже немало кода используют локальные переменные-записи. недавно обнаружил, что объявленные локально в функциях/процедурах/событиях переменные-записи содержат внутри мусор, по моей логике работы с записями - не всегда все поля задаются явно по алгоритму, и не присвоенные в коде процедуры поля записи остаются непроинициализированные, соотв. с мусором. Так выявилась проблема, что поле типа TDateTime, которое не было присвоено в коде, при записи в БД вызывало арифметическую ошибку.
Суть проблемы - я так понял, нельзя задать свой дефолтный конструктор для записи. То есть задать во всех моих записях конструктор по умолчанию, чтоб он занулял все поля. Нужно добавить свой конструктор с каким-то параметром и потом перед использованием переменной-записи вызывать его явно в начале использования. (как-то сумбурно описал, но надеюсь вы смогли что-то понять). Грубо говоря - есть уже готовый код с использованием переменных-записей. Можно ли без добавления явного конструктора-обнулятора в каждом применении переменной-записи обнулить переменную-запись? Как я понял из документации - нельзя, но вдруг я плохой чукча-читатель?
Вот пример.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
type
	TcfCash=record
    CID					:Int64;
    CFROM       :Int32;
    CTO         :Int32;
    CTYPE       :Int32;
    CPAYMENT    :Currency;
    CDATE       :TDateTime;
    CCAID       :Int32;
    CACCEPTED   :TDateTime;
    CCANCELED   :TDateTime;
    CCONFIRMED  :TDateTime;
    CVIEWED     :TDateTime;
    EMPID       :Int32;
    CDESCR      :string;
    CNO         :string;
    CDEST       :string;
    DBDATE      :TDateTime;
    CORDID      :Int64;
    CPARENT     :Int64;

    function 	 	AddCurrent(Atrs:TFDTransaction):Int64;
    function 	 	LoadToCurrent(ACID:Int64):boolean;
end;


////////////////////
function TcfCash.AddCurrent(Atrs:TFDTransaction):Int64;
var qw:TFDQuery;
begin
	qw:=TFDQuery.Create(nil);
	qw.Connection:=DM.conCF;
  qw.Transaction:=Atrs;
  qw.UpdateOptions.AutoCommitUpdates:=False;
  qw.UpdateTransaction:=Atrs;
  qw.SQL.Text:=
' insert into CASH (CFROM, CTO, CTYPE, CPAYMENT, CDATE, CCAID, CACCEPTED, CCANCELED, CCONFIRMED, CVIEWED, EMPID, CDESCR, '+
'                  CNO, CDEST, DBDATE, CORDID, CPARENT) '+
' values (:CFROM, :CTO, :CTYPE, :CPAYMENT, :CDATE, :CCAID, :CACCEPTED, :CCANCELED, :CCONFIRMED, :CVIEWED, :EMPID, :CDESCR, '+
'        :CNO, :CDEST, ''now'', :CORDID, :CPARENT) '+
' returning CID ';

	SetParamIfNot0(CFROM,				qw.ParamByName('CFROM'));
	SetParamIfNot0(CTO,					qw.ParamByName('CTO'));
  qw.ParamByName('CTYPE').AsInteger			:=CTYPE;
  qw.ParamByName('CPAYMENT').AsCurrency	:=CPAYMENT;
  qw.ParamByName('CDATE').AsDateTime		:=CDATE;
  qw.ParamByName('CCAID').AsInteger			:=CCAID;
  qw.ParamByName('EMPID').AsInteger			:=EMPID;
	SetParamIfNot0(CACCEPTED,		qw.ParamByName('CACCEPTED'));
	SetParamIfNot0(CCANCELED,		qw.ParamByName('CCANCELED'));
	SetParamIfNot0(CCONFIRMED,	qw.ParamByName('CCONFIRMED'));
	SetParamIfNot0(CVIEWED,			qw.ParamByName('CVIEWED'));
	SetParamIfNot0(CDESCR,			qw.ParamByName('CDESCR'));
	SetParamIfNot0(CNO,					qw.ParamByName('CNO'));
	SetParamIfNot0(CDEST,				qw.ParamByName('CDEST'));
	SetParamIfNot0(CORDID,			qw.ParamByName('CORDID'));
	SetParamIfNot0(CPARENT,			qw.ParamByName('CPARENT'));
  qw.active:=true;

  CID:=		qw.FieldByName('CID').AsLargeInt;
	result:=qw.FieldByName('CID').AsLargeInt;
	qw.Free;
end;


SetParamIfNot0 - это функция, которая очищает параметр (clear), если значение поля нулевое
Так вот, если я какое-то поле принудительно не зануля в своем коде - по умолчанию оно может быть совсем не нулевое и выходить за рамки сущности (как с датой - в поле TDateTime был мусор, который и не нулевой, и при записи в БД сыпал ошибку)
...
Рейтинг: 0 / 0
15.08.2020, 22:12
    #39990142
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
GrigoriyFomin,

В 10.4 появилась возможность перегружать операторы инициализаци, финализации и присваивания:
Код: pascal
1.
2.
3.
class operator Initialize(out Value : TMyRec);
class operator Finalize(var Value : TMyRec);
class operator Assign(var Dst : TMyRec; const [ref] Src : TMyRec);
...
Рейтинг: 0 / 0
15.08.2020, 22:20
    #39990146
GrigoriyFomin
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
Kazantsev Alexey
GrigoriyFomin,

В 10.4 появилась возможность перегружать операторы инициализаци, финализации и присваивания:
Код: pascal
1.
2.
3.
class operator Initialize(out Value : TMyRec);
class operator Finalize(var Value : TMyRec);
class operator Assign(var Dst : TMyRec; const [ref] Src : TMyRec);



на 10.4 смысла переходить пока не вижу - сыро и убого пока. А на более ранних получается нет возможности?
...
Рейтинг: 0 / 0
15.08.2020, 22:34
    #39990152
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
GrigoriyFomin
А на более ранних получается нет возможности?

Без хаков - нет. С хаками, можно захучить продеруру InitializeRecord из system.pas, но решение так себе.
...
Рейтинг: 0 / 0
16.08.2020, 09:07
    #39990189
DmSer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
GrigoriyFomin,
Лайфхак: добавьте в запись динамический массив и выставьте ему длину 1 элемент при обнулении полей. Далее проверяйте длину массива. Если массив пуст, значит работать нельзя.
...
Рейтинг: 0 / 0
16.08.2020, 15:33
    #39990211
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
Извратное, но рабочее, решение:

Можно сделать переменные рекорда приватными, доступ к ним организовать через проперти.
Дополнительно в рекорде добавить манаджед переменную (например строку).
И в геттере проверять на значение этой строки, если она пустая - инициализировать значения всх анманаджед переменных в рекорде. Ну и зачение строки менять на признак того что рекорд заинициализирован.
...
Рейтинг: 0 / 0
17.08.2020, 01:40
    #39990234
Bred eFeM
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
GrigoriyFomin, хороший вопрос уже содержит ответ -
вызывать его явно в начале использования
или засплайсить/подменить InitializeRecord (да, лень она такая!)
Но, как говорят классики - нужно проверять входные значения на корректность (IsNan)
...
Рейтинг: 0 / 0
17.08.2020, 10:39
    #39990275
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
rgreat
Извратное, но рабочее, решение:
Можно сделать переменные рекорда приватными, доступ к ним организовать через проперти.

Да нормальное решение.
...
Рейтинг: 0 / 0
17.08.2020, 10:48
    #39990277
delphinotes
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
Переменные типа record, как и остальные "простые" переменные, требует явной инициализации (без которой в себе содержат мусор).

Если есть привычка обнулять локальные переменные простым присваиванием и нет желания дёргать спец.функцию инициализации, можно сделать, например так:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
// глобальная переменная (можно спрятать в классе-хелпере)
var
  GZeroCash: TcfCash;

initialization
  // быстрое "обнуление" (можно вынести в класс-конструктор хелпера)
  ZeroMemory(@GZeroCash, SizeOf(GZeroCash));

// где-то в коде:
  // инициализация простым присваиванием
  MyCash := GZeroCash;
  // и далее работа
  MyCash.CID := ...;
...
Рейтинг: 0 / 0
17.08.2020, 12:24
    #39990304
Мимопроходящий
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
delphinotes, F1: Declaring variables
...
Рейтинг: 0 / 0
17.08.2020, 12:44
    #39990314
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
delphinotes

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
// глобальная переменная (можно спрятать в классе-хелпере)
var
  GZeroCash: TcfCash;

initialization
  // быстрое "обнуление" (можно вынести в класс-конструктор хелпера)
  ZeroMemory(@GZeroCash, SizeOf(GZeroCash));

// где-то в коде:
  // инициализация простым присваиванием
  MyCash := GZeroCash;
  // и далее работа
  MyCash.CID := ...;


Код: pascal
1.
2.
  MyCash := Default(TcfCash);
  MyCash.CID := ...;
...
Рейтинг: 0 / 0
17.08.2020, 13:05
    #39990322
makhaon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
delphinotes,

так лучше:

Код: pascal
1.
 GZeroCash := Default(TcfCash);
...
Рейтинг: 0 / 0
17.08.2020, 13:11
    #39990325
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
makhaon
delphinotes,

так лучше:
Код: pascal
1.
 GZeroCash := Default(TcfCash);


И зачем вообще эта прокладка нужна?..
...
Рейтинг: 0 / 0
17.08.2020, 13:27
    #39990330
makhaon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
alekcvp,

какая прокладка?

Код: pascal
1.
2.
3.
// глобальная переменная (можно спрятать в классе-хелпере)
var
  GZeroCash: TcfCash;
...
Рейтинг: 0 / 0
17.08.2020, 14:03
    #39990339
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
makhaon
alekcvp,
какая прокладка?

Он эту переменную создал чтобы её обнулить и присваивать её нормальным. Зачем так делать, если можно обнулять сразу нужные?
...
Рейтинг: 0 / 0
17.08.2020, 14:07
    #39990340
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
alekcvp
Он эту переменную создал чтобы её обнулить и присваивать её нормальным. Зачем так делать, если можно обнулять сразу нужные?

После появления Default не нужно. Это прием из старой школы.
...
Рейтинг: 0 / 0
17.08.2020, 17:42
    #39990369
makhaon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
alekcvp,

не понял о чем речь. вот глобальная переменная:

Код: pascal
1.
2.
3.
// глобальная переменная (можно спрятать в классе-хелпере)
var
  GZeroCash: TcfCash;



ее нужно очищать. и лучше это делать как Default, а не как ZeroMemory. какая прокладка?
...
Рейтинг: 0 / 0
17.08.2020, 17:44
    #39990370
Мимопроходящий
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
ГЛОБАЛЬНЫЕ переменные очищать НЕ НУЖНО!
RTFM уже в конце концов.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
17.08.2020, 21:41
    #39990407
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
как задать конструктор записи по умолчанию?
makhaon
alekcvp,

не понял о чем речь. вот глобальная переменная:
ее нужно очищать. и лучше это делать как Default, а не как ZeroMemory. какая прокладка?

Ему нужно очищать локальные переменные, а не глобальные. И он делает это присваивая им пустую глобальную переменную , т.е. прокладку.
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / как задать конструктор записи по умолчанию? / 19 сообщений из 19, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]