使用XML向SQL Server 2005批量写入数据——一次

系统 2328 0
原文: 使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历

常常遇到需要向SQL Server插入批量数据,然后在存储过程中对这些数据进行进一步处理的情况。存储过程并没有数组、列表之类的参数类型,使用XML类型可妥善解决这个问题。

不过,SQL Server2005对标准xml的支持不足,很多地方需要特别处理。举一个例子说明一下。

这个场景是往存储过程里传递一个xml序列化了的List<Model>。

1.Model的代码如下,这是一个实体类

      
        public
      
      
        class
      
      
         Model

{

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         UIN

    
      
      
        ///
      
      
        </summary>
      
      

    [XmlElement(
      
        "
      
      
        UIN
      
      
        "
      
      
        )]

    
      
      
        public
      
      
        long
      
       UIN { 
      
        get
      
      ; 
      
        set
      
      
        ; }

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         昵称

    
      
      
        ///
      
      
        </summary>
      
      

    [XmlElement(
      
        "
      
      
        Name
      
      
        "
      
      
        )]

    
      
      
        public
      
      
        string
      
       Name { 
      
        get
      
      ; 
      
        set
      
      
        ; }

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         头像

    
      
      
        ///
      
      
        </summary>
      
      

    [XmlElement(
      
        "
      
      
        Img
      
      
        "
      
      
        )]

    
      
      
        public
      
      
        string
      
       Img { 
      
        get
      
      ; 
      
        set
      
      
        ; }

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         访问时间

    
      
      
        ///
      
      
        </summary>
      
      

    [XmlElement(
      
        "
      
      
        VisitTime
      
      
        "
      
      
        )]

    
      
      
        public
      
       DateTime VisitTime { 
      
        get
      
      ; 
      
        set
      
      
        ; }

}
      
    

然后我们需要将这个List<Model>序列化成一个xml的字符串。但是SQL Server对xml的命名空间识别是有问题的,.net默认的序列化会出现xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd= http://www.w3.org/2001/XMLSchema

