|
#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. |