Допустим нам нужно записать файловую директорию \public\files\UserID\2016\28\10\temp в базу данных. Данный алгоритм запишет только папки директории, и не более. Чтобы полностью отразить директорию, нужен обход с рекурсивным алгоритмом, который я представлю чуть позже, в другом посте.
Я сделал это так. Для начала оптимизированный вариант
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 |
procedure TDataBaseUnitServer.WriteDirToDataBase(dir: string); var SplittedString: TArray<String>; idParent:integer; idNextParent: integer; i: Integer; begin // for example we need to write \public\files\UserID\2016\28\10\temp to DataBase // check if dir exists on disk, if ok then continue if not TDirectory.Exists(dir) then exit; //so here could be some error before, dir wasn't created and we exit // divide dir by separator '\' SplittedString:=dir.Split(['\']); // \public is Root dir so idParent=-1 for \public we need [0] number in separated array //ShowMessage(SplittedString[0]); // for test - gives 'public' // adding public if needed // check if not \public already written, if not - write in database with idParent=-1 // writing root element idParent:=-1; idNextParent:=-2; // means negative result if not IsFileOrFolderAlreadyInDB(idParent,SplittedString[0],idNextParent) then InsertFolderOrFileToDB( true, // isFolder idParent, // idParent SplittedString[0], // name SplittedString[2].ToInteger, // users_id -1 // filesize ); // writing all other not root elements for i := 1 to High(SplittedString) do begin if idNextParent=-2 then idParent:=GetLastInsertedID else idParent:=idNextParent; if not IsFileOrFolderAlreadyInDB(idParent,SplittedString[i],idNextParent) then InsertFolderOrFileToDB( true, // isFolder idParent, // idParent SplittedString[i], // name SplittedString[2].ToInteger, // users_id -1 // filesize ); end; end; |
Прикол был с users_id, суть в том, что это поле содержит в себе внешний ключ к таблице пользователей, и если указать при вставке значение, которого нет, то выпадает ошибка. Поэтому тут внимательнее.
Тоже самое, только не в цикле
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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
procedure TDataBaseUnitServer.WriteDirToDataBase(dir: string); var SplittedString: TArray<String>; idParent:integer; idNextParent: integer; i: Integer; begin // for example we need to write \public\files\UserID\2016\28\10 to DataBase // check if dir exists on disk, if ok then continue if not TDirectory.Exists(dir) then exit; //so here could be some error before, dir wasn't created and we exit // divide dir by separator '\' SplittedString:=dir.Split(['\']); // \public is Root dir so idParent=-1 for \public we need [0] number in separated array //ShowMessage(SplittedString[0]); // for test - gives 'public' // adding public if needed // check if not \public already written, if not - write in database with idParent=-1 idParent:=-1; idNextParent:=-2; if not IsFileOrFolderAlreadyInDB(idParent,SplittedString[0],idNextParent) then InsertFolderOrFileToDB( true, // isFolder idParent, // idParent SplittedString[0], // name SplittedString[2].ToInteger, // users_id -1 // filesize ); // check if not \public\files already written, if idNextParent=-2 then idParent:=GetLastInsertedID else idParent:=idNextParent; if not IsFileOrFolderAlreadyInDB(idParent,SplittedString[1],idNextParent) then InsertFolderOrFileToDB( true, // isFolder idParent, // idParent SplittedString[1], // name SplittedString[2].ToInteger, // users_id -1 // filesize ); // check if not \public\files\UserID already written, // check if not \public\files already written, if idNextParent=-2 then idParent:=GetLastInsertedID else idParent:=idNextParent; if not IsFileOrFolderAlreadyInDB(idParent,SplittedString[2],idNextParent) then InsertFolderOrFileToDB( true, // isFolder idParent, // idParent SplittedString[2], // name SplittedString[2].ToInteger, // users_id -1 // filesize ); // check if not \public\files\2016 already written, if idNextParent=-2 then idParent:=GetLastInsertedID else idParent:=idNextParent; if not IsFileOrFolderAlreadyInDB(idParent,SplittedString[3],idNextParent) then InsertFolderOrFileToDB( true, // isFolder idParent, // idParent SplittedString[3], // name SplittedString[2].ToInteger, // users_id -1 // filesize ); // check if not \public\files\2016\12 already written, if idNextParent=-2 then idParent:=GetLastInsertedID else idParent:=idNextParent; if not IsFileOrFolderAlreadyInDB(idParent,SplittedString[4],idNextParent) then InsertFolderOrFileToDB( true, // isFolder idParent, // idParent SplittedString[4], // name SplittedString[2].ToInteger, // users_id -1 // filesize ); // check if not \public\files\2016\12\22 already written, if idNextParent=-2 then idParent:=GetLastInsertedID else idParent:=idNextParent; if not IsFileOrFolderAlreadyInDB(idParent,SplittedString[5],idNextParent) then InsertFolderOrFileToDB( true, // isFolder idParent, // idParent SplittedString[5], // name SplittedString[2].ToInteger, // users_id -1 // filesize ); //if not - write in database with idParent=idParent of \public // ...continue so up to the last element in array - maybe doing loop is a good idea end; |
Вспомогательные функции
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 |
function TDataBaseUnitServer. IsFileOrFolderAlreadyInDB(idParent:Integer; nameToCompare:string; var idParentNext:integer):boolean; begin // Result:=false; idParentNext:=-2; with qSelectWhereParent do begin Params.ParamValues['idParent']:=idParent; Open(); while not EOF do begin if nameToCompare=FieldByName('name').AsString then begin idParentNext:=FieldByName('id').AsInteger; Result:=true; Break; end; Next(); end; Close(); end; end; |
Соответствующий запрос для этой функции
1 |
SELECT * FROM coffeetest_db.foldersandfilesonserver WHERE `idParent`=:idParent; |
И ещё одна
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 |
procedure TDataBaseUnitServer.InsertFolderOrFileToDB( IsFolder:Boolean; idParent:Integer; nameToInsert:string; users_id:integer; fileSize:integer); var DateTime:TDateTime; DateTimeForMySQL:string; LastInsertedID:integer; begin // DateTime:=Now; DateTimeForMySQL:=FormatDateTime('yyyy-mm-dd hh:mm:ss',DateTime); with qInsertFolderOrFile do begin Params.ParamValues['idParent']:=idParent; Params.ParamValues['name']:=nameToInsert; Params.ParamValues['creationDateTime']:=DateTimeForMySQL; Params.ParamValues['changesDateTime']:=DateTimeForMySQL; Params.ParamValues['lastAccessDateTime']:=DateTimeForMySQL; if IsFolder then Params.ParamValues['isFolder']:=1 else Params.ParamValues['isFolder']:=0; Params.ParamValues['users_id']:=users_id; // will be updated in different request Params.ParamValues['fileSize']:=fileSize.ToString; ExecSQL; end; end; |
Соответствующий запрос
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
INSERT INTO `coffeetest_db`.`foldersandfilesonserver` ( `idParent`, `name`, `creationDateTime`, `changesDateTime`, `lastAccessDateTime`, `isFolder`, `users_id`, `fileSize`) VALUES ( :idParent, :name, :creationDateTime, :changesDateTime, :lastAccessDateTime, :isFolder, :users_id, :fileSize ); |
И ещё одна
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function TDataBaseUnitServer.GetLastInsertedID:integer; begin Result:=-1; with qGetLastInsertedID do begin Open(); Result:=FieldByName('lastInsertedID').AsInteger; Close(); end; end; |
И соответствующий запрос
1 |
SELECT max(id) as lastInsertedID FROM coffeetest_db.foldersandfilesonserver; |