+5 votos
389 visitas
Temos uma rotina escrita em Delphi que emite notas fiscais de serviço para as prefeituras. Esta rotina utiliza um container de itens como base para quase tudo. Como cada prefeitura tem suas regras específicas, acontece com muita frequência de uma correção feita para um determinado município acabar estragando o funcionamento de outro município e sério... estamos nesse loop há mais de ano!

Para evitar este tipo de problema, definimos que o caminho é criar testes automatizados e assim eles servirão como requisitos de negócio, que mudam de cidade para cidade, evitando essa quebra constante nos clientes, mesmo que várias pessoas trabalhem na rotina sem conhecer os detalhes de cada prefeitura.

Identificamos que seria suficiente refatorar apenas um trecho da rotina para possibilitar a criação de testes unitários e para isso pensamos em criá-la em C#, possibilitando que estes testes rodem no build.

Tentamos utilizar a interface IDContainerToEntitiesProxy (documentação: http://wiki.benner.com.br/wiki/index.php?title=IDContainerToEntitiesProxy) para transformar o container do Delphi em um Entities<EntityBase> no C#. Mas tivemos algumas dificuldades porque o Entities não tem FieldDefinitions e com isso não conseguimos dar GetAsString, GetAsInteger, etc. Fica tudo string e tem que usar parse direto, o que não é muito legal.

Por esta razão, há um tempo atrás foi criado aqui no corporativo um cara que lê o XML obtido pelo método TDContainer.GetXML() e transforma num IList<IEntityBase>. Com isso, a vinda do container para o C# está funcionando. Aí trabalhamos com esses valores do container no C# e agora gostaríamos de devolver o container atualizado.

Tentamos utilizar o IEntityToDelphiDataSetProxy (documentação: http://wiki.benner.com.br/wiki/index.php?title=TEntityDataSet), mas ele se torna um IDispatch no Delphi e tornou-se difícil repassar essas informações ao container que já estava criado e sendo utilizado antes de chegar na chamada do C#.

Essas dificuldades com a interoperabilidade do Container entre Delphi e C#, estão nos limitando com relação à refatoração de código e migração para C#.

Existe uma forma "correta" de se fazer isso?

Resumo da necessidade: Enviar um container já instanciado do Delphi para o C#, trabalhar com os dados no C# e receber o container com os dados já atualizados no Delphi.
por (97 pontos) | 389 visitas
Você consegue demostrar um pouco de código? De como é transformado num  IList<IEntityBase> ?
Para ter a interoperabilidade do DContainer entre Delphi e C# com retorno dos valores você deve utilizar o IDContainerToEntitiesProxy como citado.

O DContainerToEntitiesProxy já cria uma definição dos FieldDefinitions com todos os campos do DContainer ou com uma definição da tabela pela função do Delphi DContainerToEntitiesWithDefinition(dc: TDContainer; entityDefinitionName: string).

Consegues demostrar o problema do GetAsString, GetAsInteger, etc? E como é chamada a função do DContainerToEntitiesProxy ?
Isso é o que temos para transformar o XML do container em um IList<IEntityBase>:

public IList<IEntityBase> DestrincharParaEntityBase(string xml)
        {
            IList<IEntityBase> result = new List<IEntityBase>();

            XElement content = GetElementFromContainer(xml, "CONTENT");

            IEntityBuilder modelBuilder = CriarModeloEntityBaseDoContainer(xml);

            foreach (var row in content.Elements("ROW"))
            {
                IEntityBase model = modelBuilder.Build();

                foreach (var field in row.Elements())
                    model[field.Name.LocalName].Value = field.Value.Replace(".period;", ".");

                result.Add(model);
            }

            return result;
        }

--------------------------

private XElement GetElementFromContainer(string xml, string elementName)
        {
            return XDocument.Parse(xml).Element("PACKEDCONTAINER").Element(elementName);
        }

--------------------------

private IEntityBuilder CriarModeloEntityBaseDoContainer(string xml)
        {
            byte fieldsIndex = 0;
            byte fieldsTypeIndex = 1;

            XElement fieldsDef = GetElementFromContainer(xml, "FIELDSDEF");

            string[] fieldsAndTypes = fieldsDef.FirstNode.ToString().Split(';');

            IEntityBuilder entityBuilder = new EntityBuilder();

            foreach (var item in fieldsAndTypes)
            {
                if (item.Length <= 0)
                    continue;

                string[] currentFields = item.Split(':');
                string[] fields = currentFields[fieldsIndex].Split(',');

                string fieldType = currentFields[fieldsTypeIndex].ToUpper();

                foreach (var field in fields)
                {
                    switch (fieldType)
                    {
                        case "CURRENCY":
                        case "MONEY":
                        case "DOUBLE":
                            entityBuilder.AddDecimal(field, 0m);
                            break;

                        case "INTEGER":
                            entityBuilder.AddInteger(field, 0);
                            break;

                        case "STRING":
                        case "CHAR":
                            entityBuilder.AddString(field, string.Empty);
                            break;

                        case "TDATETIME":
                        case "DATETIME":
                            entityBuilder.AddDateTime(field, DateTime.MinValue);
                            break;

                        case "BOOLEAN":
                            entityBuilder.AddBoolean(field, false);
                            break;
                    }
                }

            }
            return entityBuilder;
        }
"Para ter a interoperabilidade do DContainer entre Delphi e C# com retorno dos valores você deve utilizar o IEntityToDelphiDataSetProxy como citado."

Como repasso os valores do IDispatch para o container atual sem ter que percorrer todos os campos toda vez que precisar desse repasse?

1 Resposta

+1 voto
Melhor resposta

Você esta criando um novo objeto no C# pelo XML do DContainer, por enquanto não é possivel converte-ló novamente em DContainer no Delphi. Da para converter em DataSet, com IEntityToDelphiDataSetProxy , mas terá que alterar o código Delphi. 

Você deveria utilizar a função DContainerToEntities e utilizar a interface IDContainerToEntitiesProxy no C#.

Se houver problemas ao utilizar as funções GetAsString, GetAsInteger, etc. Deves criar uma SMS para Tecnologia. Mas como o entityDefinition já é criado na ultima versão, junto com os FieldsDefinition, e as funções acima devem funcionar.

 

por (956 pontos)
selecionada por
Conforme vimos juntos, quando utilizamos o IDContainerToEntitiesProxy para envio do container ao C#, não há uma implementação que atualize os valores na volta para o Delphi.

Estou abrindo uma SMS de implementação, conforme alinhamos.

Abertas as seguintes SMS's:

1699139 - "KeyNotFoundException - O campo 'x' não existe na entidade" ao tentar usar a interface IEntityBase de um objeto IDContainerToEntitiesProxy vindo do Delphi

1699168 - Implementar no C# o retorno dos dados de um container que tenha vindo do Delphi pelo uso da interface IDContainerToEntitiesProxy

Perguntas relacionadas

+4 votos
2 respostas
+6 votos
1 resposta
perguntado 16 Set, 2014 por bruno.cardoso (282 pontos) | 107 visitas
+3 votos
1 resposta
+2 votos
2 respostas
perguntado 14 Nov, 2019 por pajucara.wallacef (29 pontos) | 249 visitas
Melhores Aug 2025
    200 pontos
    Melhores 2025 Jul 28 - Aug 03
    1. Larson

      156 Pontos

    2. danilo.pereira

      96 Pontos

    3. danilo.pereira

      96 Pontos

    4. danilo.pereira

      96 Pontos

    5. luciano.fronza

      61 Pontos

    6. luciano.fronza

      61 Pontos

    7. luciano.fronza

      61 Pontos

    8. diuari.molinari

      52 Pontos

    9. diuari.molinari

      51 Pontos

    10. diuari.molinari

      51 Pontos

    517 perguntas
    566 respostas
    389 comentários
    704 usuários