简体   繁体   English

将来自 XML 的数据存储在关系数据库 SQL 中

[英]Store data from XML in relational SQL database

I need to store data from an XML file into SQL database with 2 tables.我需要将 XML 文件中的数据存储到具有 2 个表的 SQL 数据库中。 The XML file looks like this (the full file has more Document nodes): XML 文件如下所示(完整文件具有更多Document节点):

<Documents>
    <Document>
        <Number>110</Number>
        <Date>2020-10-23</Date>
        <TotalPrice>3800</TotalPrice>
        <Items>
            <Item>
                <SKU>001234</SKU>
                <Name>FirstItem</Name>
                <Quantity>10</Quantity>
                <Price>1550</Price>
            </Item>
            <Item>
                <SKU>001235</SKU>
                <Name>SecondItem</Name>
                <Quantity>8</Quantity>
                <Price>1200</Price>
            </Item>
            <Item>
                <SKU>001236</SKU>
                <Name>ThirdItem</Name>
                <Quantity>21</Quantity>
                <Price>1050</Price>
            </Item>
        </Items>
    </Document>
</Documents>

The SQL database has 2 tables. SQL 数据库有 2 个表。 One for Documents, and the other one for Items.一个用于文档,另一个用于项目。

create table Document(
DocumentId int identity(1,1) not null primary key,
Number int not null,
[Date] date not null,
TotalPrice money not null
);

create table Item(
ItemId int identity(1,1) not null primary key,
SKU int not null,
[Name] nvarchar(30) not null,
Quantity int not null,
Price money not null,
DocumentId int not null foreign key references Document(DocumentId)
);

Previously, I've been storing only simple XML files into SQL databases with only one table.以前,我只将简单的 XML 个文件存储到只有一个表的 SQL 个数据库中。 The way that I was doing it (let's say that we just have Document table, and we can ignore Items):我这样做的方式(假设我们只有文档表,我们可以忽略项目):

DocumentMetadata.cs文档元数据.cs

    [Serializable]
    [XmlRoot("Document")]
    public class DocumentMetadata
    {
        [XmlElement("Number")]
        public int Number { get; set; }

        [XmlElement("Date")]
        public DateTime Date { get; set; }

        [XmlElement("TotalPrice")]
        public int TotalPrice { get; set; }
    }

    [MetadataType(typeof(DocumentMetadata))]
    public partial class Document
    {

    }

Example.cs例子.cs

XDocument xDoc = XDocument.Load(XmlFile);

List<Document> documentList = xDoc.Descendants("Document").Select(document => new Document
{
    Number = Convert.ToInt32(document.Element("Number").Value),
    Date = Convert.ToDateTime(document.Element("Date").Value),
    TotalPrice = Convert.ToInt32(document.Element("TotalPrice").Value),
}).ToList();


using (DocumentsEntities entity = new DocumentsEntities())
{
    foreach (var doc in documentList)
    {
        var dbDoc = entity.Documents.Where(x => x.Number.Equals(d.Number)).FirstOrDefault();

        if (dbDoc != null)
        {
            dbDoc.Number = doc.Number;
            dbDoc.Date = doc.Date;
            dbDoc.TotalPrice = doc.TotalPrice;
        }
        else
        {
            entity.Documents.Add(doc);
        }
    }
        entity.SaveChanges();
    }

Since I have a bit more complex XML now to work with, and 2 related database tables, my head is all over the place.由于我现在要使用更复杂的 XML 和 2 个相关的数据库表,所以我的脑袋到处都是。 What would be the best approach in this situation?在这种情况下最好的方法是什么? Could you point me in the right direction?你能指出我正确的方向吗? Thanks in advance.提前致谢。

I don't see the point in shredding the XML using complex C# code.我看不出使用复杂的 C# 代码粉碎 XML 有什么意义。 SQL Server can do this pretty neatly SQL 服务器可以很巧妙地做到这一点

INSERT Document
  (Number, [Date], TotalPrice)
SELECT
  x.doc.value('(Number/text())[1]','int'),
  x.doc.value('(Date/text())[1]','date'),
  x.doc.value('(TotalPrice/text())[1]','money')
FROM @xml.nodes('Documents/Document') x(doc);

INSERT Item
  (SKU, [Name], Quantity, Price, DocumentId)
SELECT
  x2.item.value('(SKU/text())[1]','int'),
  x2.item.value('(Name/text())[1]','nvarchar(30)'),
  x2.item.value('(Quantity/text())[1]','int')
  x2.item.value('(Price/text())[1]','money'),
FROM @xml.nodes('Documents/Document') x(doc)
JOIN Document d ON d.Number = x.doc.value('(Number/text())[1]','int')
CROSS APPLY x.doc.nodes('Item') x2(item);

Your C# code could be something like您的 C# 代码可能类似于

const string sql = @"
THE ABOVE SQL
";

using (DocumentsEntities entity = new DocumentsEntities())
{
    entity.ExecuteSqlCommand(sql, new SqlParameter("@x", xDoc));
}

If you need the IDENTITY ID numbers you can use an OUTPUT clause with entity.FromSqlQuery如果您需要IDENTITY ID 号码,您可以将OUTPUT子句与entity.FromSqlQuery一起使用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM