![]() |
|
|
#1
|
||||
|
||||
|
товарищи давайте обсудим столь интересную тему.
было бы очень интересно узнать кто как подходит к решению данного вопроса. в книгах пишут про ООП что это круто и здорово, но примеров - просто нет. взглянуть бы хоть на один исходник, или хотя бы интерфейсную часть модуля работы с БД. Я думаю ни одного меня это интересует |
|
#2
|
||||
|
||||
|
Взгляни на adodb.pas
![]() |
|
#3
|
||||
|
||||
|
типа посмеялся?
да смешно!с компонентный подходом всё ясно (об этом много говорим), интересен именно ООП |
|
#4
|
||||
|
||||
|
Единственная объектная БД с которой приходилось работать - 1С. И то там все довольно убого. Да и не в топик про нее
![]() |
|
#5
|
||||
|
||||
|
Да нет. Я не про объектные БД.
Предположим у меня есть класс "Сотрудник" с полями "имя", "фамилия", "должность" и данные будут загружаться из базы, ну и сохраняться понятно тоже будут в ней же. Так вот как мне заносить/сохранять данные из БД? бросить на форму какой-нить Connection, прицепить к нему какой-нить DataSet? так чтож здесь от ООП? компоненты и не более. |
|
#6
|
||||
|
||||
|
Значит твой объект "Сотрудник" должен иметь методы сохранения и чтения себя из базы. И разработчик пользующийся этим объектом не должен думать о том что нужно бросить что-то еще на форму
![]() |
|
#7
|
||||
|
||||
|
Есть консэнсус!
Собственно об этом и тема! Как это реализовать? В класс запихивать Connection и DataSet? это не выход. Ну вот как например ты делаешь? есть у тебя подобный опыт? |
|
#8
|
||||
|
||||
|
Ну Connection конечно пихать в класс не стоит, можно передавать его в конструктор при создании. А вот DataSet'ы различные можно реализовать и внутри класса.
|
|
#9
|
||||
|
||||
|
А как поступать когда класс содержит в себе другой класс, а он в свою очередь еще...
пример: класс "Район" содержит в себе класс "Муниципальное образование", в нем есть класс "Населенный пункт" в котором есть "Улица". Понятно каждый класс работает с БД. Передаем Connection в "Район" а он в свою очередь раздает всем остальным? Ты считаешь не коряво выходит? |
|
#10
|
||||
|
||||
|
...а вообще было бы здорово посмотреть на чей нибудь исходник...
|
|
#11
|
||||
|
||||
|
Цитата:
![]() |
|
#12
|
||||
|
||||
|
есть исходник? не жадничай - покажи!
|
|
#13
|
||||
|
||||
|
с инкапсуляцией-то всё понятно, спрятать можно всё что угодно. но тему я эту открыл не от того что не знаю как это сделать.
хочу посмотреть (или обсудить) как это делают другие программисты. ещё раз повторюсь данный вопрос очень скудно освещён, или не освещен вовсе. |
|
#14
|
||||
|
||||
|
Эх, въедливый. Ну да это и не плохо. Что ж, будем писать объектную БД на дельфях. Чисто для обучения.
Для начала нам понадобится движок, можно конечно взять любой, но мы не ищем легких путей, поэтому напишем свой, простой до безобразия, зато все внутненности работы будут нам понятны. Вот что получилось набросать за последний час рабочего дня ![]() Код:
unit AbstractDB;
{
Модуль реализующий класс абстрактного движка БД
Эта БД ничего особого не умеет :)
Но для примера она нам пригодится
Работаем только со строками длинной в 250 символов - никаких других типов
Процедуры чтения и записи данных по индексу в БД
+ процедура пометки записи на удаление
}
interface
uses
Classes;
const
DeleteFlag = $FF; //признак того что данная запись в БД помечена на удаление
type
TMyRec = string[250]; //Это будет нашей записью
TAbstractDB = class //Это класс самого движка
protected
FFileName:string; //Тут имя файла с которым будем работать
FData:TFileStream; //Объект для работы с файлом (кстати, тут умное слово ИНКАПСУЛЯЦИЯ)
FBuffer:array [1..255] of byte; //Буффер чтения/записи (ПОЧЕМУ длинна буфера не равна длине данных - потому что первые 5 байт будем использовать для системных нужд)
function ReadData(i:integer):TMyRec; //Функция реализующая чтение
procedure WriteData(i:integer;data:TMyRec); //Процедура реализующая запись
public
constructor Create (aFileName:string); //Конструктор
destructor Destroy; override; //Деструктор
procedure Delete (index:integer); //Процедура ПОМЕТКИ на удаление
property data[index:integer]:TMyRec read ReadData write WriteData; //Единственное (пока??) свойство доступа к данным
end;
implementation
uses SysUtils;
{ TAbstractDB }
constructor TAbstractDB.Create(aFileName: string);
begin
inherited Create;
if FileExists(aFileName) then
FData:=TFileStream.Create(aFileName,fmOpenReadWrite)
else
FData:=TFileStream.Create(aFileName,fmCreate);
end;
procedure TAbstractDB.Delete(index: integer);
{
Пометка записи на удаление
i - номер записи которую хотим того :)
}
begin
if FData.Size>=(index-1)*255 then //проверим не вывалимся ли за границу файла
begin
FData.Seek((index-1)*255,soFromBeginning); //спозиционируем курсор в файле
FData.ReadBuffer(FBuffer[1],255); //читаем
FBuffer[1]:=DeleteFlag; //установили пометку
FData.WriteBuffer(FBuffer[1],255); //записали назад
end;
end;
destructor TAbstractDB.Destroy;
begin
FData.Destroy; //Файл не забыли грохнуть
inherited;
end;
function TAbstractDB.ReadData(i: integer): TMyRec;
{
Чтение данных из базы
i - номер читаемой записи
result - наши мега данные :)
}
begin
if FData.Size>=(i-1)*255 then //проверим не вывалимся ли за границу файла
begin
FData.Seek((i-1)*255,soFromBeginning); //спозиционируем курсор в файле
FData.ReadBuffer(FBuffer[1],255); //читаем
Move(FBuffer[6],result[1],250);
end;
end;
procedure TAbstractDB.WriteData(i: integer; data: TMyRec);
{
Запись данных в БД
i - номер записи по порядку (нумерация с нуля)
data - данные
}
begin
if FData.Size>=(i-1)*255 then //проверим не вывалимся ли за границу файла
begin
FillChar(FBuffer[1],255,#0); //очистим буффер
Move(data[1],FBuffer[6],250); //скопируем в него инфу
FData.Seek((i-1)*255,soFromBeginning); //спозиционируем курсор в файле
FData.WriteBuffer(FBuffer[1],255); //Запишем данные
end;
end;
end.пример использования: Код:
var
i:TAbstractDB;
begin
i:=TAbstractDB.Create('c:\data.ADB');
i.data[1]:='какой-то там текст';
i.data[2]:='другой текст';
ShowMessage(i.data[2]);
i.Free;
end;т.к. рабочий день закончился продолжим чуть поздже (когда до дому доберусь). Пока можно задавать вопросы по "движку". |
| Этот пользователь сказал Спасибо Aristarh Dark за это полезное сообщение: | ||
gerych (14.01.2012)
| ||
|
#15
|
||||
|
||||
|
Шаришь! ничё ни скажешь.
но я все же немного про другое, до своего ADO или dbExpress я еще не дорос лучше будет если я покажу код, а ты скажешь что в нем не верно Код:
unit ObjectAdress;
interface
uses ADODB, Contnrs;
type
TMunicList = class;
TTownList = class;
TStreetList = class;
TAdrObj = class
private
FName: string;
FParent: integer;
FConnection: TADOConnection;
FID: integer;
procedure SetConnection(const Value: TADOConnection);
procedure SetID(const Value: integer);
procedure SetName(const Value: string);
procedure SetParent(const Value: integer);
public
property ID: integer read FID write SetID;
property Name: string read FName write SetName;
property Connection: TADOConnection read FConnection write SetConnection;
property Parent: integer read FParent write SetParent;
end;
TMunicTown = class(TAdrObj)
private
FKadastralNumber: string;
FOKATO: string;
procedure SetKadastralNumber(const Value: string);
procedure SetOKATO(const Value: string);
public
property OKATO: string read FOKATO write SetOKATO;
property KadastralNumber: string read FKadastralNumber write SetKadastralNumber;
end;
TAdrList = class(TObjectList)
private
DataSet: TADODataSet;
FParent: integer;
FConnection: TADOConnection;
procedure SetConnection(const Value: TADOConnection);
procedure SetParent(const Value: integer);
public
constructor Create;
property Connection: TADOConnection read FConnection write SetConnection;
property Parent: integer read FParent write SetParent;
end;
TRaion = class(TAdrObj)
private
FMunicList: TMunicList;
procedure SetMunicList(const Value: TMunicList);
function GetMunicList: TMunicList;
public
procedure CreateMunicList;
property MunicList: TMunicList read GetMunicList write SetMunicList;
end;
TMunic = class(TMunicTown)
private
FTownList: TTownList;
procedure SetTownList(const Value: TTownList);
function GetTownList: TTownList;
public
procedure CreateTownList;
property TownList: TTownList read GetTownList write SetTownList;
end;
TTown = class(TMunicTown)
private
FStreetList: TStreetList;
FPrefix: string;
procedure SetStreetList(const Value: TStreetList);
procedure SetPrefix(const Value: string);
function GetStreetList: TStreetList;
public
procedure CreateStreetList;
property Prefix: string read FPrefix write SetPrefix;
property StreetList: TStreetList read GetStreetList write SetStreetList;
end;
TStreet = class(TAdrObj)
private
FDocument: string;
FPrefix: string;
procedure SetDocument(const Value: string);
procedure SetPrefix(const Value: string);
public
property Document: string read FDocument write SetDocument;
property Prefix: string read FPrefix write SetPrefix;
end;
TRaionList = class(TAdrList)
protected
procedure Put(Index: integer; Item: TRaion);
function Get(Index: integer): TRaion;
public
property Items[Index: integer]: TRaion read Get write Put; default;
function Add(Raion: TRaion): integer;
procedure ReadFromDB;
end;
TMunicList = class(TAdrList)
protected
procedure Put(Index: integer; Item: TMunic);
function Get(Index: integer): TMunic;
public
property Items[Index: integer]: TMunic read Get write Put; default;
function Add(Munic: TMunic): integer;
procedure ReadFromDB;
end;
TTownList = class(TAdrList)
protected
procedure Put(Index: integer; Item: TTown);
function Get(Index: integer): TTown;
public
property Items[Index: integer]: TTown read Get write Put; default;
function Add(Town: TTown): integer;
procedure ReadFromDB;
end;
TStreetList = class(TAdrList)
protected
procedure Put(Index: integer; Item: TStreet);
function Get(Index: integer): TStreet;
public
property Items[Index: integer]: TStreet read Get write Put; default;
function Add(Street: TStreet): integer;
procedure ReadFromDB;
end;
implementation
{ TRaionList }
const
cSQL_GetRaion: string =
'SELECT id, name FROM adr WHERE lvl = 1';
function TRaionList.Add(Raion: TRaion): integer;
begin
Result := inherited Add(Raion);
end;
function TRaionList.Get(Index: integer): TRaion;
begin
if Count -1 >= Index then
Result := TRaion(inherited Items[Index])
else
Result := nil;
end;
procedure TRaionList.Put(Index: integer; Item: TRaion);
begin
inherited Items[Index] := Item;
end;
procedure TRaionList.ReadFromDB;
var i: integer;
begin
Clear;
DataSet.Connection := Self.Connection;
DataSet.CommandText := cSQL_GetRaion;
DataSet.Open;
while not DataSet.Eof do
begin
i := Add(TRaion.Create);
Items[i].Id := DataSet.FieldByName('id').AsInteger;
Items[i].Name := DataSet.FieldByName('name').AsString;
Items[i].Connection := Self.Connection;
Items[i].Parent := Parent;
Items[i].CreateMunicList;
DataSet.Next
end;
DataSet.Close;
end;
{ TAdrObj }
procedure TAdrObj.SetConnection(const Value: TADOConnection);
begin
FConnection := Value;
end;
procedure TAdrObj.SetID(const Value: integer);
begin
FID := Value;
end;
procedure TAdrObj.SetName(const Value: string);
begin
FName := Value;
end;
procedure TAdrObj.SetParent(const Value: integer);
begin
FParent := Value;
end;
{ TAdrList }
constructor TAdrList.Create;
begin
DataSet := TADODataSet.Create(nil);
self.FParent := 0;
end;
procedure TAdrList.SetConnection(const Value: TADOConnection);
begin
FConnection := Value;
end;
procedure TAdrList.SetParent(const Value: integer);
begin
FParent := Value;
end;
{ TMunicTown }
procedure TMunicTown.SetKadastralNumber(const Value: string);
begin
FKadastralNumber := Value;
end;
procedure TMunicTown.SetOKATO(const Value: string);
begin
FOKATO := Value;
end;
{ TMunicList }
const
cSQL_GetMunicFromParent: string =
'SELECT id, name, okato, kadastr FROM adr WHERE lvl = 2 AND' +
' parent_id = :parent_id';
//реализация методов аналогично TRaionList
function TMunicList.Add(Munic: TMunic): integer;
function TMunicList.Get(Index: integer): TMunic;
procedure TMunicList.Put(Index: integer; Item: TMunic);
procedure TMunicList.ReadFromDB;
{ TRaion }
procedure TRaion.CreateMunicList;
begin
FMunicList := TMunicList.Create;
FMunicList.Connection := Self.Connection;
FMunicList.Parent := Self.ID;
end;
function TRaion.GetMunicList: TMunicList;
begin
if FMunicList.Count = 0 then
FMunicList.ReadFromDB;
Result := FMunicList;
end;
procedure TRaion.SetMunicList(const Value: TMunicList);
begin
FMunicList := Value;
end;
{ TTownList }
const
cSQL_GetTownFromParent: string =
'SELECT id, pref, name, okato, kadastr FROM adr WHERE lvl = 3 AND' +
' parent_id = :parent_id';
//реализация методов аналогично TRaionList
function TTownList.Add(Town: TTown): integer;
function TTownList.Get(Index: integer): TTown;
procedure TTownList.Put(Index: integer; Item: TTown);
procedure TTownList.ReadFromDB;
{ TMunic }
procedure TMunic.CreateTownList;
begin
FTownList := TTownList.Create;
FTownList.Connection := Self.Connection;
FTownList.Parent := Self.ID;
end;
function TMunic.GetTownList: TTownList;
begin
if FTownList.Count = 0 then
FTownList.ReadFromDB;
Result := FTownList
end;
procedure TMunic.SetTownList(const Value: TTownList);
begin
FTownList := Value;
end;
{ TStreet }
procedure TStreet.SetDocument(const Value: string);
begin
FDocument := Value;
end;
procedure TStreet.SetPrefix(const Value: string);
begin
FPrefix := Value;
end;
{ TStreetList }
const
cSQL_GetStreetFromParent: string =
'SELECT adr.id, pref, adr.name, doc.name ' +
'FROM adr INNER JOIN doc ON doc.id = adr.id_doc ' +
'WHERE lvl = 4 AND parent_id = :parent_id';
//реализация методов аналогично TRaionList
function TStreetList.Add(Street: TStreet): integer;
function TStreetList.Get(Index: integer): TStreet;
procedure TStreetList.Put(Index: integer; Item: TStreet);
procedure TStreetList.ReadFromDB;
{ TTown }
procedure TTown.CreateStreetList;
begin
FStreetList := TStreetList.Create;
FStreetList.Connection := Self.Connection;
FStreetList.Parent := Self.ID;
end;
function TTown.GetStreetList: TStreetList;
begin
if FStreetList.Count = 0 then
FStreetList.ReadFromDB;
Result := FStreetList
end;
procedure TTown.SetPrefix(const Value: string);
begin
FPrefix := Value;
end;
procedure TTown.SetStreetList(const Value: TStreetList);
begin
FStreetList := Value;
end;
end. |