Example Business Object (Customer)

Re: Example Business Object (Customer)

Postby Marcelo Via Giglio » Fri Nov 16, 2018 2:54 pm

Hola,

maybe we can see to far and think in ORM https://en.wikipedia.org/wiki/Object-relational_mapping

an idea only

regards

Marcelo Vía
Marcelo Via Giglio
 
Posts: 1050
Joined: Fri Oct 07, 2005 3:33 pm
Location: Cochabamba - Bolivia

Re: Example Business Object (Customer)

Postby Silvio.Falconi » Fri Nov 16, 2018 3:54 pm

No I wish See how Make the same sample of Jeff Bott ( made with tdata and trecord)

but with Tdatabase and tdataRow of Fivetech
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 6774
Joined: Thu Oct 18, 2012 7:17 pm

Re: Example Business Object (Customer)

Postby nageswaragunupudi » Sun Nov 18, 2018 12:57 am

This is a similar sample of TEmployee class derived from TDatarow class. This class works with not only TDatabase, but also directly with DBF, FWMariaDB, TDolphin and ADO ( with any RDMS ) also. To save the time of creation of base table on all these platforms, I have used "customer" table which is already present in all sample dbs of FWH.

Copy this program to \fwh\samples folder and use buildh.bat or buildx.bat to build and run the test program. You may try with DBF, TDatabase, FWMariaDB, ADO and Dolphin.
Code: Select all  Expand view
#include "fivewin.ch"

REQUEST DBFCDX

#ifndef __XHARBOUR__
EXTERNAL TDOLPHINQRY
#endif

static oCn

//----------------------------------------------------------------------------//

function Main()

   local aSrc  := { "DBF", "TDATABASE", "FWMARIADB", "ADO" }
   local nSrc
   local oEmp

#ifndef __XHARBOUR__
   AADD( aSrc, "DOLPHIN" )
#endif

   SET DATE ITALIAN
   SET CENTURY ON
   RDDSETDEFAULT( "DBFCDX" )

   nSrc  := Alert( "Select Data Source Type", aSrc )
   if nSrc == 0
      return nil
   endif

   if aSrc[ nSrc ] == "FWMARIADB"
      oCn   := FW_DemoDB()
   elseif aSrc[ nSrc ] == "ADO"
      oCn   := FW_OpenAdoConnection( "xbrtest.mdb", .t. )
   elseif aSrc[ nSrc ] == "DOLPHIN"
      oCn   := FW_DemoDB( "DLP" )
   endif

   TEmployee():cDbType := Upper( aSrc[ nSrc ] )

   oEmp  := TEmployee():New( 101 )

   ? oEmp:cDbType
   ? oEmp:id, oEmp:FullName, oEmp:City
   ? oEmp:YearsWorked, oEmp:Gratuity
   ? oEmp:Salary
   oEmp:PayIncrease( 2000 )
   ? oEmp:Salary

   oEmp:Edit()
   oEmp:Close()

   if !Empty( oCn )
      if aSrc[ nSrc ] $ "FWMARIADB,DOLPHIN"
         oCn:End()
      endif
   endif

   ? "Done"

return nil

//----------------------------------------------------------------------------//

CLASS TEmployee FROM TDataRow

   CLASSDATA cDbType   AS CHARACTER INIT "DBF"
   CLASSDATA employees
   CLASSDATA nCount     INIT 0

   DATA oRs

   METHOD New( nID ) CONSTRUCTOR

   ACCESS FullName   INLINE Trim( ::First ) + ", " + Trim( ::Last )
   ACCESS YearsWorked INLINE YEAR( Date() ) - YEAR( ::HireDate ) - ;
                      If( SUBSTR( DTOS( DATE() ), 5 ) < SUBSTR( DTOS( ::HireDate ), 5 ), 1, 0 )

   METHOD PayIncrease( n ) INLINE ( ::Salary += n, ::Save(), ::Salary )

   ACCESS Gratuity INLINE ROUND( ::Salary * ::YearsWorked / 2, 0 )

   METHOD OpenTable() //used only by DBF and TDatabase

   METHOD Close()

ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( nID ) CLASS TEmployee

   local cSql

   if ::cDbType $ "DBF,TDATABASE"
      ::OpenTable()
      if ::cDbType == "DBF"
         ( ::employees )->( DBSEEK( nID ) )
      else
         ::employees:Seek( nID )
      endif
   else
      cSql  := "SELECT * FROM customer WHERE ID = " + cValToChar( nID )
      ::oRs := If( ::cDbType == "ADO", FW_OpenRecordSet( oCn, cSql ), oCn:Query( cSql ) )
   endif

   ::Super:New( IfNil( ::oRs, ::employees ) )

   ::lNavigate := .f.

