No vídeo de hoje, vamos demonstrar em como criar uma tela Modelo 3 em MVC (com duas tabelas, pai e filho) usando tabelas temporárias (com FWTemporaryTable).
A dúvida de hoje, nos perguntaram, se seria possível, criar uma tela Modelo 3 em MVC, mas sem usar as tabelas do dicionário, usando tabelas temporárias criadas com FWTemporaryTable.
Pensando nisso, montamos esse exemplo, onde vamos demonstrar em como fazer isso, criando as tabelas, vinculando-as, e criando um bLoad na grid para o caso dos dados já gravados. Observação: Não é muito recomendado ou usual fazer uma Modelo 3 com temporárias, devido a todo o trabalho de manutenção que pode ser gerado, além de possíveis ajustes e correções, utilize em último caso.
Segue abaixo o vídeo exemplificando:
E abaixo o código fonte desenvolvido:
//Bibliotecas #Include "Totvs.ch" #Include "FWMVCDef.ch" //Variveis Estaticas Static cTitulo := "" /*/{Protheus.doc} User Function zVid0128 Cadastro de temporária modelo 3 (com duas tabelas) @author Atilio @since 15/03/2024 @version 1.0 @obs Baseado no exemplo - https://terminaldeinformacao.com/2022/09/19/temporaria-em-mvc-com-fwtemporarytable-ti-responde-022/ /*/ User Function zVid0128() Local aArea := FWGetArea() Local oBrowse Local aCampos1 := {} Local aCampos2 := {} Local aColunas := {} Local aPesquisa := {} Private aRotina := {} Private oTmpTable1 Private cAliasTmp1 := GetNextAlias() Private oTmpTable2 Private cAliasTmp2 := GetNextAlias() //Definicao do menu aRotina := MenuDef() cTitulo := "Temporárias Mod3 - " //Campos da temporária pai aAdd(aCampos1, {"TMPAI_COD", "C", 06, 0}) aAdd(aCampos1, {"TMPAI_DES", "C", 50, 0}) aAdd(aCampos1, {"TMPAI_VAL", "N", 10, 0}) aAdd(aCampos1, {"TMPAI_DAT", "D", 08, 0}) //Campos da temporária filho aAdd(aCampos2, {"TMFIL_COD", "C", 006, 0}) aAdd(aCampos2, {"TMFIL_ITEM", "C", 002, 0}) aAdd(aCampos2, {"TMFIL_DESC", "C", 100, 0}) //Cria a temporária pai oTmpTable1 := FWTemporaryTable():New(cAliasTmp1) oTmpTable1:SetFields(aCampos1) oTmpTable1:AddIndex("1", {"TMPAI_COD"} ) oTmpTable1:Create() cTitulo += "Pai - " + oTmpTable1:GetRealName() //Cria a temporária filho oTmpTable2 := FWTemporaryTable():New(cAliasTmp2) oTmpTable2:SetFields(aCampos2) oTmpTable2:AddIndex("1", {"TMFIL_COD", "TMFIL_ITEM"} ) oTmpTable2:Create() cTitulo += "; Filho - " + oTmpTable2:GetRealName() //Definindo as colunas que serão usadas no browse aAdd(aColunas, {"Codigo", "TMPAI_COD", "C", 06, 0, "@!"}) aAdd(aColunas, {"Descricao", "TMPAI_DES", "C", 50, 0, "@!"}) aAdd(aColunas, {"Valor", "TMPAI_VAL", "N", 10, 0, "@E 9,999,999.99"}) aAdd(aColunas, {"Data", "TMPAI_DAT", "D", 08, 0, "@D"}) //Adiciona os indices para pesquisar /* [n,1] Título da pesquisa [n,2,n,1] LookUp [n,2,n,2] Tipo de dados [n,2,n,3] Tamanho [n,2,n,4] Decimal [n,2,n,5] Título do campo [n,2,n,6] Máscara [n,2,n,7] Nome Físico do campo - Opcional - é ajustado no programa [n,3] Ordem da pesquisa [n,4] Exibe na pesquisa */ aAdd(aPesquisa, {"Codigo", {{"", "C", 6, 0, "Codigo", "@!", "TMPAI_COD"}} } ) //Criando o browse da temporária oBrowse := FWMBrowse():New() oBrowse:SetAlias(cAliasTmp1) oBrowse:SetTemporary(.T.) oBrowse:SetFields(aColunas) oBrowse:DisableDetails() oBrowse:SetDescription(cTitulo) oBrowse:SetSeek(.T., aPesquisa) oBrowse:Activate() oTmpTable1:Delete() FWRestArea(aArea) Return Nil /*/{Protheus.doc} MenuDef Menu de opcoes na funcao zVid0128 @author Atilio @since 15/03/2024 @version 1.0 /*/ Static Function MenuDef() Local aRotina := {} //Adicionando opcoes do menu ADD OPTION aRotina TITLE "Visualizar" ACTION "VIEWDEF.zVid0128" OPERATION 1 ACCESS 0 ADD OPTION aRotina TITLE "Incluir" ACTION "VIEWDEF.zVid0128" OPERATION 3 ACCESS 0 ADD OPTION aRotina TITLE "Alterar" ACTION "VIEWDEF.zVid0128" OPERATION 4 ACCESS 0 ADD OPTION aRotina TITLE "Excluir" ACTION "VIEWDEF.zVid0128" OPERATION 5 ACCESS 0 ADD OPTION aRotina TITLE "Copiar" ACTION "VIEWDEF.zVid0128" OPERATION 9 ACCESS 0 Return aRotina /*/{Protheus.doc} ModelDef Modelo de dados na funcao zVid0128 @author Atilio @since 15/03/2024 @version 1.0 /*/ Static Function ModelDef() Local oModel := Nil Local oStTMPPai := FWFormModelStruct():New() Local oStTMPFil := FWFormModelStruct():New() Local aRelation := {} Local bPre := Nil Local bPos := Nil Local bCancel := Nil //Na estrutura, define os campos e a temporária oStTMPPai:AddTable(cAliasTmp1, {'TMPAI_COD', 'TMPAI_DES', 'TMPAI_VAL', 'TMPAI_DAT'}, "Temporaria Pai") oStTMPFil:AddTable(cAliasTmp2, {'TMFIL_COD', 'TMFIL_ITEM', 'TMFIL_DESC'}, "Temporaria Filho") //Adiciona os campos da estrutura oStTMPPai:AddField(; "Codigo",; // [01] C Titulo do campo "Codigo",; // [02] C ToolTip do campo "TMPAI_COD",; // [03] C Id do Field "C",; // [04] C Tipo do campo 06,; // [05] N Tamanho do campo 0,; // [06] N Decimal do campo Nil,; // [07] B Code-block de validação do campo Nil,; // [08] B Code-block de validação When do campo {},; // [09] A Lista de valores permitido do campo .T.,; // [10] L Indica se o campo tem preenchimento obrigatório FwBuildFeature( STRUCT_FEATURE_INIPAD, "Iif(!INCLUI,"+cAliasTmp1+"->TMPAI_COD,'')" ),; // [11] B Code-block de inicializacao do campo .T.,; // [12] L Indica se trata-se de um campo chave .F.,; // [13] L Indica se o campo pode receber valor em uma operação de update. .F.) // [14] L Indica se o campo é virtual oStTMPPai:AddField(; "Descricao",; // [01] C Titulo do campo "Descricao",; // [02] C ToolTip do campo "TMPAI_DES",; // [03] C Id do Field "C",; // [04] C Tipo do campo 50,; // [05] N Tamanho do campo 0,; // [06] N Decimal do campo Nil,; // [07] B Code-block de validação do campo Nil,; // [08] B Code-block de validação When do campo {},; // [09] A Lista de valores permitido do campo .T.,; // [10] L Indica se o campo tem preenchimento obrigatório FwBuildFeature( STRUCT_FEATURE_INIPAD, "Iif(!INCLUI,"+cAliasTmp1+"->TMPAI_DES,'')" ),; // [11] B Code-block de inicializacao do campo .F.,; // [12] L Indica se trata-se de um campo chave .F.,; // [13] L Indica se o campo pode receber valor em uma operação de update. .F.) // [14] L Indica se o campo é virtual oStTMPPai:AddField(; "Valor",; // [01] C Titulo do campo "Valor",; // [02] C ToolTip do campo "TMPAI_VAL",; // [03] C Id do Field "N",; // [04] C Tipo do campo 10,; // [05] N Tamanho do campo 02,; // [06] N Decimal do campo Nil,; // [07] B Code-block de validação do campo Nil,; // [08] B Code-block de validação When do campo {},; // [09] A Lista de valores permitido do campo .F.,; // [10] L Indica se o campo tem preenchimento obrigatório FwBuildFeature( STRUCT_FEATURE_INIPAD, "Iif(!INCLUI,"+cAliasTmp1+"->TMPAI_VAL,'')" ),; // [11] B Code-block de inicializacao do campo .F.,; // [12] L Indica se trata-se de um campo chave .F.,; // [13] L Indica se o campo pode receber valor em uma operação de update. .F.) // [14] L Indica se o campo é virtual oStTMPPai:AddField(; "Data",; // [01] C Titulo do campo "Data",; // [02] C ToolTip do campo "TMPAI_DAT",; // [03] C Id do Field "D",; // [04] C Tipo do campo 08,; // [05] N Tamanho do campo 0,; // [06] N Decimal do campo Nil,; // [07] B Code-block de validação do campo Nil,; // [08] B Code-block de validação When do campo {},; // [09] A Lista de valores permitido do campo .F.,; // [10] L Indica se o campo tem preenchimento obrigatório FwBuildFeature( STRUCT_FEATURE_INIPAD, "Iif(!INCLUI,"+cAliasTmp1+"->TMPAI_DAT,'')" ),; // [11] B Code-block de inicializacao do campo .F.,; // [12] L Indica se trata-se de um campo chave .F.,; // [13] L Indica se o campo pode receber valor em uma operação de update. .F.) // [14] L Indica se o campo é virtual // -- oStTMPFil:AddField(; "Codigo",; // [01] C Titulo do campo "Codigo",; // [02] C ToolTip do campo "TMFIL_COD",; // [03] C Id do Field "C",; // [04] C Tipo do campo 06,; // [05] N Tamanho do campo 0,; // [06] N Decimal do campo Nil,; // [07] B Code-block de validação do campo Nil,; // [08] B Code-block de validação When do campo {},; // [09] A Lista de valores permitido do campo .F.,; // [10] L Indica se o campo tem preenchimento obrigatório FwBuildFeature( STRUCT_FEATURE_INIPAD, "Iif(!INCLUI,"+cAliasTmp2+"->TMFIL_COD,'')" ),; // [11] B Code-block de inicializacao do campo .T.,; // [12] L Indica se trata-se de um campo chave .F.,; // [13] L Indica se o campo pode receber valor em uma operação de update. .F.) // [14] L Indica se o campo é virtual oStTMPFil:AddField(; "Item",; // [01] C Titulo do campo "Item",; // [02] C ToolTip do campo "TMFIL_ITEM",; // [03] C Id do Field "C",; // [04] C Tipo do campo 2,; // [05] N Tamanho do campo 0,; // [06] N Decimal do campo Nil,; // [07] B Code-block de validação do campo Nil,; // [08] B Code-block de validação When do campo {},; // [09] A Lista de valores permitido do campo .T.,; // [10] L Indica se o campo tem preenchimento obrigatório FwBuildFeature( STRUCT_FEATURE_INIPAD, "Iif(!INCLUI,"+cAliasTmp2+"->TMFIL_ITEM,'')" ),; // [11] B Code-block de inicializacao do campo .F.,; // [12] L Indica se trata-se de um campo chave .F.,; // [13] L Indica se o campo pode receber valor em uma operação de update. .F.) // [14] L Indica se o campo é virtual oStTMPFil:AddField(; "Descricao",; // [01] C Titulo do campo "Descricao",; // [02] C ToolTip do campo "TMFIL_DESC",; // [03] C Id do Field "C",; // [04] C Tipo do campo 100,; // [05] N Tamanho do campo 0,; // [06] N Decimal do campo Nil,; // [07] B Code-block de validação do campo Nil,; // [08] B Code-block de validação When do campo {},; // [09] A Lista de valores permitido do campo .T.,; // [10] L Indica se o campo tem preenchimento obrigatório FwBuildFeature( STRUCT_FEATURE_INIPAD, "Iif(!INCLUI,"+cAliasTmp2+"->TMFIL_DESC,'')" ),; // [11] B Code-block de inicializacao do campo .F.,; // [12] L Indica se trata-se de um campo chave .F.,; // [13] L Indica se o campo pode receber valor em uma operação de update. .F.) // [14] L Indica se o campo é virtual //Cria o modelo de dados para cadastro oModel := MPFormModel():New("zVid128M", bPre, bPos, /*bCommit*/, bCancel) oModel:AddFields("PAIMASTER", /*cOwner*/, oStTMPPai) oModel:AddGrid("FILDETAIL","PAIMASTER",oStTMPFil,/*bLinePre*/, /*bLinePost*/,/*bPre - Grid Inteiro*/,/*bPos - Grid Inteiro*/, {|oGridFilho| fLoadGrid(oGridFilho)}) oModel:SetDescription("Modelo de dados - " + cTitulo) oModel:GetModel("PAIMASTER"):SetDescription( "Dados de - " + cTitulo) oModel:GetModel("FILDETAIL"):SetDescription( "Grid de - " + cTitulo) oModel:SetPrimaryKey({}) //Fazendo o relacionamento aAdd(aRelation, {"FIL_FILIAL", "FWxFilial('FIL')"} ) aAdd(aRelation, {"TMFIL_COD", "TMPAI_COD"}) oModel:SetRelation("FILDETAIL", aRelation, FIL->(IndexKey(1))) //Definindo campos unicos da linha oModel:GetModel("FILDETAIL"):SetUniqueLine({'TMFIL_DESC'}) Return oModel /*/{Protheus.doc} ViewDef Visualizacao de dados na funcao zVid0128 @author Atilio @since 15/03/2024 @version 1.0 /*/ Static Function ViewDef() Local oModel := FWLoadModel("zVid0128") Local oStTMPPai := FWFormViewStruct():New() Local oStTMPFil := FWFormViewStruct():New() Local oView := Nil //Adicionando campos da estrutura oStTMPPai:AddField(; "TMPAI_COD",; // [01] C Nome do Campo "01",; // [02] C Ordem "Codigo",; // [03] C Titulo do campo "Codigo",; // [04] C Descricao do campo Nil,; // [05] A Array com Help "C",; // [06] C Tipo do campo "@!",; // [07] C Picture Nil,; // [08] B Bloco de PictTre Var Nil,; // [09] C Consulta F3 Iif(INCLUI, .T., .F.),; // [10] L Indica se o campo é alteravel Nil,; // [11] C Pasta do campo Nil,; // [12] C Agrupamento do campo Nil,; // [13] A Lista de valores permitido do campo (Combo) Nil,; // [14] N Tamanho maximo da maior opção do combo Nil,; // [15] C Inicializador de Browse Nil,; // [16] L Indica se o campo é virtual Nil,; // [17] C Picture Variavel Nil) // [18] L Indica pulo de linha após o campo oStTMPPai:AddField(; "TMPAI_DES",; // [01] C Nome do Campo "02",; // [02] C Ordem "Descricao",; // [03] C Titulo do campo "Descricao",; // [04] C Descricao do campo Nil,; // [05] A Array com Help "C",; // [06] C Tipo do campo "@!",; // [07] C Picture Nil,; // [08] B Bloco de PictTre Var Nil,; // [09] C Consulta F3 .T.,; // [10] L Indica se o campo é alteravel Nil,; // [11] C Pasta do campo Nil,; // [12] C Agrupamento do campo Nil,; // [13] A Lista de valores permitido do campo (Combo) Nil,; // [14] N Tamanho maximo da maior opção do combo Nil,; // [15] C Inicializador de Browse Nil,; // [16] L Indica se o campo é virtual Nil,; // [17] C Picture Variavel Nil) // [18] L Indica pulo de linha após o campo oStTMPPai:AddField(; "TMPAI_VAL",; // [01] C Nome do Campo "03",; // [02] C Ordem "Valor",; // [03] C Titulo do campo "Valor",; // [04] C Descricao do campo Nil,; // [05] A Array com Help "N",; // [06] C Tipo do campo "@E 9,999,999.99",; // [07] C Picture Nil,; // [08] B Bloco de PictTre Var Nil,; // [09] C Consulta F3 .T.,; // [10] L Indica se o campo é alteravel Nil,; // [11] C Pasta do campo Nil,; // [12] C Agrupamento do campo Nil,; // [13] A Lista de valores permitido do campo (Combo) Nil,; // [14] N Tamanho maximo da maior opção do combo Nil,; // [15] C Inicializador de Browse Nil,; // [16] L Indica se o campo é virtual Nil,; // [17] C Picture Variavel Nil) // [18] L Indica pulo de linha após o campo oStTMPPai:AddField(; "TMPAI_DAT",; // [01] C Nome do Campo "04",; // [02] C Ordem "Data",; // [03] C Titulo do campo "Data",; // [04] C Descricao do campo Nil,; // [05] A Array com Help "D",; // [06] C Tipo do campo "@D",; // [07] C Picture Nil,; // [08] B Bloco de PictTre Var Nil,; // [09] C Consulta F3 .T.,; // [10] L Indica se o campo é alteravel Nil,; // [11] C Pasta do campo Nil,; // [12] C Agrupamento do campo Nil,; // [13] A Lista de valores permitido do campo (Combo) Nil,; // [14] N Tamanho maximo da maior opção do combo Nil,; // [15] C Inicializador de Browse Nil,; // [16] L Indica se o campo é virtual Nil,; // [17] C Picture Variavel Nil) // [18] L Indica pulo de linha após o campo // - oStTMPFil:AddField(; "TMFIL_COD",; // [01] C Nome do Campo "01",; // [02] C Ordem "Codigo",; // [03] C Titulo do campo "Codigo",; // [04] C Descricao do campo Nil,; // [05] A Array com Help "C",; // [06] C Tipo do campo "@!",; // [07] C Picture Nil,; // [08] B Bloco de PictTre Var Nil,; // [09] C Consulta F3 Iif(INCLUI, .T., .F.),; // [10] L Indica se o campo é alteravel Nil,; // [11] C Pasta do campo Nil,; // [12] C Agrupamento do campo Nil,; // [13] A Lista de valores permitido do campo (Combo) Nil,; // [14] N Tamanho maximo da maior opção do combo Nil,; // [15] C Inicializador de Browse Nil,; // [16] L Indica se o campo é virtual Nil,; // [17] C Picture Variavel Nil) // [18] L Indica pulo de linha após o campo oStTMPFil:AddField(; "TMFIL_ITEM",; // [01] C Nome do Campo "02",; // [02] C Ordem "Item",; // [03] C Titulo do campo "Item",; // [04] C Descricao do campo Nil,; // [05] A Array com Help "C",; // [06] C Tipo do campo "@!",; // [07] C Picture Nil,; // [08] B Bloco de PictTre Var Nil,; // [09] C Consulta F3 .F.,; // [10] L Indica se o campo é alteravel Nil,; // [11] C Pasta do campo Nil,; // [12] C Agrupamento do campo Nil,; // [13] A Lista de valores permitido do campo (Combo) Nil,; // [14] N Tamanho maximo da maior opção do combo Nil,; // [15] C Inicializador de Browse Nil,; // [16] L Indica se o campo é virtual Nil,; // [17] C Picture Variavel Nil) // [18] L Indica pulo de linha após o campo oStTMPFil:AddField(; "TMFIL_DESC",; // [01] C Nome do Campo "03",; // [02] C Ordem "Descrição",; // [03] C Titulo do campo "Descrição",; // [04] C Descricao do campo Nil,; // [05] A Array com Help "C",; // [06] C Tipo do campo "@!",; // [07] C Picture Nil,; // [08] B Bloco de PictTre Var Nil,; // [09] C Consulta F3 .T.,; // [10] L Indica se o campo é alteravel Nil,; // [11] C Pasta do campo Nil,; // [12] C Agrupamento do campo Nil,; // [13] A Lista de valores permitido do campo (Combo) Nil,; // [14] N Tamanho maximo da maior opção do combo Nil,; // [15] C Inicializador de Browse Nil,; // [16] L Indica se o campo é virtual Nil,; // [17] C Picture Variavel Nil) // [18] L Indica pulo de linha após o campo //Cria a visualizacao do cadastro oView := FWFormView():New() oView:SetModel(oModel) oView:AddField("VIEW_PAI", oStTMPPai, "PAIMASTER") oView:AddGrid("VIEW_FIL", oStTMPFil, "FILDETAIL") //Partes da tela oView:CreateHorizontalBox("CABEC", 30) oView:CreateHorizontalBox("GRID", 70) oView:SetOwnerView("VIEW_PAI", "CABEC") oView:SetOwnerView("VIEW_FIL", "GRID") //Titulos oView:EnableTitleView("VIEW_PAI", "Cabecalho - PAI") oView:EnableTitleView("VIEW_FIL", "Grid - FILHO") //Removendo campos oStTMPFil:RemoveField("TMFIL_COD") //Adicionando campo incremental na grid oView:AddIncrementField("VIEW_FIL", "TMFIL_ITEM") Return oView Static Function fLoadGrid(oGridFilho) Local aArea := FWGetArea() Local aRetorno := {} Local cCampos := '%R_E_C_N_O_, TMFIL_COD, TMFIL_ITEM, TMFIL_DESC%' Local cTmpQry := GetNextAlias() Local cTabela := '%' + oTmpTable2:GetRealName() + '%' Local cCodPai := (cAliasTmp1)->TMPAI_COD //Executa a query SQL, filtrando o código do pai na tabela de filhos BeginSQL Alias cTmpQry SELECT %Exp:cCampos% FROM %Exp:cTabela% WHERE TMFIL_COD = %Exp:cCodPai% AND %NotDel% ORDER BY TMFIL_ITEM EndSQL //Executa a função FWLoadByAlias populando a grid e fecha a query aRetorno := FWLoadByAlias(oGridFilho, cTmpQry) (cTmpQry)->(DBCloseArea()) FWRestArea(aArea) Return aRetorno
Bom pessoal, por hoje é só.
Abraços e até a próxima.