LavsTo
LavsTo

Reputation: 129

XML Bulk Import of Records Using PostgreSQLCopyHelper - Npgsql.PostgresException: 42601

On importing records from an XML with two records file into database table, I have an issue were the first record is being inserted twice while the second record isn't getting saved into the table.

This is the XML file with the two records/products

<?xml version="1.0" encoding="ISO-8859-1"?>
<ProdExtract>

 <ExtractHeader>
  <Schema>
   <id>Accord ePOS Product Extract</id>
   <Version>1.00</Version>
  </Schema>  
 </ExtractHeader>

 <Product>
  <Mode>Modify</Mode>
   <ProductID>  
    <LongDescription>ZOLMANS MINT SAUCE      #</LongDescription>  
   </ProductID>
   <BasicFields>  
    <Units>6</Units>
    <VAT VatCode="A" VatRate="0" />  
   </BasicFields>
   <Price>  
    <CurrentWSP>9.55</CurrentWSP>
    <CurrentRSP>2.01</CurrentRSP>  
   </Price>
   <Barcode>  
    <Eancode>5000147032921</Eancode>  
   </Barcode>
 </Product>

 <Product>
  <Mode>Modify</Mode>
   <ProductID>  
    <LongDescription>TEST XML IMPORT PRODUCT     </LongDescription>  
   </ProductID>
   <BasicFields>  
    <Units>10</Units>
    <VAT VatCode="A" VatRate="0" />  
   </BasicFields>
   <Price>  
    <CurrentWSP>8.88</CurrentWSP>
    <CurrentRSP>2.22</CurrentRSP>  
   </Price>
   <Barcode>  
    <Eancode>5000147032923</Eancode>  
   </Barcode>
 </Product>

</ProdExtract>

Reading the file and saving it to the database table

var entities = new List<ProductViewModel>();
        PostgreSQLCopyHelper<ProductViewModel> insert = null;

        NpgsqlConnection connection = new NpgsqlConnection("Host=192.168.0.52;Database=bolo;Username=western;Password=western");
        connection.Open(); /*OPEN DATABASE CONNECTION*/            

        ProductViewModel p;            

        try
        {
            if (ModelState.IsValid && upload != null)
            {
                //uploaded file
                Stream stream = upload.InputStream;

                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(stream);
                XmlElement root = xDoc.DocumentElement;
                XmlNodeList nodes = root.SelectNodes("Product");

                foreach (XmlNode node in nodes)                    
                {
                    //while((p = node.InnerText) != null)
                    {
                        insert = new PostgreSQLCopyHelper<ProductViewModel>("public", "q_product");
                        p = new ProductViewModel();
                        p.q_guid = Guid.NewGuid();
                        p.q_description = node.SelectSingleNode("ProductID/LongDescription").InnerText;
                        p.q_barcode = node.SelectSingleNode("Barcode / Eancode").InnerText;
                        p.q_casesize = Convert.ToDecimal(node.SelectSingleNode("BasicFields/Units").InnerText);
                        p.q_sellprice = Convert.ToDecimal(node.SelectSingleNode("Price/CurrentRSP").InnerText);
                        p.q_casecost = Convert.ToDecimal(node.SelectSingleNode("Price/CurrentWSP").InnerText);
                        entities.Add(p);
                    }                        
                }

                try
                {
                   insert.SaveAll(connection, entities);
                    int lineCount = entities.Count();
                    TempData["SuccessMessage"] = lineCount + " Records Inserted!";
                    connection.Close(); /*CLOSE CONNECTION*/
                }
                catch (DataException error)
                {
                    TempData["ErrorMessage"] = error.Message;
                }

                return RedirectToAction("Index");
            }                
        }
        catch(DataException error)
        {

            ModelState.AddModelError("", error.Message);
        }

        return RedirectToAction("Index");

UPDATE

Mapping this way, only gets the first row saved into the table. Testing with a file that only has 3 products, and the first row will get saved 3 times in the table.

insert = insert ?? new PostgreSQLCopyHelper<ProductViewModel>("public", "q_product")
   .MapUUID("q_guid", x => Guid.NewGuid())
   .MapText("q_description", x => node.SelectSingleNode("ProductID/LongDescription").InnerText)
   .MapText("q_barcode", x => node.SelectSingleNode("Barcode/Eancode").InnerText)
  etc........
                        ;
  entities.Add(p);

Mapping this way gets all the approppiate records into entities.Add(p) but is crashing out on the line insert.SaveAll(connection, entities); with error Npgsql.PostgresException: 42601: syntax error at or near ")"... because insert has no columns to insert data into at time of saving.

insert = new PostgreSQLCopyHelper<ProductViewModel>("public", "q_product");
      p = new ProductViewModel();
      p.q_guid = Guid.NewGuid();
      p.q_description = node.SelectSingleNode("ProductID/LongDescription").InnerText;
      p.q_barcode = node.SelectSingleNode("Barcode / Eancode").InnerText;
      p.q_casesize = Convert.ToDecimal(node.SelectSingleNode("BasicFields/Units").InnerText);
      p.q_sellprice = Convert.ToDecimal(node.SelectSingleNode("Price/CurrentRSP").InnerText);
      p.q_casecost = Convert.ToDecimal(node.SelectSingleNode("Price/CurrentWSP").InnerText);
      entities.Add(p);

Update Solution

Removing the line insert = new PostgreSQLCopyHelper<ProductViewModel>("public", "q_product");

and using the following, works for my current needs. I am aware there are probably faster methods than this solution, but this works for my current needs at the moment.

NpgsqlCommand cmd = new NpgsqlCommand
                            ("INSERT INTO q_product (q_guid, q_description, q_barcode, q_casesize, q_sellprice, q_casecost, q_import_vatcode)" +
                            "VALUES (@pk, @des, @bcode, @csize, @sprice, @ccost, @vcode )",
                            con);

                        cmd.Parameters.AddWithValue("@pk", p.q_guid);
                        cmd.Parameters.AddWithValue("@des", p.q_description);
                        cmd.Parameters.AddWithValue("@bcode", p.q_barcode);
                        cmd.Parameters.AddWithValue("@csize", p.q_casesize);
                        cmd.Parameters.AddWithValue("@sprice", p.q_sellprice);
                        cmd.Parameters.AddWithValue("@ccost", p.q_casecost);
                        cmd.Parameters.AddWithValue("@vcode", p.q_import_vatcode);
                        cmd.ExecuteNonQuery();

Upvotes: 0

Views: 523

Answers (1)

mjwills
mjwills

Reputation: 23975

Your issue is that you are repeatedly adding the same element:

entities.Add(p);

On each iteration of the loop you need to create a new object and set properties on it:

p = new WhateverYourTypeIs();
p.Property1 = node.Something;
p.Property2 = node.SomethingElse;
entities.Add(p);

etc.

Upvotes: 1

Related Questions