原文:使用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时间格式的折腾经历的更多相关文章

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

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

  2. SQL Server 2008 批量插入数据时报错

    前几天在SQL Server 2008同步产品数据时,总是提示二进制文本被截断的错误,但是经过检查发现数据都符合格式要求. 百思不得其解,单独插入一条条数据则可以插入,但是批量导入则报错. 批量导入代 ...

  3. SQL Server中批量替换数据

    SQL Server数据库中批量替换数据的方法 SQL Server数据库操作中,我们可能会根据某写需要去批量替换数据,那么如何批量修改替换数据呢?本文我们就介绍这一部分内容,接下来就让我们一起来了解 ...

  4. SQL Server TVPs 批量插入数据

    在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题.下面介绍SQL Server支持的两种批量 ...

  5. 从TXT文本文档向Sql Server中批量导入数据

    下面我们通过以下的简单的SQL语句即可实现数据的批量导入,代码如下: Bulk insert id From 'G:\文档\test.txt' With ( fieldterminator=',', ...

  6. 在Sql Server 2005中将主子表关系的XML文档转换成主子表“Join”形式的表

    本文转载:http://www.cnblogs.com/Ricky81317/archive/2010/01/06/1640434.html 最近这段时间在Sql Server 2005下做了很多根据 ...

  7. SQL Server 2005 盛宴系列 经典教程

    SQL Server 2005 盛宴系列 经典教程  [复制链接]   发表于 2007-3-27 14:08 | 来自 51CTO网页 [只看他] 楼主     TECHNET  SQL serve ...

  8. 转载--SQL Server 2005的XQuery介绍

    原文地址: http://bbs.51cto.com/thread-458009-1-1.html   引用: 摘要 本文介绍了SQL Server 2005能够支持的XQuery的各方面特性如FLW ...

  9. SQL Server 2005的XML数据修改语言(XML DML)

    转:http://www.microsoft.com/china/msdn/library/data/sqlserver/XMLDML.mspx?mfr=true 作为对XQuery语言的扩展,XML ...

随机推荐

  1. 第三章 AOP 基于@AspectJ的AOP

    在前面,我们分别使用Pointcut.Advice.Advisor接口来描述切点.增强.切面.而现在我们使用@AdpectJ注解来描述. 在下面的例子中,我们是使用Spring自动扫描和管理Bean. ...

  2. php判断变量是否存在

    isset— 检测变量是否设置, isset() 只能用于变量,因为传递任何其它参数都将造成解析错误.若想检测常量是否已设置,可使用 defined() 函数. 如果已经使用 unset() 释放了一 ...

  3. UVA 10831 - Gerg&#39;s Cake(数论)

    UVA 10831 - Gerg's Cake 题目链接 题意:说白了就是给定a, p.问有没有存在x^2 % p = a的解 思路:求出勒让德标记.推断假设大于等于0,就是有解,小于0无解 代码: ...

  4. 解决SMARTFORMS 中table 控件单行跨页的问题

    在CX项目中,MM模块做了大量的的单据打印的工作,一个问题困扰了我好久,一直不能解决.当物料描述很长时,table控件在单元格中能自动换行,这样就有可能在换页处出现一行记录的一部分打在上一页,一部分记 ...

  5. Lua语言在Wireshark中使用(转)

    1.       检查Wireshark的版本是否支持Lua 打开Wireshark,点击“HelpàAbout Wireshark”菜单,查看弹出的对话框,如果有“with Lua 5.1”表示支持 ...

  6. 【Nginx】开发一个简单的HTTP模块

    首先来分析一下HTTP模块是怎样介入Nginx的. 当master进程fork出若干个workr子进程后,每一个worker子进程都会在自己的for死循环中不断调用事件模块: for ( ;; ) { ...

  7. COM模块三---根的形成和注册代理server(Building and Registering a Proxy DLL)

    Prerequisite:C++ 程序员,熟windows计划,熟Win32 Dll,了解windows注册表. 笔者:割者 上一篇文章中,我们定义了COM接口.通过编译生成了四个文件,本文使用这四个 ...

  8. 主从集群搭建及容灾部署redis

    redis主从集群搭建及容灾部署(哨兵sentinel) Redis也用了一段时间了,记录一下相关集群搭建及配置详解,方便后续使用查阅. 提纲 l  Redis安装 l  整体架构 l  Redis主 ...

  9. linux根据该文件夹的读取权限和权限运行差异

    假设你linux下使用ls.细心的你会发现居然夹有权限运行.例如: drwxrwxr-x 11 cl cl 4096  9 25 14:22 ./ drwxr-xr-x 49 cl cl 4096 1 ...

  10. C++ 习题 输出日期时间--友元函数

    Description 设计一个日期类和时间类,编写display函数用于显示日期和时间.要求:display函数作为类外的普通函数,分别在Time和Date类中将display声明为友元函数.在主函 ...