#1 2019-11-29 19:16:25

Javierus
Member
Registered: 2019-09-18
Posts: 43

Business rules example

Hello,

I'm trying to understand how the bussiness rules work in the ORM.

In the case where an article affects other, how can I do it?

Example:

  TSQProductRecord = class(TSQLRecord)
  private
    fReference: RawUTF8;
    fName: RawUTF8;
    fPrice: Double;
    fStock: Double;
  published
    property Reference: RawUTF8 index 30 read fReference write fReference;
    property Name: RawUTF8 index 100 read fName write fName;
    property Price: Double read fPrice write fPrice;
    property Stock: Double read fStock write fStock;
  end;

  TSQLMovementRecord = class(TSQLRecord)
  private
    fIDproduct: TRecordReference;
    fDelta: Double;
    fDate: TDateTime;
  published
    property IDproduct: TRecordReference read fIDproduct write fIDproduct;
    property Delta: Double read fDelta write fDelta;
    property Date: TDateTime read fDate write fDate;
  end;

How could I code that Delta should accumulate on the Stock field on the linked Product?
How can I reject a Movement is saved with a non-existent IDproduct?

I have no clue, and am unable to find any info on this topic.

Thanks in advance

Offline

#2 2019-11-29 22:13:55

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Business rules example

Why use a TRecordReference ?
I guess you don't need it here, since you expect to link only a product.

You should either:
- define a  IDproduct: TSQLProductRecord then use this value as a fake pointer
- define a IDProduct: TSQLProductRecordID defining the type TSQLProductRecordID = type TID
The 2nd way is IMHO preferred.

There is information about this in the documentation.
Including how deletion or modification is handled.

Offline

#3 2019-12-03 17:17:08

Javierus
Member
Registered: 2019-09-18
Posts: 43

Re: Business rules example

Thanks again, AB

Somehow I missed it; now I've read and on my way to understanding the mechanics

I'm used to put my business logic on the OnBeforePost, OnAfterPost, OnBeforeDelete, and so on.
Where and how should I implement the business logic of objects?
I'm refering not just to field validation, wich currently I implement on the OnBeforePost, but also things as deletion validation (Is acceptable deleting this object?), insert validation, side effects on other objects, and so on.

Offline

#4 2019-12-03 19:04:02

oz
Member
Registered: 2015-09-02
Posts: 95

Re: Business rules example

You should go for the DDD way with interface based services.
Have a look at the documentation about DDD. It‘s an excellent stating point.
We are developing quite a large project based on mORMot over here using this principle, and it works like a charm!
Try to encapsulate those business rules inside CQRS services, or even in higher layered „parent“ services who are consuming those CQRS services by themself. Expose only high level services as api. Don‘t rely your business rules on TSQLRecords but on business PODOs. That‘s my advice for building complex servers based on mORMot.

Offline

#5 2019-12-09 10:27:26

Javierus
Member
Registered: 2019-09-18
Posts: 43

Re: Business rules example

oz wrote:

Don‘t rely your business rules on TSQLRecords but on business PODOs. That‘s my advice for building complex servers based on mORMot.

I'm very grateful for your advice, thank you very much.
I've been programming Pascal for 35 years, but I'm the lowest newbie in ORM stuff; so I'm not sure I truly understand you.
Is your advice taking all the mORMot framework, but the ORM part?
Any direction on where to find some information about "Rely your business rules on business PODOs"?

Offline

#6 2019-12-09 16:05:32

oz
Member
Registered: 2015-09-02
Posts: 95

Re: Business rules example

Javierus wrote:

Is your advice taking all the mORMot framework, but the ORM part?

No, you got me wrong here.

My advice is to use the ORM part as a simple data storage layer only. All the domain specific functions should reside in higher level services. Don't use TSQLRecords in your domain logic. The domain should know nothing about TSQLRecords.

If you you are in a large/complicated domain, then keep your CQRS Services who are responsible for storing TSQLRecord* data as dumb as possible. By following mORMot's DDD principles you end with a TSQLProductRecord=class(TSQLRecord)... and a correspondig TProductRecord = class(TSynPersistent). TSQLProductRecord is your ORM storage class, TProductRecord is your PODO (plain old Delphi object). Your bussines rules should aways work on TProductRecord, not on TSQLRecord* classes.

E.g.: sometimes it's not enough to store any kind of item arrays as Variant only in your entity. Searching for specific items would result in loading all entities, then searching each entity for the array-item.
If you have another higher-level service in front of your CQRS service, then the .Add method could utilize various CQRS services and split your PODO values to different TSQLRecords...

I hope you get what I mean.

Offline

#7 2019-12-09 17:36:06

Javierus
Member
Registered: 2019-09-18
Posts: 43

Re: Business rules example

oz wrote:

My advice is to use the ORM part as a simple data storage layer only

Now I'm begining to get it; I was absolutely lost.

Thanks for all the advices packed in your answer; will be of great help.

Offline

Board footer

Powered by FluxBB