return Self

//----------------------------------------------------------------------------//

METHOD OpenTable() CLASS TEmployee

   if !File( "CUSTOMER.CDX" )
      USE CUSTOMER EXCLUSIVE
      FW_CdxCreate()
      CLOSE DATA
   endif

   if ::employees == nil
      if ::cDbType == "DBF"
         USE CUSTOMER NEW SHARED ALIAS ( ::employees := cGetNewAlias( "CUST" ) )
         SET ORDER TO TAG ID
         GO TOP
      elseif ::cDbType == "TDATABASE"
         ::employees := TDataBase():Open( nil, "CUSTOMER" )
         WITH OBJECT ::employees
            :SetOrder( "ID" )
            :GoTop()
         END
      endif
      ::nCount := 0
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Close() CLASS TEmployee

   if ::cDbType $ "DBF,TDATABASE" .and. !Empty( ::employees )
      ::nCount--
      if ::nCount < 1
         if ::cDbType == "DBF"
            ( ::employees )->( DBCLOSEAREA() )
         else
            ::employees:End()
         endif
         ::employees := nil
         ::nCount    := 0
      endif
   elseif !Empty( ::oRs )
      if ::cDbType $ "FWMARIADB,ADO"
         ::oRs:Close()
      elseif ::cDbType == "DOLPHIN"
         ::oRs:End()
      endif
      ::oRs := nil
   endif

return nil

//----------------------------------------------------------------------------//
 
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10248
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Example Business Object (Customer)

Postby nageswaragunupudi » Sun Nov 18, 2018 1:14 am

Silvio.Falconi wrote:No I wish See how Make the same sample of Jeff Bott ( made with tdata and trecord)

but with Tdatabase and tdataRow of Fivetech


Same sample:
First please create arcust.dbf using the program already provided by Mr. James Bott to create the dbf.

This is the class posted in the first post with little modification to match TDataRow and TDataBase, retaining the same functionality.
Code: Select all  Expand view
#include "fivewin.ch"

Function Main()

   Local oCustomer, oCustomers
   Local cCustNo
   Field custno, company

   REQUEST DBFCDX
   rddsetdefault( "DBFCDX" )
   set deleted on

   ferase("arcust.cdx")

   // Just for testing
   // Must use TAG clause with CDXs
   use arcust exclusive
   index on CUSTNO tag "CUSTNO" to arcust
   index on upper(COMPANY) tag "COMPANY" to arcust
   use

   // Instantiate the object
   cCustNo:="10007"
   oCustomer:= TCustomer():new(cCustNo)
   oCustomer:display()

   /* Testing
   msgInfo( oCustomer:Company,"oCustomer:Company")
   msgInfo( oCustomer:getBalance(), "Customer Balance"  )
   msgInfo( oCustomer:paymentStatus(), "Payment Status" )
   msgInfo( oCustomer:PaymentTerms(), "Payment Terms" )
   msgInfo( oCustomer:YearToDateSales(),"Year To Date Sales"  )
   */


   oCustomer:end()

Return nil


//--- Customer class
CLASS TCustomer from TDataRow

   DATA oTable

   METHOD New( cCustNo )
   METHOD ApplyPayment( nAmount, dDate)
   Method Display()
    METHOD End()
   Method GetBalance()
   Method PaymentStatus()
   Method PaymentTerms()
   Method PastDueAmount()
   Method PastDueDays()
   Method PTDSales() inline ::ptdsls
   Method YearToDateSales() inline ::ytdsls
   Method SalesHistory()
