none
Como inserir dados de um XML no banco de dados usando DataSet RRS feed

  • Pergunta

  • Bom dia,

    estou desenvolvendo uma aplicação para Pocket PC onde o mesmo faz uma solicitação ao WebService de alguns dados, ele me retorna um XML com os dados. Até ai tudo bem, o problema é na hora de pegar essas informações e inserir no banco de dados.
    Queria que, quando receber o XML eu iria inserir ele em um DataSet para depois fazer o insert no banco de dados.
    Mas não estou conseguindo, ele não insere.

    Estou utilizando o metodo Update do DataAdapter para fazer esse insert:

    DataSet xml = new DataSet("Shippers");
    xml.ReadXml("\\caminho onde esta o arquivo\\Dados.xml");
    xml.AcceptChanges();

    Na camada de acesso a dados, eu recebo esse dataset e o comando de insert:

    pComandText: "INSERT INTO [Shippers] ([Company Name]) VALUES (@p1)";

     SqlCeDataAdapter adpt = new SqlCeDataAdapter(pComandText, conexao);
     conexao.Open();        

     adpt.Update(dataSet, "nome da tabela que esta no banco do pocket pc");

     conexao.Close();
     adpt.Dispose();
     dataSet.Dispose();  

    Mas não insere..como posso resolver isso?

    Obrigado.



    quarta-feira, 20 de fevereiro de 2008 14:48

Respostas

  • Po estou começando a icar preocupado, ou eu escrevo mal, ou vc está interpretando me errado. rs

    Mas é o seguinte, o Command, o Parameters, e o Prepare, voce deve instanciar e setar as propriedades ANTES de fazer o loop para ler o xml.

     

    Code Snippet

    SqlCeCommand cmd = new SqlCeCommand(comandoSql, conn);

    //abaixo voce deverá informar TODOS os parametros disponíveis, e deixe o parametro value null

    cmd.Parameters.Add("@p" + position, null); 

     

    //chame o prepare ANTES do loop

    cmd.Prepare();

     reader = new XmlTextReader(new StringReader(xml));
                    reader.WhitespaceHandling = WhitespaceHandling.None;
                    int position = 1;               

                    while (reader.Read())
                    {
                        switch (reader.NodeType)
                        {
                            case XmlNodeType.Element:

                                if (reader.IsStartElement())
                                {
                                    if (reader.IsEmptyElement)
                                    {
                                                                          
                                        position++;
                                    }
                                }
                                break;

                            case XmlNodeType.Text:

                                //informe o valor respectivo do campo somente
                                cmd.Parameters[position].Value = reader.Value;                           
                                position++;
                                break;

                            case XmlNodeType.EndElement:

                                if (reader.Name == "tb_ativo")
                                { 

                        //simplesmente executa.           

    cmd.ExecuteNonQuery();


                                    //cmd.Parameters.Clear(); não limpa o parameters

                                    position = 1;                               
                                }
                                break;
                        }
                    }

     

     


    Abraços

    quinta-feira, 21 de fevereiro de 2008 20:10

