Отделение бизнес логики от базы

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Отделение бизнес логики от базы

Сообщение Jordan » 24.06.2020 08:39:10

Приветствую!

Хотелось бы уточнить вопрос, как отделить бизнес логику от базы данных в проектах Lazarus?
Я знаю, что есть патnерн MVC но не видел его применения в Delphi/Lazarus. Может есть какие то практики, советы и т.д

Пример.
Есть таблица заказов в базе, данную информацию нужно выводить менеджеру. Первый вариант работал так.
Накидал на форму кнопочки и stringgrid и при инициализации делал запрос и заполнял таблицу. Но мне по задаче понадобилось, что бы эту таблицу могли просматривать другие сотрудники.
Второй вариант. Создал класс Manager Table которая в конструкторе настраивает кол-во колонок и именую их + делает запрос к базе. Теперь я просто размещаю stringgrid на форме и передаю ее в класс ManagerTable.
Теперь хочу отделить логику базы от интерфейса.

Как я сделал.

Код: Выделить всё
unit ucore;

{$mode objfpc}{$H+}

interface

uses
  classes, udb;

type
  PProduct = ^TProduct;
  TProduct = object
  private
  public
    Id   : string;
    Title: string;
  end;

  PTask = ^TTask;
  TTask = object
  private
  public
    Id      : string;
    Width   : string;
    Height  : string;
    Product : TProduct;
  end;

  TTasks = array of TTask;
type
  PCore = ^TCore;
  TCore = object
  private
  public
    Ident: string;
    Title: string;
    function GetProductNameById(id: longword): string;
    procedure EditProductNameById(id: longword; Name: string);
    function GetTasks(): TTasks;
  end;

implementation
function TCore.GetProductNameById(id: longword): string;
begin
  with Db.Query do
  begin
    SQL.Clear;
    SQL.Add('SELECT title FROM products WHERE id = :id');
    ParamByName('id').AsInteger := id;
    Open;
    Result := FieldByName('title').AsString;
    Close;
  end;
end;

procedure TCore.EditProductNameById(id: longword; Name: string);
begin
  Db.Query.SQL.Clear;
  Db.Query.SQL.Add('UPDATE products SET title = :title WHERE id = :id');
  Db.Query.ParamByName('id').AsInteger := id;
  Db.Query.ParamByName('title').AsString := Name;
  Db.Query.ExecSQL;
  Db.Transact.Commit;
  Db.Query.Close;
end;

function TCore.GetTasks(): TTasks;
var
  Tasks: TTasks;
  i    : longword;
begin

  with Db.Query do
  begin
    SQL.Clear;
    SQL.Add('SELECT tasks.id as task_id, width, height, products.title as product_name, products.id as product_id FROM tasks JOIN products ON tasks.product_id = products.id');
    Open;

    SetLength(Tasks, RecordCount);

    i := 0;
    while  Eof <> true do
    begin
      Tasks[i].Id            := FieldByName('task_id').AsString;
      Tasks[i].Width         := FieldByName('width').AsString;
      Tasks[i].Height        := FieldByName('height').AsString;
      Tasks[i].Product.Title := FieldByName('product_name').AsString;
      Tasks[i].Product.Id    := FieldByName('product_id').AsString;
      Next;
      inc(i);
    end;

    Close;
  end;

  Result := Tasks;
end;

end.


И вызываю уже в программе данный класс. Данное ядро пишу на фрипаскале в консольном варианте, с последующей интеграцией модулей.



Код: Выделить всё
{$mode objfpc}   

program test;

uses
  classes, ucore;

var
  Source: TCore;
  Table : TTasks;
  i     : longword;

begin
  SetMultiByteConversionCodePage(CP_UTF8);
  SetMultiByteRTLFileSystemCodePage(CP_UTF8);

  Table := Source.GetTasks();

  i := 0;
  while (i < Length(Table)) do
  begin
    WriteLn(Table[i].id + ':' + Table[i].Width + ':' + Table[i].Product.Title);
    inc(i);
  end;
 