ENDCLASS

METHOD New( cCustNo ) CLASS TCustomer
   ::oTable:= TCustomers():New()
   ::oTable:setOrder(1)
   ::oTable:seek( cCustNo )
//   ::Load()
   ::Super:New( ::oTable )

RETURN Self

METHOD End() Class TCustomer
    ::oTable:End()
Return nil

METHOD ApplyPayment( nAmount, dDate ) CLASS TCustomer
   default dDate:= date()
   ::balance:= ::balance - nAmount
   ::lastPay:= dDate
   ::lpymt  := nAmount
   ::save()
RETURN nil

Method GetBalance() Class TCustomer
Return ::balance

Method PaymentStatus() Class TCustomer
Return "Paid Up"

Method PaymentTerms() Class TCustomer
Return "Net "+alltrim(str(::PDays))+" days"

Method PastDueAmount() Class TCustomer
Return 0

Method SalesHistory() Class TCustomer
   //Local oSalesHistory:= TSalesHistory():New(::custNo)
   //oSalesHistory:Display()
   //oSalesHistory:end()
Return nil

Method PastDueDays() Class TCustomer
Return 0

Method Display() Class TCustomer
   Local cString:=""

   cString := cString + "Customer No: "+ ::custno + CRLF
   cString := cString + "Payment Status: "+ ::paymentStatus + CRLF
   cString := cString + "Payment Terms: "+ ::paymentTerms() + CRLF
   cString := cString + "Balance: " + TRANSFORM(::GetBalance(), "$999,999.99") + CRLF
   cString := cString + "Year-To-Date Sales: " + transform(::yeartodateSales(), "$999,999.99") + CRLF

   msgInfo(cString, ::Company)

Return nil




//---------------------------------------------------------------------------//
// Customer table class
Class TCustomers From TDataBase
   Method New()
   Method End() inline ::close()
Endclass

Method New() Class TCustomers
   ::super:new(,"arcust")
   ::use()
   ::setOrder(1)
   ::gotop()
Return self

// EOF
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10248
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Example Business Object (Customer)

Postby Silvio.Falconi » Mon Nov 19, 2018 7:18 pm

Mr Rao,
To better understand how to create a management with Tdatabase and Tdatarow it is possible to make a small program from A to Z, inserting the management of an archive even simple with the following possibilities: insertion, modification, search, printing also with the possibility to insert data from other archives for example through a selection
For us beginners it could be very useful
Since from 1991/1992 ( fw for clipper Rel. 14.4 - Momos)
I use : FiveWin for Harbour November 2023 - January 2024 - Harbour 3.2.0dev (harbour_bcc770_32_20240309) - Bcc7.70 - xMate ver. 1.15.3 - PellesC - mail: silvio[dot]falconi[at]gmail[dot]com
User avatar
Silvio.Falconi
 
Posts: 6774
Joined: Thu Oct 18, 2012 7:17 pm

Re: Example Business Object (Customer)

Postby nageswaragunupudi » Mon Nov 19, 2018 7:31 pm

Mr. Silvio

What you are asking is totally different from what Mr. James Bott was discussing. (i.e., the subject of this post)

A Customer object is for ONE customer only. The question of adding customer, deleting customer, etc. does not arise.

For that, you need a class to handle Tables. That is what TData or TDatabase does.
These classes already have methods to append, modify, seek and all those.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10248
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Example Business Object (Customer)

Postby José Luis Sánchez » Tue Nov 20, 2018 8:51 am

Marcelo Via Giglio wrote:Hola,

maybe we can see to far and think in ORM https://en.wikipedia.org/wiki/Object-relational_mapping

an idea only

regards

Marcelo Vía


Hello Marcelo,
I'm using your TRecord class and works fine for me. Do you have any other classes like a simple ORM and want to share them ?

Regards,
User avatar
José Luis Sánchez
 
Posts: 539
Joined: Thu Oct 13, 2005 9:23 am
Location: Novelda - Alicante - España

Re: Example Business Object (Customer)

Postby Carlos Mora » Wed Nov 21, 2018 8:25 pm

