读取xml通过deserialize和linq to sql快速更新数据表

本文目的

  本文旨在提供通过读取xml文件快速更新数据表的方法,为本人在项目应用中的实践所的,所涉及到的内容都比较基础,还请各位博友拍砖。

  序幕

  Linq to sql给我们的orm影射带来了极大的便利,实体类写很少的代码就可以完成数据库表的增删查改,也使我们能够更加专注于业务逻辑;而Xml的应用也是相当广泛,如今的SOA很大程度上是利用了Xml格式的SOAP消息来进行交互。有的时候我们会碰到需要读取xml保存到数据库的情况,在没有Linq的时候,可能我们会通过XmlSerializer的Deserialize方法来反序列化Xml生成相对应的net class,然后操作net class插入数据库,如果不采用orm的话,代码量和利用XmlDocument直接操作Xml更新数据库没有什么差别,那么现在有了Linq to sql,反序列化的net class和Linq to sql的Entity可以优雅的结合到一起,看看减轻了我们多少的工作量?

  XmlSerializer.Deserialize

  首先我们看一下XmlSerializer.Deserialize的例子

  使用的xml文件

  norm.xml

  <Norm>
  <TradeName>纺织</TradeName>
  <SubmittedDate>2008-04-28</SubmittedDate>
  <Index>
    <IndexName>信息化投入比</IndexName>
    <IndexNum>500</IndexNum>
  </Index>
  <Index>
    <IndexName>环保改善率</IndexName>
    <IndexNum>300</IndexNum>
  </Index>
</Norm>

  对应的net class

  norm.cs

  public class Norm
    {
        private int normID;
        private string tradeName;
        private DateTime submittedDate;
        private Index[] indexs;
        [XmlIgnore]
        public int NormID
        {
            get{return normID;}
            set{normID=value;}
        }
        [XmlElement("TradeName")]
        public string TradeName
        {
            get{return tradeName;}
            set{tradeName=value;}
        }
        [XmlElement("SubmittedDate")]
        public DateTime SubmittedDate
        {
            get{return submittedDate;}
            set{submittedDate=value;}
        }
        [XmlElement("Index")]
        public Index[] Indexs
        {
            get{return indexs;}
            set{indexs=value;}
        }
       
    }
    public class Index
    {
        private int indexID;
        private string indexName;
        private float indexNum;
        private int normID;
        [XmlIgnore]
        public int IndexID
        {
            get{return indexID;}
            set{indexID=value;}
        }
        [XmlElement("IndexName")]
        public string IndexName
        {
            get{return indexName;}
            set{indexName=value;}
        }
        [XmlElement("IndexNum")]
        public float IndexNum
        {
            get{return indexNum;}
            set{indexNum=value;}
        }
        [XmlIgnore]
        public int NormID
        {
            get{return normID;}
            set{normID=value;}
        }
    }

  注意Index[] Indexs的Attribute设置为XmlElement("Index"),CLR可以帮助我们将多个Index Element反序列化为Indexs数组。

  Program.cs 

class Program
    {
        static void Main(string[] args)
        {
            XmlDocument responseXmlDocument = new XmlDocument();
            responseXmlDocument.Load("C://a.xml");

            XmlNode xn = responseXmlDocument.DocumentElement.ParentNode;

            XmlSerializer serializer = new XmlSerializer(typeof(Norm));
            Norm norm = serializer.Deserialize(new XmlNodeReader(xn)) as Norm;
            Console.WriteLine("Succeed!");
        }
    }

  

  反序列化结合Linq to sql使用

  首先给出表结构

 