Todas as Respostas

  • Olá Wilker,

     

    Olha, não vou te ajudar diretamente, mas vou te dar uma ótima dica, utilize o XmlTextReader para ler o xml ( de preferencia sem salvar ele, utilize-o na memória mesmo ), crie um comand, utilizando os parameter, o metodo Prepare(), e depois faça um loop e insira os dados, é muito mais rápido, e voce não compromete a memória do dispositivo, No msdn.com voce encontra bastante exemplos de como utilizar o XmlTextReader, e bastante referencia mostrando questões de performance utilizando ele. Dá mais trabalho, mas o resultado, vale muito a pena

     

    Abraços

    quarta-feira, 20 de fevereiro de 2008 15:38
  • Julio vlw d+....vou olhar sim....

    e obrigado pela resposta....

    flw...
    quarta-feira, 20 de fevereiro de 2008 17:10
  • E ai Julio, blz?

    Cara, eu olhei o XmlTextReader e alguns exemplos e fiz um método que trata o arquivo XML para pegar os Parametros para depois inserir no banco de dados.
    Segue o exemplo:

     XmlTextReader reader = new XmlTextReader(new StringReader("arquivo xml"));
                    reader.WhitespaceHandling = WhitespaceHandling.None;

                    SqlCeParameter ps = null;

          // lista com os parametros que serão utilizados para o insert
                    List<SqlCeParameter> parameters = new List<SqlCeParameter>();
                   

         // aki que eu não tive ideia melhor pra fazer. Seguinte: no arquivo XML eu preciso pegar a primeira sequencia
         // dos Shippers e fazer o insert no banco de dados, depois pegar a outra e assim por diante...
        /*  <Shippers>

        <Shippers>
            <Shippers_ID>1</Shippers_ID>
            <Shippers_Nome>ASDF</Shippers_Nome>
        </Shippers>

        <Shippers>
            <Shippers_ID>1</Shippers_ID>
            <Shippers_Nome>ASDF</Shippers_Nome>
        </Shippers>

    </Shippers>
    */

    //aki é pra guardar os elementos para depois verificar quando acabou de fazer a leitura de um
    Shippers
                    System.Collections.ArrayList elementos = new System.Collections.ArrayList();
                    while (reader.Read())
                    {
                        switch (reader.NodeType)
                        {
                            case XmlNodeType.Element:
                                elementos.Add(reader.Name);
                                break;
                            case XmlNodeType.Text:
                                ps = new SqlCeParameter("@p" + position, reader.Value);
                                parameters.Add(ps);
                                position++;
                                break;
                            case XmlNodeType.EndElement:
                                elementos.Remove(reader.Name);
    // quando so tiver um elemento...que seria o ultimo do arquivo, entao ele faz o insert no banco
                                if (elementos.Count == 1)
                                {
                                   
                                    MobileSQLHelper.ExecuteNonQuery(strConexao,
                                                 "INSERT INTO [Shippers] ([Company Name]) VALUES (@p1)",
                                                 parameters);

                                    parameters.Clear();
                                    position = 0;
                                }
                                break;
                        }

                    }

                    if (reader != null)
                        reader.Close();

    Queria uma opinião/ajuda para melhorar isso, pois quando faço o insert de muitos dados, fica lento, e o arquivo que vou tratar quando estiver em produção, é muito grande..

    Obrigado.
    quarta-feira, 20 de fevereiro de 2008 20:13
  • Olá Wilker,

     

     Caramba rapaz, se voce achou o resultado assim lento, vc iria chorar quando visse o resultado utilizando dataset....

     Então, eu não me lembro bem de cabeça como funciona o xmltextreader, pra isso vou ter que ler a documentação e procurar algum exemplo meu ehheeh, mas eu acho que voce não precisa guardar o nome do elemento para verificar o final dele, veja com mais calma como funciona o read com o NodeType.

     E um outro detalhe, não fará muita diferença se voce utilizar poucos registros, mas se voce trabalhar com muitos registros, sugiro que voce não utilize o sqlHelper, e crie uma classe simples pra fazer isso, e o seu objeto command, instancie ele 1 vez só, adicione os parametros 1 vez só, com TODOS os parametros possíveis ( isso é muito importante), e depois chame o metodo Prepare() para após isso voce iniciar o loop, e somente lá chamar o executenonquery, e no final não se esqueça de liberar os objetos que vc utilizou.

     Uma outra opção se a quantidade de informação for muito grande, é voce estudar a possibilidade de utilizar o RDA, ou até para o xml ficar "menor" utilize números no nome do campo :

    <t1>

    <1>1</1>
    <2>ASDF</2>

    </t1>

    é "gambiarra" forte, mas vc ganha muito na performance.

     

    Abraços
    quinta-feira, 21 de fevereiro de 2008 13:14
  • opa...Julio...vlw novamente pela ajuda...

    Mas vou abusar mais um pouco...heheh..

    Cara, fiz o seguinte:

                    int position = 1;
                    XmlTextReader reader = new XmlTextReader(new StringReader("xml a ser inserido.xml"));
                    reader.WhitespaceHandling = WhitespaceHandling.None;

                    SqlCeParameter ps = null;
                    List<SqlCeParameter> parameters = new List<SqlCeParameter>();

                    while (reader.Read())
                    {
                        switch (reader.NodeType)
                        {
                            case XmlNodeType.Element:

                                if (reader.IsStartElement())
                                {
                                    if (reader.IsEmptyElement)
                                    {
                                        ps = new SqlCeParameter("@p" + position, null);
          parameters.Add(ps);
          position++;
                                    }
                                }
                                break;

                            case XmlNodeType.Text:

                                ps = new SqlCeParameter("@p" + position, reader.Value);
            parameters.Add(ps);
            position++;
                                break;

                            case XmlNodeType.EndElement:

                                if (reader.Name == "book")
                                {
                                    MobileSQLHelper.ExecuteNonQuery(conn, tras,
                                                         "INSERT INTO [tabela] VALUES (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8," +
                                                           "@p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17)",
                                                           parameters);

                                    parameters.Clear();
                                    position = 1;
                                    tras.Commit();
                                }
                                break;
                        }
                    }

    Bom, assim eu consigo pegar todos os dados necessário para meu insert no banco de dados.
    No metodo MobileSQLHelper.ExecuteNonQuery que criei, eu passo os dados necessário para fazer o insert. Lá é criado somente um Command onde eu passo para o command os paramentros e mando executar e faço o dispose dos objetos que usei.
    Eu tive que fazer um IF no EndElement para verificar se fechou um "bloco" para poder fazer o insert de um dado, pois não achei outra forma de confirmar o fechamento do "bloco":

    <Teste>
        <book>
            <title>Pride And Prejudice</title>
            <misc/>
            <nome>JOAO</nome>
            <valor>100</valor>
        </book>
        <book>
            <title>ÇÇÇÇ</title>
            <misc>555</misc>
            <nome>JHOAO</nome>
            <valor>200</valor>
        </book>

        <book>
            <title>JOAO MARIA JOSE</title>
            <misc>3333</misc>
            <nome>JBAHASDF</nome>
            <valor>2727</valor>
        </book>
       
    </Teste>

    Será q agora ficou melhor?...rsrsr

    Mas ja agradeço a ajuda...

    Obrigado..
    quinta-feira, 21 de fevereiro de 2008 17:00
  • Olá Wilker,

     

     Cara se ficou melhor, quem decide isso é voce, ou o seu chefe rs.

     

    Aos meus olhos, uso do xmltextreader está estranho, e com relação ao uso do Command, com o Parameters, é como eu disse anteriormente, do jeito que voce está utilizando no exemplo acima, voce está perdendo performance, instanciando várias vezes o command e os parameters, não estou supondo, estou afirmando, se voce criar o command antes,  com todos os parameters, executar o Prepare() e durante o loop atribuir os valores e executar a query, vai ficar + rápido, mas isso com muitos registros, se voce for utilizar só una 1000 registros, nem se de ao trabalho, ams se voce começar a trabalhar com 10000 pra cima, aí vale a pena.... e é claro isso depende também da quantidade de campos....

     

    Dá uma lida nesses artigos :

    http://msdn2.microsoft.com/en-us/library/aa446542.aspx#netcfperf_topic019

    http://msdn2.microsoft.com/en-us/library/1766918e.aspx

    http://msdn2.microsoft.com/en-us/netframework/aa497275.aspx

     

    Este não tem nada a ver mas é muito bom :

    http://msdn2.microsoft.com/en-us/library/aa446535.aspx

     

    Abraços
    quinta-feira, 21 de fevereiro de 2008 17:46
  • Ola Julio,

    Ja agradeço novamente pela ajuda...

    Bom, pelo que eu entendi sobre o Command, pois ainda não tive tempo e olhar a parte do xmltextreader, ficou assim:

    SqlCeCommand cmd = new SqlCeCommand(comandoSql, conn);

     reader = new XmlTextReader(new StringReader(xml));
                    reader.WhitespaceHandling = WhitespaceHandling.None;
                    int position = 1;               

                    while (reader.Read())
                    {
                        switch (reader.NodeType)
                        {
                            case XmlNodeType.Element:

                                if (reader.IsStartElement())
                                {
                                    if (reader.IsEmptyElement)
                                    {
                                        cmd.Parameters.Add("@p" + position, null);                                  
                                        position++;
                                    }
                                }
                                break;

                            case XmlNodeType.Text:

                                cmd.Parameters.Add("@p" + position, reader.Value);                           
                                position++;
                                break;

                            case XmlNodeType.EndElement:

                                if (reader.Name == "tb_ativo")
                                {
      cmd.Prepare();
                                    cmd.ExecuteNonQuery();
                                    cmd.Parameters.Clear();

                                    position = 1;                               
                                }
                                break;
                        }
                    }

    Bom essa é parte do Command, agora a do XML ainda vou ter que olhar...
    Mas é assim ou estou invertendo as ordens?

    Obrigado.
    quinta-feira, 21 de fevereiro de 2008 19:29
  • Po estou começando a icar preocupado, ou eu escrevo mal, ou vc está interpretando me errado. rs

    Mas é o seguinte, o Command, o Parameters, e o Prepare, voce deve instanciar e setar as propriedades ANTES de fazer o loop para ler o xml.

     

    Code Snippet

    SqlCeCommand cmd = new SqlCeCommand(comandoSql, conn);

    //abaixo voce deverá informar TODOS os parametros disponíveis, e deixe o parametro value null

    cmd.Parameters.Add("@p" + position, null); 

     

    //chame o prepare ANTES do loop

    cmd.Prepare();

     reader = new XmlTextReader(new StringReader(xml));
                    reader.WhitespaceHandling = WhitespaceHandling.None;
                    int position = 1;               

                    while (reader.Read())
                    {
                        switch (reader.NodeType)
                        {
                            case XmlNodeType.Element:

                                if (reader.IsStartElement())
                                {
                                    if (reader.IsEmptyElement)
                                    {
                                                                          
                                        position++;
                                    }
                                }
                                break;

                            case XmlNodeType.Text:

                                //informe o valor respectivo do campo somente
                                cmd.Parameters[position].Value = reader.Value;                           
                                position++;
                                break;

                            case XmlNodeType.EndElement:

                                if (reader.Name == "tb_ativo")
                                { 

                        //simplesmente executa.           

    cmd.ExecuteNonQuery();


                                    //cmd.Parameters.Clear(); não limpa o parameters

                                    position = 1;                               
                                }
                                break;
                        }
                    }

     

     


    Abraços

    quinta-feira, 21 de fevereiro de 2008 20:10
  • Ola Juliano..

    Cara, deu certo....e fiz uma medição de tempo e realmente ficou bem mais rápido...vlw mesmo...tipo, sem usar o prepare dava um tempo de -44273 usando dessa forma que vc me explicou, deu -29450, pra uma determinada quantidade de dados.

    Cara vc me ajudou e muito...

    Posso até dar por encerrado essa dúvida...muito obrigado mesmo....

    Até a proxima dúvida....

    ps.: vou olhar melhor os links que vc me passou....

    Obrigado.
    quinta-feira, 21 de fevereiro de 2008 20:46