Hi Marcelo
Marcelo Via Giglio wrote:maybe we can see to far and think in ORM https://en.wikipedia.org/wiki/Object-relational_mapping

ORM are a very elegant solution followed widely in almost every modern programming language. The most important concept behind is that it separates the persistency layer from the data layer, that is it's hidden to the app how the data is stored in permanent memory. For those of us who have being using dbfs for so long, it could be a little bit challenging to forget about that. We are so used to the navigational ISAM model, GOing TOP, SKIPing until EOF that all that sounds a little bit weird in the begining.
Back to ORM, the most complete ones have 2 types of objects: the Entity object and the Repository object. The Entity represents one and only one individual of the collection: a customer, a product, an account, etc. The Repository is the full set of objects on a given Entity, like ClientsRepository, ProductRepository, etc. The Repository is usually the responsible for Find()ing a given or a subset of entities, and for the aggregational functions like Count(), Sum(), etc.
Entities are also able to represent complex objects throw the knowledge of relations between entities: an Invoice:hasMany(InvoiceItems), an Invoice:belongsTo(Customer) and so on, so in your code, given an instance of Invoice oInvoice, you can get the corresponding oCustomer just calling oInvoice:Customer.
Usually the reciprocal relation is true: an Invoice:belongsTo(Customer) so a Customer:hasMany(Invoice) .
With such ORM the code will reduce the need of direct data access by our code significantly.
This is a sample of an Entity written in PHP and Laravel's Eloquent ORM
Code: Select all  Expand view

<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Cliente extends Model
{
    protected $fillable = [
        'agrupacion_id',
        'nombre',
        'apellido1',
        'apellido2',
        'cif',
        'tipo_persona',
        'tipo_via',
        'nombre_via',
        'num_via',
        'otros_via',
        'poblacion',
        'codigo_postal',
        'telefono1',
        'telefono2',
        'email',
        'fax',
    ];
   
    static function rules(){
        return [
            'nombre' => 'required|max:64',
            'apellido1' => 'max:45',
            'apellido2' => 'max:45',
            'cif' => 'required|cif_nif_nie',
            'tipo_persona' => 'required|in:F,J',
            'tipo_via' => 'required',
            'nombre_via' => 'required',
            'num_via' => 'required',
            'otros_via' => '',
            'poblacion' => '',
            'codigo_postal' => 'required',
            'email' => 'email|required|max:64',
            ];
    }

    public function bancos(){
        return $this->hasMany('App\Models\BancoCliente', 'cliente_id', 'id');
    }

    public function solicitudes(){
        return $this->hasMany('App\Models\Solicitud', 'cliente_id', 'id');
    }

    public function agrupacion(){
        return $this->belongsTo('App\Models\Agrupacion', 'id', 'agrupacion_id');
    }

    /**
    * List of values for field Tipo de Persona
    *
    * @return array
    */

    static public function tipo_personaSelectData(){
        return [
            'J' => 'Jurídica',
            'F' => 'Física',
        ];
    }
} 


$Fillable are the fields the app is able to change, rules are the validation rules to apply in creating or editing, and then bancos, solicitudes and agrupacion are the relations among entities, so given a Client $client, invoking $client->bancos will return a collection of bank accounts without the need of writing a single line of code or SQL. Beauty! Thanks to the static methods, the same Model class acts as a Repository, so Cliente::find(32) will retrieve the cliente whose id is 32.
All of this can be done independent of the database used: it can be MySQL/MariadB, Postgress, SQLServer, Oracle, Sqlite, etc.

It would be really nice to have an ORM like that in Harbour, and it will have to be really good to make us to forget about the simplicity of having the dbf data as part of the very same language. I think there is no equivalent of that in any other language in the world.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Example Business Object (Customer)

Postby Marcelo Via Giglio » Fri Nov 23, 2018 2:58 pm

Dear José Luis,

sorry, I don't have any close to ORM

Dear Carlos,

good explanation about ORM, but will be a best sample a Java ORM like Hibernate, EclipseLink, etc. where with a simple line of code, you can persist entire sophisticates relation entities.

I think [x]Harbour is flexible, maybe can be possible to develop a basic ORM