CREATE TABLE [dbo].[Norm] (
    [NormID] [int] IDENTITY (1, 1) NOT NULL ,
    [TradeName] [nvarchar] (30) NOT NULL ,
    [SubmittedDate] [datetime] NOT NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[Index] (
    [IndexID] [int] IDENTITY (1, 1) NOT NULL ,
    [IndexName] [nvarchar] (30) NOT NULL ,
    [IndexNum] [float] NOT NULL ,
    [NormID] [int] NOT NULL
) ON [PRIMARY]

ALTER TABLE [dbo].[Index] ADD
    CONSTRAINT [FK_Index_Norm] FOREIGN KEY
    (
        [NormID]
    ) REFERENCES [dbo].[Norm] (
        [NormID]
    )

  norm和index为1对多的关系,norm的主键为normid(int not null identity),index的主键为indexid(int not null identity),normid为index表的外键

  下面给出解决方案,最简单的方法就是修改linq to sql的设计器生成的代码

  

  只需要在相应的Property上加上XmlElementAttribute就可以,由于代码太长,这里我只列出自己建立的linq to sql实体和DataContext

 

public class NormDataContext : DataContext
    {

        public Table<Norm> Norms;

        public NormDataContext(IDbConnection connection) : base(connection) { }

        public NormDataContext(string connection) : base(connection) { }

    }
    [Table(Name = "dbo.Norm")]
    public class Norm
    {
        private int _NormID;

        private string _TradeName;

        private System.DateTime _SubmittedDate;

        private EntitySet<Index> _Index;
        public Norm()
        {
            this._Index = new EntitySet<Index>(new Action<Index>(this.attach_Index), new Action<Index>(this.detach_Index));
           
        }
        [XmlIgnore]
        [Column(Storage = "_NormID", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
        public int NormID
        {
            get { return _NormID; }
            set { _NormID = value; }
        }
        [XmlElement("TradeName")]
        [Column(Storage = "_TradeName", DbType = "NVarChar(30) NOT NULL", CanBeNull = false)]
        public string TradeName
        {
            get { return _TradeName; }
            set { _TradeName = value; }
        }
        [XmlElement("SubmittedDate")]
        [Column(Storage = "_SubmittedDate", DbType = "DateTime NOT NULL")]
        public System.DateTime SubmittedDate
        {
            get { return _SubmittedDate; }
            set { _SubmittedDate = value; }
        }
        [XmlElement("Index")]
        [Association(Name = "Norm_Index", Storage = "_Index", OtherKey = "NormID")]
        public EntitySet<Index> Index
        {
            get { return _Index; }
            set { _Index = value; }
        }
        private void attach_Index(Index entity)
        {
            entity.Norm = this;
        }

        private void detach_Index(Index entity)
        {
            entity.Norm = null;
        }

   
    }

    [Table(Name = "dbo.[Index]")]
    public class Index
    {
        private int _IndexID;

        private string _IndexName;

        private double _IndexNum;

        private int _NormID;

        private EntityRef<Norm> _Norm;

        public Index()
        {
            this._Norm = default(EntityRef<Norm>);
        }
        [XmlIgnore]
        [Column(Storage = "_IndexID", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
        public int IndexID
        {
            get{return _IndexID;}
            set{_IndexID=value;}
        }
        [XmlElement("IndexName")]
        [Column(Storage = "_IndexName", DbType = "NVarChar(30) NOT NULL", CanBeNull = false)]
        public string IndexName
        {
            get{return _IndexName;}
            set{_IndexName=value;}
        }
        [XmlElement("IndexNum")]
        [Column(Storage = "_IndexNum", DbType = "Float NOT NULL")]
        public double IndexNum
        {
            get{return _IndexNum;}
            set{_IndexNum=value;}
        }
        [XmlIgnore]
        [Column(Storage = "_NormID", DbType = "Int NOT NULL")]
        public int NormID
        {
            get{return _NormID;}
            set{_NormID=value;}
        }
        [Association(Name = "Norm_Index", Storage = "_Norm", ThisKey = "NormID", IsForeignKey = true)]
        public Norm Norm
        {
            get{return _Norm.Entity;}
            set{_Norm.Entity=value;}
        }
    }

  注意norm和index的构造函数的内容一定要有,否则会报NSERT 语句与 COLUMN FOREIGN KEY 约束冲突,另外把相应的需要反序列化的Property标记XmlElement,不需要的如NormID,IndexID标记XmlIgnore(这个对应数据表的自增长列,利用linq to sql的DataContext完成剩下的提交工作),看代码

   Norm norm = serializer.Deserialize(new XmlNodeReader(xn)) as Norm;        
                NormDataContext ndc = new NormDataContext("server=server;database=BlackJack;uid=sa;pwd=");
                StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory+"/log1.txt", true); // Append
                ndc.Log = sw;
                ndc.Norms.InsertOnSubmit(norm);
                ndc.SubmitChanges();

  后记

  在完成这段代码前,我一直在网上找类似的解决方案,但比较少,也可能是我孤陋寡闻,是不是linq系列将来会考虑支持这种方式感觉微软在xml序列化/反序列化做的很好,提供了很多的Attribute,使我们不用编写代码就能够完成工作,这里我也是抛砖引玉,还望园子里的朋友不吝赐教,另外我也把我的问题提出来,我在反序列化net class中利用XmlRootAttribute加入了自己的namespace,可是总是无法正确的反序列化,不知道怎么回事?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值