使用PostgreSQLCopyHelper对记录进行XML批量导入 - Npgsql.PostgresException:42601

时间:2017-07-03 19:52:22

标签: xml postgresql import

在将具有两个记录文件的XML中的记录导入数据库表时,我遇到的问题是第一条记录被插入两次而第二条记录没有保存到表中。

这是包含两个记录/产品的XML文件

<?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>

读取文件并将其保存到数据库表

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");

更新

以这种方式映射,只获取保存在表中的第一行。使用只有3个产品的文件进行测试,第一行将在表格中保存3次。

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);

以这种方式进行映射会将所有适当的记录转换为entities.Add(p),但会在行insert.SaveAll(connection, entities);上崩溃并出现错误Npgsql.PostgresException: 42601: syntax error at or near ")" ...因为insert没有列可以在时间插入数据保存。

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);

更新解决方案

删除该行 insert = new PostgreSQLCopyHelper<ProductViewModel>("public", "q_product");

并使用以下内容,可满足我当前的需求。我知道有可能比这个解决方案更快的方法,但这适用于我目前的需求。

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();

1 个答案:

答案 0 :(得分:1)

您的问题是您反复添加相同的元素:

entities.Add(p);

在循环的每次迭代中,您需要创建一个新对象并在其上设置属性:

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