Convertendo BO 1.1 para DBO 2.0
Este capítulo é destinado ao desenvolvedor que utiliza DBO 1.1 e deseja convertê-lo para DBO 2.0.
Para converter um DBO 1.1 devem ser seguidos os seguintes passos: Criar um novo DBO 2.0;
Transferir lógicas dos métodos básicos do DBO 1.1 para o DBO 2.0; Mas, antes de detalhar estes passos, é importante saber como fazer a relação entre os métodos antigos e os novos métodos.
A seguir são detalhados os passos:
Relação entre métodos
A maior parte dos métodos básicos possuem métodos que são correspondentes no novo DBO, sendo assim descreve-se a seguinte relação:
compareVersion -
Não há método correspondente no novo DBO; endMethod e startMethod -
Estes métodos eram utilizados para execução de EPCs, porém a execução de EPCs no novo DBO é feita de forma automática. Sendo assim, não há método correspondente no novo DBO;
findRowidShow -
Deve-se executar primeiramente o método emptyRowObject e logo após o método repositionRecord;
CAPÍTULO 4 Convertendo BO 1.1 para DBO 2.0 47
findRowid -
Deve-se executar o método repositionRecord; getCurrent -
Deve-se executar o método getRecord; findFirst -
Deve-se executar o método getFirst. O novo DBO somente trabalha com query;
finLast -
Deve-se executar o método getLast. O novo DBO somente trabalha com query;
findNext -
Deve-se executar o método getNext. O novo DBO somente trabalha com query;
findPrev -
Deve-se executar o método getPrev. O novo DBO somente trabalha com query;
getRowid -
Continua existindo no novo DBO; setCurrent -
Deve-se executar o método _copyBuffer2TT. Porém, este método é somente para uso interno dos includes padrão;
prevBrowseNavigation -
Não há método correspondente no novo DBO; serverSendRows -
Deve-se executar o método getBatchRecords; validateCreate -
Deve-se primeiramente executar o método createRecord e logo após o getRowid;
Deve-se primeiramente executar o método repositionRecord, após o deleteRecord e por último getRowid;
validateUpdate -
Deve-se primeiramente executar o método repositionRecord, após o setRecord e por último updateRecord;
openQuery -
Deve-se executar o método openQueryStatic. Porém, o novo método utiliza strings ao invés de números e desta forma deve-se controlar isto através de um método proxy definido pelo desenvolvedor.
Criar o novo DBO
Este passo está detalhado no item 'Construindo o DBO'.
Transferir lógicas dos métodos básicos do DBO 1.1 para o DBO
2.0
No antigo DBO, grande parte dos métodos básicos eram codificados pelo próprio desenvolvedor. Porém, no novo DBO grande parte dos métodos básicos são definidos em includes padrão.
A seguir, está descrito como deve ser feita a transferência dos métodos: openQuery
Este método deve ser subdividido em novos métodos, conforme exemplo a seguir:
Método antigo:
PROCEDURE openQuery:
DEFINE INPUT PARAMETER i-abertura AS INTEGER NO-UNDO. CASE i-abertura:
WHEN 1 THEN
OPEN QUERY {&Query-Name} FOR EACH Customer NO-LOCK. WHEN 2 THEN
OPEN QUERY {&Query-Name} FOR EACH Customer NO-LOCK BY Customer.Name.
END CASE.
CAPÍTULO 4 Convertendo BO 1.1 para DBO 2.0 49
ASSIGN l-query = true
i-bo-query = i-abertura. END PROCEDURE.
Método novo:
PROCEDURE openQueryMain:
OPEN QUERY {&Query-Name} FOR EACH Customer NO-LOCK. END PROCEDURE.
PROCEDURE openQueryByName:
OPEN QUERY {&Query-Name} FOR EACH Customer NO-LOCK BY Customer.Name.
END PROCEDURE.
Nesta conversão, o método openQuery foi substituído por 2 (dois) outros métodos. E ainda, para realizar a abertura da query deve-se utilizar o método genérico openQueryStatic passando como parâmetro a descrição da query. Conforme exemplo a seguir:
RUN openQueryStatic IN THIS-PROCEDURE (INPUT "Main":U). ou
RUN openQueryStatic IN THIS-PROCEDURE (INPUT "ByName":U). Vale salientar que os métodos setConstraint devem ter seus nomes alterados a fim de possuírem nomenclatura semelhante aos métodos
openQuery<Description> associados. Conforme exemplo a seguir: PROCEDURE openQueryByName:
...
END PROCEDURE.
PROCEDURE setConstraintByName: ...
END PROCEDURE. validateCreate
Este método foi dividido em novos métodos, sendo 1 (um) deles definido dentro do DBO e outro em include padrão.
Neste método, a parte responsável pelas validações específicas à criação devem ser transferidas para o método beforecreateRecord, as validações análogas à criação e alteração devem ser transferidas para o método
validateRecord. E ainda, caso ocorra algum erro nas validações, ao final deve ser retornado um flag "NOK" através do comando RETURN-VALUE. Quanto aos erros ocorridos, estes devem ser cadastrados na temp-table RowErrors através da include method/svc/errors/inserr.i.
Estes procedimentos são demonstrados através do exemplo a seguir: Método antigo:
PROCEDURE validateCreate:
DEFINE INPUT PARAMETER TABLE FOR RowObject. DEFINE OUTPUT PARAMETER TABLE FOR tt-bo-erro. DEFINE OUTPUT PARAMETER r-chave AS ROWID NO-UNDO. FOR EACH tt-bo-erro:
DELETE tt-bo-erro. END.
IF CAN-FIND(FIRST Customer WHERE Customer.Cust-Num = RowObject.Cust-Num)
THEN DO:
ASSIGN i-seq-erro = i-seq-erro + 1.
RUN utp/ut-msgs.p (INPUT "MSG":U, INPUT 9999, INPUT "":U). CREATE tt-bo-erro.
ASSIGN tt-bo-erro.i-sequen = i-seq-erro tt-bo-erro.cd-erro = 9999
tt-bo-erro.mensagem = RETURN-VALUE. END.
IF RowObject.Cust-Num <= 0 THEN DO: ASSIGN i-seq-erro = i-seq-erro + 1.
RUN utp/ut-msgs.p (INPUT "MSG":U, INPUT 9999, INPUT "":U). CREATE tt-bo-erro.
ASSIGN tt-bo-erro.i-sequen = i-seq-erro tt-bo-erro.cd-erro = 9999
tt-bo-erro.mensagem = RETURN-VALUE. END.
RUN validateFields IN THIS-PROCEDURE. FIND FIRST tt-bo-erro NO-ERROR. IF NOT AVAILABLE tt-bo-erro THEN DO: RUN executeCreate IN THIS-PROCEDURE. ASSIGN r-chave = TO-ROWID(RETURN-VALUE). END.
CAPÍTULO 4 Convertendo BO 1.1 para DBO 2.0 51
OBSERVAÇÃO: O utilitário UTP/UT-MSGS.P era utilizado em SmartObjects, porém, não deverá ser utilizado em DBOs, conforme conceito da tecnologia de DBOs.
Método novo:
Toda a lógica responsável pela criação dos novos registros foi passada para o método createRecord, que é um método básico ao qual o desenvolvedor não tem acesso. Este método é responsável pela execução do método
validateRecord e de seus métodos override.
Neste caso é demonstrado somente a transferência das validações. Parte do código que o desenvolvedor possui acesso.
PROCEDURE validateRecord:
IF RowObject.Cust-Num <= 0 THEN DO: {method/svc/errors/inserr.i &ErrorNumber="9999" &ErrorType="EMS" &ErroSubType="ERRO" &ErrorParameters="''"} END.
IF CAN-FIND(FIRST RowErrors) THEN RETURN "NOK":U.
RETURN "OK":U. END PROCEDURE.
PROCEDURE beforecreateRecord:
IF CAN-FIND(FIRST Customer WHERE Customer.Cust-Num = RowObject.Cust-Num) THEN DO: {method/svc/errors/inserr.i &ErrorNumber="9999" &ErrorType="EMS" &ErroSubType="ERRO" &ErrorParameters="''"} END.
IF CAN-FIND(FIRST RowErrors) THEN RETURN "NOK":U.
RETURN "OK":U. END PROCEDURE.
Nesta conversão, o método validateCreate foi substituído por 2 (dois) outros métodos definidos pelo usuário e 1 (um) definido em include padrão. E ainda, para realizar a criação de registro deve-se utilizar o método createRecord. Conforme exemplo a seguir:
RUN setRecord IN THIS-PROCEDURE (INPUT TABLE RowObject). RUN createRecord IN THIS-PROCEDURE.
validateUpdate
Este método foi dividido em novos métodos, sendo 1 (um) deles definido dentro do DBO e outro em include padrão.
Neste método, a parte responsável pelas validações específicas à alteração devem ser transferidas para o método beforeUpdateRecord; as validações análogas à criação e alteração devem ser transferidas para o método
validateRecord. E ainda, caso ocorra algum erro nas validações, ao final deve ser retornado um flag "NOK":U através do comando RETURN-VALUE. Quanto aos erros ocorridos, estes devem ser cadastrados na temp-table RowErrors através da include method/svc/errors/inserr.i.
Estes procedimentos são demonstrados através do exemplo a seguir: Método antigo:
PROCEDURE validateUpdate:
DEFINE INPUT PARAMETER TABLE FOR RowObject. DEFINE INPUT PARAMETER r-chave AS ROWID NO-UNDO. DEFINE OUTPUT PARAMETER TABLE FOR tt-bo-erro. FOR EACH tt-bo-erro:
DELETE tt-bo-erro. END.
RUN validateFields IN THIS-PROCEDURE. FIND FIRST tt-bo-erro NO-ERROR. IF NOT AVAILABLE tt-bo-erro THEN DO:
FIND {&Table-Name} WHERE ROWID({&Table-Name}) = r-chave EXCLUSIVE-LOCK NO-ERROR.
IF AVAILABLE {&Table-Name} THEN
RUN executeUpdate IN THIS-PROCEDURE. END.
END PROCEDURE. Método novo:
Toda a lógica responsável pela alteração de registros foi passada para o método updateRecord, ao qual o desenvolvedor não tem acesso. Este método é responsável pela execução do método validateRecord e de seus métodos override.
Nesta conversão, o método validateUpdate foi substituído por 1 (um) método definido pelo usuário e 1 (um) definido em include padrão. E ainda, para
CAPÍTULO 4 Convertendo BO 1.1 para DBO 2.0 53
realizar a alteração de registro deve-se utilizar o método updateRecord. Conforme exemplo a seguir:
/* Pode-se utilizar 1 (um) dos métodos de navegação: getFirst, getLast, getNext, getPrev ou repositionRecord, conforme a implementação */ RUN repositionRecord IN THIS-PROCEDURE (INPUT r-Rowid).
RUN setRecord IN THIS-PROCEDURE (INPUT TABLE RowObject). RUN updateRecord IN THIS-PROCEDURE.
validateDelete
Este método foi subdividido em novos métodos, sendo 1 (um) deles definido dentro do DBO e outro em include padrão.
Neste método, a parte responsável pelas validações específicas à eliminação devem ser transferidas para o método beforeDeleteRecord. E ainda, caso ocorra algum erro na validação, ao final deve ser retornado um flag "NOK":U através do comando RETURN-VALUE.
Quanto aos erros ocorridos, estes devem ser cadastrados na temp-table RowErrors através da include method/svc/errors/inserr.i.
Método antigo:
PROCEDURE validateDelete:
DEFINE INPUT-OUTPUT PARAMETER r-chave AS ROWID NO-UNDO. DEFINE OUTPUT PARAMETER TABLE FOR tt-bo-erro. FIND {&TABLE-NAME} WHERE ROWID({&TABLE-NAME}) = r-chave EXCLUSIVE-LOCK NO-ERROR.
IF AVAILABLE {&TABLE-NAME} THEN RUN executeDelete.
IF l-query THEN
GET NEXT {&QUERY-NAME} NO-LOCK NO-WAIT. ELSE
FIND NEXT {&TABLE-NAME} NO-LOCK NO-ERROR. IF NOT AVAILABLE {&TABLE-NAME} THEN DO: IF l-query THEN
GET PREV {&QUERY-NAME} NO-LOCK NO-WAIT. ELSE
FIND PREV {&TABLE-NAME} NO-LOCK NO-ERROR. END.
ASSIGN r-chave = ROWID({&TABLE-NAME}). END PROCEDURE.
Toda a lógica responsável pela eliminação de registros foi passado o método deleteRecord, que é um método básico que o desenvolvedor não tem acesso. Porém, este método é responsável pela execução de seus métodos override. Nesta conversão, o método validateDelete foi substituído por 1 (um) método definido pelo usuário e 1 (um) definido em include padrão. E ainda, para realizar a eliminação de registro deve-se utilizar o método deleteRecord. Conforme exemplo a seguir:
/* Pode-se utilizar 1 (um) dos métodos de navegação: getFirst, getLast, getNext, getPrev ou repositionRecord, conforme a implementação */
RUN repositionRecord IN THIS-PROCEDURE (INPUT r-Rowid). RUN deleteRecord IN THIS-PROCEDURE.
validateFields
Este método foi substituído pelo método validateRecord, que é definido pelo desenvolvedor.
Neste método, estão as validações análogas aos métodos de createRecord e updateRecord. E ainda, caso ocorra algum erro na validação, ao final deve ser retornado um flag "NOK":U, através do comando RETURN-VALUE, ou um flag "OK":U caso não ocorre nenhum erro.
Quanto aos erros ocorridos, estes devem ser cadastrados na temp-table RowErrors através da include method/svc/errors/inserr.i.
Estes procedimentos são demonstrados através do exemplo a seguir: Método antigo:
PROCEDURE validateFields:
FIND FIRST RowObject NO-ERROR. IF RowObject.Cust-Num <= 0 THEN DO: ASSIGN i-seq-erro = i-seq-erro + 1.
RUN utp/ut-msgs.p (INPUT "MSG":U, INPUT 9999, INPUT "":U). CREATE tt-bo-erro.
ASSIGN tt-bo-erro.i-sequen = i-seq-erro tt-bo-erro.cd-erro = 999
tt-bo-erro.mensagem = RETURN-VALUE. END.
IF RowObject.Name = "":U OR RowObject.Name = ? THEN DO: ASSIGN i-seq-erro = i-seq-erro + 1.
CAPÍTULO 4 Convertendo BO 1.1 para DBO 2.0 55
CREATE tt-bo-erro.
ASSIGN tt-bo-erro.i-sequen = i-seq-erro tt-bo-erro.cd-erro = 999
tt-bo-erro.mensagem = RETURN-VALUE. END.
END PROCEDURE.
OBSERVAÇÃO: O utilitário UTP/UT-MSGS.P era utilizado em SmartObjects, porém, não deverá ser utilizado em DBOs, conforme conceito da tecnologia de DBOs.
Método novo: PROCEDURE validateRecord: IF RowObject.Cust-Num <= 0 THEN {method/svc/errors/inserr.i &ErrorNumber="9999" &ErrorType="EMS" &ErroSubType="ERRO" &ErrorParameters="''"}
IF RowObject.Name = "":U OR RowObject.Name = ? THEN {method/svc/errors/inserr.i
&ErrorNumber="9999" &ErrorType="EMS"
&ErroSubType="ERRO" &ErrorParameters="''"} IF CAN-FIND(FIRST RowObject) THEN
RETURN "NOK":U. RETURN "OK":U. END PROCEDURE.
Nesta conversão, o método validateFields foi substituído pelo método validateRecord. E ainda, a gravação dos erros é feita através da include method/svc/errors/inserr.i e ao final do processo é retornada a flag que indica a existência de erros ou não.
Vale salientar que este método é executado internamente, não havendo necessidade do client executá-lo.
57