有网友给出了一个完美序列化Sql Server2005支持的xml的类(参考 http://www.cnblogs.com/prime/archive/2012/10/11/SQLXML.html ):

 

      
        public
      
      
        static
      
      
        class
      
      
         DbXml

{

    
      
      
        private
      
      
        static
      
      
        readonly
      
       XmlSerializerNamespaces Namespaces = 
      
        new
      
      
         XmlSerializerNamespaces();



    
      
      
        static
      
      
         DbXml()

    {

        
      
      
        //
      
      
        去掉 xmlns:xsi="
      
      
        http://www.w3.org/2001/XMLSchema-instance
      
      
        " xmlns:xsd="
      
      
        http://www.w3.org/2001/XMLSchema
      
      
        "
      
      

        Namespaces.Add(
      
        string
      
      .Empty, 
      
        string
      
      
        .Empty);

    }

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         把一个对象序列化成一个Xml字符串

    
      
      
        ///
      
      
        </summary>
      
      
        ///
      
      
        <typeparam name="T"></typeparam>
      
      
        ///
      
      
        <param name="obj"></param>
      
      
        ///
      
      
        <returns></returns>
      
      
        public
      
      
        static
      
      
        string
      
       SerializeXml<T>
      
        (T obj)

    {

        XmlSerializer serializer 
      
      = 
      
        new
      
       XmlSerializer(
      
        typeof
      
      
        (T));

        
      
      
        using
      
       (MemoryStream stream = 
      
        new
      
      
         MemoryStream())

        {

            serializer.Serialize(stream, obj, Namespaces);

            
      
      
        return
      
      
         Encoding.UTF8.GetString(stream.ToArray());

        }

    }



    
      
      
        public
      
      
        static
      
       T DeserializeXml<T>(
      
        string
      
      
         obj)

    {

        XmlSerializer serializer 
      
      = 
      
        new
      
       XmlSerializer(
      
        typeof
      
      
        (T));

        
      
      
        using
      
       (StringReader reader = 
      
        new
      
      
         StringReader(obj))

        {

            
      
      
        return
      
      
         (T)serializer.Deserialize(reader);

        }

    }

}
      
    

使用的时候只需要:string xml = DbXml.SerializeXml<List<QQVisitorXml>>(list) 即可获取序列化后的xml字符串:

      
        <?
      
      
        xml version="1.0"
      
      
        ?>
      
      
        <
      
      
        ArrayOfModel
      
      
        >
      
      
        <
      
      
        Model
      
      
        >
      
      
        <
      
      
        UIN
      
      
        >
      
      0
      
        </
      
      
        UIN
      
      
        >
      
      
        <
      
      
        Name
      
      
        >
      
      name0
      
        </
      
      
        Name
      
      
        >
      
      
        <
      
      
        Img
      
      
        >
      
      img0
      
        </
      
      
        Img
      
      
        >
      
      
        <
      
      
        VisitTime
      
      
        >
      
      2009-07-17T00:00:00-05:00
      
        </
      
      
        VisitTime
      
      
        >
      
      
        </
      
      
        Model
      
      
        >
      
      
        <
      
      
        Model
      
      
        >
      
      
        <
      
      
        UIN
      
      
        >
      
      1
      
        </
      
      
        UIN
      
      
        >
      
      
        <
      
      
        Name
      
      
        >
      
      name1
      
        </
      
      
        Name
      
      
        >
      
      
        <
      
      
        Img
      
      
        >
      
      img1
      
        </
      
      
        Img
      
      
        >
      
      
        <
      
      
        VisitTime
      
      
        >
      
      2009-07-17T00:00:00-05:00
      
        </
      
      
        VisitTime
      
      
        >
      
      
        </
      
      
        Model
      
      
        >
      
      
        <
      
      
        Model
      
      
        >
      
      
        <
      
      
        UIN
      
      
        >
      
      2
      
        </
      
      
        UIN
      
      
        >
      
      
        <
      
      
        Name
      
      
        >
      
      name2
      
        </
      
      
        Name
      
      
        >
      
      
        <
      
      
        Img
      
      
        >
      
      img2
      
        </
      
      
        Img
      
      
        >
      
      
        <
      
      
        VisitTime
      
      
        >
      
      2009-07-17T00:00:00-05:00
      
        </
      
      
        VisitTime
      
      
        >
      
      
        </
      
      
        Model
      
      
        >
      
      
        </
      
      
        ArrayOfModel
      
      
        >
      
    

2.存储过程里,读取xml到一个临时表#temp里:

      
        select
      
       c.value(
      
        '
      
      
        (UIN)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(30)
      
      
        '
      
      ) 
      
        as
      
      
         uin,

c.value(
      
      
        '
      
      
        (Name)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(50)
      
      
        '
      
      ) 
      
        as
      
      
         Name,

c.value(
      
      
        '
      
      
        (Img)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(200)
      
      
        '
      
      ) 
      
        as
      
      
         Img,

c.value(
      
      
        '
      
      
        (VisitTime)[1]
      
      
        '
      
      ,
      
        '
      
      
        datetime
      
      
        '
      
      ) 
      
        as
      
      
         VisitTime


      
      
        into
      
       #
      
        temp
      
      
        from
      
      
        @strxml
      
      .nodes(
      
        '
      
      
        //Model
      
      
        '
      
      ) T(c) 
      
        --
      
      
        @strxml是存储过程的xml参数
      
    

然后就可以对#temp按照普通表进行进一步处理。

我们试着执行这个存储过程。嗯?出错了?!

3.原来,XML的时间标准格式是”年-月-日T时:分:秒-时区” SQL Server2005不支持时区,所以它也不能支持xml的时间格式(倒是支持年-月-日T时:分:秒)。这个问题在SQL server 2008中得到改进,完整支持了xml的时间格式。但是我们数据库是2005,没办法,得想个办法解决。解决办法是把时间字转成字符串,然后截取 年-月-日T时:分:秒,最后再加上东八区的时区数,这样sql修正为:

      
        select
      
       c.value(
      
        '
      
      
        (UIN)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(30)
      
      
        '
      
      ) 
      
        as
      
      
         uin,

c.value(
      
      
        '
      
      
        (Name)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(50)
      
      
        '
      
      ) 
      
        as
      
      
         Name,

c.value(
      
      
        '
      
      
        (Img)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(200)
      
      
        '
      
      ) 
      
        as
      
      
         Img,


      
      
        dateadd
      
      (hour,
      
        8
      
      ,
      
        convert
      
      (
      
        datetime
      
      ,
      
        left
      
      (t.c.value(
      
        '
      
      
        (VisitTime)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(30)
      
      
        '
      
      ), 
      
        19
      
      ),
      
        127
      
      )) 
      
        as
      
      
         VisitTime


      
      
        into
      
       #
      
        temp
      
      
        from
      
      
        @strxml
      
      .nodes(
      
        '
      
      
        //Model
      
      
        '
      
      ) T(c) 
      
        --
      
      
        @strxml是存储过程的xml参数
      
    

本地测试,成功!

4.放到服务器上测试,执行倒是成功了,可以一查看数据,又出问题了!服务器上插入数据表的时间,和我本地测试数据库的时间,相差8个小时!本地开发环境是windows8,服务器是windows server 2008。开发环境和服务器环境有差异,导致本地获取xml带时区,服务器不带时区。

过于依赖环境,就太危险了!果断放弃时间格式,修改Model中时间为字符串:

      
        public
      
      
        class
      
      
         Model

{

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         UIN

    
      
      
        ///
      
      
        </summary>
      
      

    [XmlElement(
      
        "
      
      
        UIN
      
      
        "
      
      
        )]

    
      
      
        public
      
      
        long
      
       UIN { 
      
        get
      
      ; 
      
        set
      
      
        ; }

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         昵称

    
      
      
        ///
      
      
        </summary>
      
      

    [XmlElement(
      
        "
      
      
        Name
      
      
        "
      
      
        )]

    
      
      
        public
      
      
        string
      
       Name { 
      
        get
      
      ; 
      
        set
      
      
        ; }

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         头像

    
      
      
        ///
      
      
        </summary>
      
      

    [XmlElement(
      
        "
      
      
        Img
      
      
        "
      
      
        )]

    
      
      
        public
      
      
        string
      
       Img { 
      
        get
      
      ; 
      
        set
      
      
        ; }

    
      
      
        ///
      
      
        <summary>
      
      
        ///
      
      
         访问时间

    
      
      
        ///
      
      
        </summary>
      
      

    [XmlIgnore] 
      
        //
      
      
        xml序列化时跳过
      
      
        public
      
       DateTime VisitTime { 
      
        get
      
      ; 
      
        set
      
      
        ; }



    [XmlElement(
      
      
        "
      
      
        VisitTime
      
      
        "
      
      
        )]

    
      
      
        public
      
      
        string
      
      
         XVisitTime

    {

        
      
      
        get
      
       { 
      
        return
      
      
        this
      
      .VisitTime.ToString(
      
        "
      
      
        yyyy-MM-dd HH:mm:ss
      
      
        "
      
      
        ); }

        
      
      
        set
      
       { 
      
        this
      
      .VisitTime =
      
         DateTime.Parse(value); }

    }

}
      
    

在存储过程中把这个时间字符串转换成时间:

      
        select
      
       c.value(
      
        '
      
      
        (UIN)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(30)
      
      
        '
      
      ) 
      
        as
      
      
         uin,

c.value(
      
      
        '
      
      
        (Name)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(50)
      
      
        '
      
      ) 
      
        as
      
      
         Name,

c.value(
      
      
        '
      
      
        (Img)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(200)
      
      
        '
      
      ) 
      
        as
      
      
         Img,


      
      
        convert
      
      (
      
        datetime
      
      ,c.value(
      
        '
      
      
        (VisitTime)[1]
      
      
        '
      
      ,
      
        '
      
      
        varchar(30)
      
      
        '
      
      )) 
      
        as
      
      
         VisitTime


      
      
        into
      
       #
      
        temp
      
      
        from
      
      
        @strxml
      
      .nodes(
      
        '
      
      
        //Model
      
      
        '
      
      ) T(c)
    

Ok。所有问题都解决了,畅快。

使用XML向SQL Server 2005批量写入数据——一次有关XML时间格式的折腾经历


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论