end.


Код подключения к базе.

Код: Выделить всё
unit udb;

{$mode objfpc}{$H+}

interface

uses
  sqldb, sqlite3conn;

type
  TDataBase = class
  private
  public
    Connect : TSQLite3Connection;
    Transact: TSQLTransaction;
    Query   : TSQLQuery;
    constructor Create(Name: string);
    destructor Free();
  end;

var
  Db: TDataBase;

implementation

constructor TDataBase.Create(Name: string);
begin
  Connect := TSQLite3Connection.Create(nil);
  Connect.DatabaseName := Name;
  Connect.Transaction  := Transact;
  Connect.Connected    := True;

  Transact := TSQLTransaction.Create(nil);
  Transact.DataBase := Connect;
  Transact.Active   := true;

  Query := TSQLQuery.Create(nil);
  Query.Database    := Connect;
  Query.Transaction := Transact;
end;

destructor TDataBase.Free();
begin
  Connect.Free;
  Transact.Free;
  Query.Free;
end;

initialization
  Db := TDataBase.Create('test.db');
finalization
  Db.Free();
end.   


Правильно я делаю, есть ли более гибкое решение?
Jordan
новенький
 
Сообщения: 13
Зарегистрирован: 19.12.2013 09:44:54

Re: Отделение бизнес логики от базы

Сообщение Снег Север » 24.06.2020 09:54:39

Если с базой должен работать более чем один сотрудник, то вариант с SQLite надо немедленно выкинуть на помойку и ставить сервер - MySQL, Firebird и т.п.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2993
Зарегистрирован: 27.11.2007 16:14:47

Re: Отделение бизнес логики от базы

Сообщение DYUMON » 25.06.2020 06:43:48

stringgrid ??? а не лучше ли dbgrid?
Sqlite хорош, когда программа для одного пользователя.
Посмотри в сторону mORMot, если уж очень хочется оперировать данными на уровне обьектов
Аватара пользователя
DYUMON
постоялец
 
Сообщения: 234
Зарегистрирован: 11.03.2009 13:32:54

Re: Отделение бизнес логики от базы

Сообщение olegy123 » 25.06.2020 20:03:58

DYUMON писал(а):stringgrid ??? а не лучше ли dbgrid?
В C# там все собирается из примитивов.
отдельно описания данных, отдельно их списки, база данных - нужно построить целый замок как в лего.

вас разбаловали dbgrid Table..

Jordan в fpc политика иная, есть Table к нему подключаешь DataSource и подключаешь DBGrid
можно прямо в дизайне увидеть результат, результат табличных данных, без компиляции.

Тут не нужно nuget_ить че попало.

Добавлено спустя 6 минут 30 секунд:
Если нужен секс как патnерн MVC тады гляди в сторону VirtualTable, там можно и данные любые в списки засунуть и изрисовать канву как душа просит
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Отделение бизнес логики от базы

Сообщение Ichthyander » 26.06.2020 22:26:52

Для отделения бизнес-логики хорошо заюзать какой-нибудь ОРМ, к примеру, я использовал dOPF, есть еще mORMot. Разделять по модулям так, чтобы компоненты отвечающие за работу с БД были в одном модуле, объекты для работы с бизнес-логикой в другом. При использовании визуальных компонентов для работы с БД сложнее будет отделить, но тоже кое-что можно сделать. Дизайнеры форм действительно отучают более внимательно относиться к паттернам, ИМХО
Аватара пользователя
Ichthyander
энтузиаст
 
Сообщения: 668
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

Re: Отделение бизнес логики от базы

Сообщение alexs » 29.06.2020 17:32:02

olegy123 писал(а):есть Table к нему подключаешь DataSource и подключаешь DBGrid

Не надо учить плохому
Вместо Table - лучше всеже брать SQLQuery - и запросами отсекать сразу лишние данные. Тянуть из базы лишнее в обработку - стрелять себе самому в ногу.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4053
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 28

Рейтинг@Mail.ru