![]() |
|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#6
|
|||
|
|||
![]() Это что-то вроде примитивной самопальной ОРМ, реализованной через несколько видов генераторов и построителей.
Это одна из важнейших функций в этой системе. Принцип работы: берётся датасет некой сущности (таблицы) с полями типа ID ID_Foo ID_Bar и другими какими-нибудь. Этот датасет модифицируется так, что из его скрываются для показа системные поля (концепция в архитектуре таблиц БД), а к ссылочным полям клеются лукап-датасеты других сущностей, через менеджер, умеющий разруливать ссылочные поля этой сущности в нужные датасеты других сущностей. Менеджер по сути просто делает запрос к базе и выдаёт ссылку на закреплённый за запросом датасет. Код:
procedure TBase.ModifyDataSet(ADataSet: TDataSet); var i: Integer; Field: TStringField; FieldName: string; LookupEnt: TEntity; FldCnt: Integer; IsLookup: Boolean; BM: TBookMark; begin BM := ADataSet.GetBookMark; ADataSet.Close; FldCnt := 0; ADataSet.Fields.Clear; for i := 0 to ADataSet.FieldDefs.Count - 1 do begin if not ADataSet.FieldDefs.Updated then ADataSet.FieldDefs.Update; if ADataSet.FindField(ADataSet.FieldDefs[i].Name) = nil then ADataSet.FieldDefs[i].CreateField(ADataSet); // если это ссылочное поле IsLookup := (Pos('ID_', ADataSet.FieldDefs[i].Name) <> 0); // дополнительные условия отрезаны if IsLookup then try FieldName := ADataSet.FieldDefs[i].Name; Delete(FieldName, 1, 3); // delete 'ID_' Field := TWideStringField.Create(nil); Field.Size := 128; Field.FieldName := FieldName; Field.FieldKind := fkLookup; Field.KeyFields := ADataSet.FieldDefs[i].Name; // определим на что ссылается, у меня в проекте это Сущность/Entity LookupEnt := TEntity(EnumValue(EntP, FieldName, 'xe')); // спец. менеджер выдаёт нужный датасет для данной энтити Field.LookupDataSet := Manager.GetData(LookupEnt); // биндим поле которое будет источником инфы по ссылке FLookupField := 'Caption'; if not Assigned(Field.LookupDataSet.FindField(FLookupField)) then FLookupField := 'Name'; Field.LookupResultField := FLookupField; Field.DisplayWidth := MinWd + 1; Field.LookupKeyFields := 'ID'; Field.DataSet := ADataSet; except raise; end; // дообработка в наследниках формы SpecModifying(FldCnt, ADataSet.Fielddefs[i].Name, IsLookup); // учёт "системных" полей таблицы if not (AnsiSameText('ID', ADataSet.FieldDefs[i].Name) or AnsiSameText('IsDeleted', ADataSet.FieldDefs[i].Name)) then Inc(FldCnt); end; ADataSet.Open; GotoBookMark(ADataSet, BM); end; В итоге в датасете остаются просто поля, системные скрываются, а вот ссылочные не только скрываются, но ещё и датасет дополняется колонками из лукап-полей, показывающих поле Caption или Name из соответствующих датасетов сущностей Foo и Bar. Этот приём позволяет добавлять и удалять таблицы, менять их поля, связи с другими таблицами, а код в программе, реализующий CRUD не меняется, везде по максимум сделана унификация, но с возможностью переопределния некоторых вещей в наследниках, только для каких-то более сложных задач дописывается вручную обработка. Надо заметить, что и база данных тоже строится/генерируется частично, что тоже способствует гибкости. Уже на нескольких проектах эта архитектура себя показывает вполне достойно. И да, нет никакого визуального проектирования работы с базой из дельфи, используется только 1 компонент для связи с бд - адоконнекшн, никаких датасурсов квери филдов и прочего, всё что нужно программа сама генерит. Последний раз редактировалось phomm, 27.11.2014 в 20:46. |
Этот пользователь сказал Спасибо phomm за это полезное сообщение: | ||
djmix (30.11.2014)
|