Это что-то вроде примитивной самопальной ОРМ, реализованной через несколько видов генераторов и построителей.
Это одна из важнейших функций в этой системе.
Принцип работы: берётся датасет некой сущности (таблицы) с полями типа 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 компонент для связи с бд - адоконнекшн, никаких датасурсов квери филдов и прочего, всё что нужно программа сама генерит.