Many thanks for your comments

Regards and sorry for my good English

Marcelo Vía
Marcelo Via Giglio
 
Posts: 1050
Joined: Fri Oct 07, 2005 3:33 pm
Location: Cochabamba - Bolivia

Re: Example Business Object (Customer)

Postby José Luis Sánchez » Sat Nov 24, 2018 7:39 am

As far as I know there is an ORM for Harbour at https://github.com/tfonrouge/oordb
You can know more about Teo Fonrouge at https://medium.com/harbour-magazine/int ... 9a1a167f7b

Regards,
User avatar
José Luis Sánchez
 
Posts: 539
Joined: Thu Oct 13, 2005 9:23 am
Location: Novelda - Alicante - España

Re: Example Business Object (Customer)

Postby James Bott » Sat Nov 24, 2018 5:46 pm

According to Wikipedia, object oriented programming is a type of ORM. So we have had this capability since the Clipper days.

After you have defined an entity object, you can create an object in one line.

oCustomer := TCustomer:New( cCustNo )

Using TDatabase you can switch from DBFs to SQL without changing any other code.
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Example Business Object (Customer)

Postby Carlos Mora » Mon Nov 26, 2018 12:43 pm

James Bott wrote:According to Wikipedia, object oriented programming is a type of ORM.
After you have defined an entity object, you can create an object in one line.

oCustomer := TCustomer:New( cCustNo )

Using TDatabase you can switch from DBFs to SQL without changing any other code.

OOP is NOT an ORM. They are absolutely different concepts. An ORM is able to hide the persistence layer of an implementation and expose entities abstracting their attributes and relations. OOP is a much wider concept, applied to everything.
Inside oCustomers you are dealing with DML, things that usually you don't need to using an ORM.
How do you get your customer's invoices? In your sample, it is required to write the code to make the select or tretrieve the records. In an ORM you just declare the relation among customer and invoice, sth like
Code: Select all  Expand view

METHOD Invoices()
RETURN ::hasMany( TInvoices() )
 


Note that you are not writing a single line of code, that should be made by the ORM.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Example Business Object (Customer)

Postby Carlos Mora » Mon Nov 26, 2018 12:54 pm

José Luis Sánchez wrote:As far as I know there is an ORM for Harbour at https://github.com/tfonrouge/oordb

No, it is not an ORM, it is a Object Oriented Relational Database. Its model is closer to an Active Record pattern than an ORM.

Regards
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Example Business Object (Customer)

Postby jose_murugosa » Tue Nov 27, 2018 10:53 am

This topic looks very atractive.
I feel very enthusiastic about it, I would like to see more information in this forum about how to use this model with FWH and Harbour.
Thanks a lot for all this knowledge you freely shear with us, this is what I love of this forum. :D
Saludos/Regards,
José Murugosa
FWH + Harbour + Bcc7. Una seda!
User avatar
jose_murugosa
 
Posts: 1144
Joined: Mon Feb 06, 2006 4:28 pm
Location: Uruguay

Re: Example Business Object (Customer)

Postby James Bott » Tue Nov 27, 2018 10:11 pm

Carlos Mora wrote:
OOP is NOT an ORM. They are absolutely different concepts. An ORM is able to hide the persistence layer of an implementation and expose entities abstracting their attributes and relations. OOP is a much wider concept, applied to everything.


From Wikipedia:

Object-relational mapping https://en.wikipedia.org/wiki/Object-relational_mapping

Object-relational mapping (ORM, O/RM, and O/R mapping tool) in computer science is a programming technique for converting data between incompatible type systems using object-oriented programming languages.

However there do seem to be varying definitions. See this discussion:

https://stackoverflow.com/questions/115 ... -framework

The issue for us FiveWin programmers is that we do not have the type of ORM that you are describing. However we do have OOP. Even without the lower level ORM that you refer to, we can accomplish the same objectives with our OOP (even if it may require slightly more code). And this does isolate our code from the relational database so it does accomplish abstraction.

So we can either continue to write procedural code, or we can use the OOP language we do have to achieve the same end as using your type of ORM.
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

PreviousNext

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: richard-service and 74 guests