[转载]在.NET使用JSON作为数据交换格式

mikel阅读(1563)

[转载]在.NET使用JSON作为数据交换格式_知识库_博客园.

我们知道在.NET中我们有多种对象序列化的方式,如XML方式序列化、Binary序列化,其中XML序列化是一种比较通用的在各语言之间传递数据的方式。除了这两种序列化方式之外,在.NET中还可以使用JSON序列化。
JSON(JavaScript Object Notation)是一种轻量级轻量级的数据交换格式,并且它独立于编程语言,与XML序列化相比,JSON序列化后产生的数据一般要比XML序列化后数 据体积小,所以在Facebook等知名网站中都采用了JSON作为数据交换方式。在.NET中有三种常用的JSON序列化的类,分别是   System.Web.Script.Serialization.JavaScriptSerializer类、 System.Runtime.Serialization.Json.DataContractJsonSerializer类和 Newtonsoft.Json.JsonConvert类。
为了便于下面的演示,下面提供一个类的代码:

[DataContract]
publicclass User
{
///<summary>
/// 编号
///</summary>
[DataMember]
publicint UserId { get; set; }
///<summary>
/// 用户名
///</summary>
[DataMember]
publicstring UserName { get; set; }
///<summary>
/// 创建时间
///</summary>
[DataMember]
[JsonConverter(
typeof(IsoDateTimeConverter))]
public DateTime CreateDate { get; set; }
///<summary>
/// 生日
///</summary>
[DataMember]
[JsonConverter(
typeof(JavaScriptDateTimeConverter))]
public DateTime Birthday { get; set; }
///<summary>
/// 相关URL
///</summary>
[DataMember]
public List<string> Urls { get; set; }
///<summary>
/// 薪水
///</summary>
//[ScriptIgnore]//使用JavaScriptSerializer序列化时不序列化此字段
//[IgnoreDataMember]//使用DataContractJsonSerializer序列化时不序列化此字段
//[JsonIgnore]//使用JsonConvert序列化时不序列化此字段
publicint Salary { get; set; }
///<summary>
/// 权利级别
///</summary>
[DataMember]
public Priority Priority { get; set; }

public User()
{
Urls
=new List<string>();
}
}
///<summary>
/// 权利级别
///</summary>
publicenum Priority:byte
{
Lowest
=0x1,
BelowNormal
=0x2,
Normal
=0x4,
AboveNormal
=0x8,
Highest
=0x16
}

使用System.Web.Script.Serialization.JavaScriptSerializer类
System.Web.Script.Serialization.JavaScriptSerializer类是.NET类库中自带的一种JSON序 列化实现,在.NET Framework3.5及以后版本中可以使用这个类,这个类位于System.Web.Extensions.dll中,使用这个类是必须添加对这个 dll的引用。
下面的代码是使用JavaScriptSerializer进行序列化和反序列化的例子:

publicstaticvoid JavaScriptSerializerDemo()
{
User user
=new User { UserId =1, UserName =李刚, CreateDate = DateTime.Now.AddYears(30),Birthday=DateTime.Now.AddYears(50), Priority = Priority.Highest, Salary =500000 };
//JavaScriptSerializer类在System.Web.Extensions.dll中,注意添加这个引用
JavaScriptSerializer serializer =new JavaScriptSerializer();
//JSON序列化
string result=serializer.Serialize(user);
Console.WriteLine(
使用JavaScriptSerializer序列化后的结果:{0},长度:{1}, result, result.Length);
//JSON反序列化
user = serializer.Deserialize<User>(result);
Console.WriteLine(
使用JavaScriptSerializer反序列化后的结果:UserId:{0},UserName: {1},CreateDate:{2},Priority:{3}, user.UserId, user.UserName, user.CreateDate, user.Priority);

}

说明:如果不想序列化某个字段,可以在字段前面加[JsonIgnore]标记。
使用System.Runtime.Serialization.Json.DataContractJsonSerializer类
System.Runtime.Serialization.Json.DataContractJsonSerializer类位于 System.ServiceModel.Web.dll中,使用这个类时除了需要添加对System.ServiceModel.Web.dll的引用 之外,还需要添加System.Runtime.Serialization.dll的引用,注意这个类也是在.NET Framework3.5及以后版本中可以使用。
下面是使用DataContractJsonSerializer类的例子:

publicstaticvoid DataContractJsonSerializerDemo()
{
User user
=new User { UserId =1, UserName =李刚, CreateDate = DateTime.Now.AddYears(30), Birthday = DateTime.Now.AddYears(50), Priority = Priority.AboveNormal, Salary =50000 };
string result =string.Empty;
//DataContractJsonSerializer类在System.ServiceModel.Web.dll中,注意添加这个引用
DataContractJsonSerializer serializer =new DataContractJsonSerializer(typeof(User));

using (MemoryStream stream =new MemoryStream())
{
//JSON序列化
serializer.WriteObject(stream, user);
result
= Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(
使用DataContractJsonSerializer序列化后的结果:{0},长度:{1}, result, result.Length);
}

//JSON反序列化
byte[] buffer = Encoding.UTF8.GetBytes(result);
using (MemoryStream stream =new MemoryStream(buffer))
{
user
= serializer.ReadObject(stream) as User;
Console.WriteLine(
使用DataContractJsonSerializer反序列化后的结果:UserId: {0},UserName:{1},CreateDate:{2},Priority:{3}, user.UserId, user.UserName, user.CreateDate, user.Priority);
}
}

注意:要使用DataContractJsonSerializer类进行序列化和反序列化,必须给类加上[DataContract]属性, 对要序列化的字段加上[DataMember]属性,如果不想序列化某个字段或者属性,可以加上[IgnoreDataMember]属性。
使用Newtonsoft.Json.JsonConvert类
Newtonsoft.Json.JsonConvert类是非微软提供的一个JSON序列化和反序列的开源免费的类库(下载网址是:http://www.codeplex.com/json/), 它提供了更灵活的序列化和反序列化控制,并且如果你的开发环境使用的是.NET Framework3.5及以后版本的话,你就可以使用Linq to JSON,这样一来面对一大段的数据不必一一解析,你可以使用Linq to JSON解析出你关心的那部分即可,非常方便。
下面是使用Newtonsoft.Json.JsonConvert类的例子:

publicstaticvoid JsonConvertDemo()
{
User user
=new User { UserId =1, UserName =李刚, CreateDate = DateTime.Now.AddYears(30), Birthday = DateTime.Now.AddYears(50), Priority = Priority.BelowNormal, Salary =5000 };
//JsonConvert类在Newtonsoft.Json.Net35.dll中,注意到http://www.codeplex.com/json/下载这个dll并添加这个引用
//JSON序列化
string result = JsonConvert.SerializeObject(user);
Console.WriteLine(
使用JsonConvert序列化后的结果:{0},长度:{1}, result, result.Length);
//JSON反序列化
user = JsonConvert.DeserializeObject<User>(result);
Console.WriteLine(
使用JsonConvert反序列化后的结果:UserId:{0},UserName: {1},CreateDate:{2},Priority:{3}, user.UserId, user.UserName, user.CreateDate, user.Priority);
}

publicstaticvoid JsonConvertLinqDemo()
{
User user
=new User { UserId =1, UserName =周公, CreateDate = DateTime.Now.AddYears(8), Birthday = DateTime.Now.AddYears(32), Priority = Priority.Lowest, Salary =500, Urls =new List<string> { http://zhoufoxcn.blog.51cto.com, http://blog.csdn.net/zhoufoxcn } };
//JsonConvert类在Newtonsoft.Json.Net35.dll中,注意到http://www.codeplex.com/json/下载这个dll并添加这个引用
//JSON序列化
string result = JsonConvert.SerializeObject(user);
Console.WriteLine(
使用JsonConvert序列化后的结果:{0},长度:{1}, result, result.Length);
//使用Linq to JSON
JObject jobject = JObject.Parse(result);
JToken token
= jobject[Urls];
List
<string> urlList =new List<string>();
foreach (JToken t in token)
{
urlList.Add(t.ToString());
}
Console.Write(
使用Linq to JSON反序列化后的结果:[);
for (int i =0; i < urlList.Count 1;i++ )
{
Console.Write(urlList[i]
+,);
}
Console.WriteLine(urlList[urlList.Count
1] +]);
}

注意:如果有不需要序列化的字段,可以给该字段添加[JsonIgnore]标记。在Newtonsoft这 个类库中对于日期的序列化有多种方式,可以类的DataTime成员添加上对应的标记,这样在进行序列化和反序列化时就会按照指定的方式进行,在本例中 User类的CreateDate属性添加的属性是[JsonConverter(typeof(IsoDateTimeConverter))],而 Birthday属性添加的属性是[JsonConverter(typeof(JavaScriptDateTimeConverter))],从序列 化的结果可以看出来它们最终的表现形式并不一样。
本文中所有的示例代码如下:

1. using System;
2. using System.Collections.Generic;
3. using System.Linq;
4. using System.Text;
5. using System.Web.Script.Serialization;
6. using System.Runtime.Serialization.Json;
7. using System.IO;
8. using System.Runtime.Serialization;
9. using Newtonsoft.Json;
10. using Newtonsoft.Json.Linq;
11. using Newtonsoft.Json.Converters;
12.
13. namespace JSONDemo
14. {
15. class Program
16. {
17. staticvoid Main(string[] args)
18. {
19. JavaScriptSerializerDemo();
20. DataContractJsonSerializerDemo();
21. JsonConvertDemo();
22. JsonConvertLinqDemo();
23. Console.ReadLine();
24. }
25.
26. publicstaticvoid JavaScriptSerializerDemo()
27. {
28. User user =new User { UserId =1, UserName =李刚, CreateDate = DateTime.Now.AddYears(30),Birthday=DateTime.Now.AddYears(50), Priority = Priority.Highest, Salary =500000 };
29. //JavaScriptSerializer类在System.Web.Extensions.dll中,注意添加这个引用
30. JavaScriptSerializer serializer =new JavaScriptSerializer();
31. //JSON序列化
32. string result=serializer.Serialize(user);
33. Console.WriteLine(使用JavaScriptSerializer序列化后的结果:{0},长度:{1}, result, result.Length);
34. //JSON反序列化
35. user = serializer.Deserialize<User>(result);
36. Console.WriteLine(使用JavaScriptSerializer反序列化后的结果:UserId:{0},UserName:{1},CreateDate:{2},Priority:{3}, user.UserId, user.UserName, user.CreateDate, user.Priority);
37.
38. }
39.
40. publicstaticvoid DataContractJsonSerializerDemo()
41. {
42. User user =new User { UserId =1, UserName =李刚, CreateDate = DateTime.Now.AddYears(30), Birthday = DateTime.Now.AddYears(50), Priority = Priority.AboveNormal, Salary =50000 };
43. string result =string.Empty;
44. //DataContractJsonSerializer类在System.ServiceModel.Web.dll中,注意添加这个引用
45. DataContractJsonSerializer serializer =new DataContractJsonSerializer(typeof(User));
46.
47. using (MemoryStream stream =new MemoryStream())
48. {
49. //JSON序列化
50. serializer.WriteObject(stream, user);
51. result = Encoding.UTF8.GetString(stream.ToArray());
52. Console.WriteLine(使用DataContractJsonSerializer序列化后的结果:{0},长度:{1}, result, result.Length);
53. }
54.
55. //JSON反序列化
56. byte[] buffer = Encoding.UTF8.GetBytes(result);
57. using (MemoryStream stream =new MemoryStream(buffer))
58. {
59. user = serializer.ReadObject(stream) as User;
60. Console.WriteLine(使用DataContractJsonSerializer反序列化后的结果:UserId:{0},UserName:{1},CreateDate:{2},Priority:{3}, user.UserId, user.UserName, user.CreateDate, user.Priority);
61. }
62. }
63.
64. publicstaticvoid JsonConvertDemo()
65. {
66. User user =new User { UserId =1, UserName =李刚, CreateDate = DateTime.Now.AddYears(30), Birthday = DateTime.Now.AddYears(50), Priority = Priority.BelowNormal, Salary =5000 };
67. //JsonConvert类在Newtonsoft.Json.Net35.dll中,注意到http://www.codeplex.com/json/下载这个dll并添加这个引用
68. //JSON序列化
69. string result = JsonConvert.SerializeObject(user);
70. Console.WriteLine(使用JsonConvert序列化后的结果:{0},长度:{1}, result, result.Length);
71. //JSON反序列化
72. user = JsonConvert.DeserializeObject<User>(result);
73. Console.WriteLine(使用JsonConvert反序列化后的结果:UserId:{0},UserName:{1},CreateDate:{2},Priority:{3}, user.UserId, user.UserName, user.CreateDate, user.Priority);
74. }
75.
76. publicstaticvoid JsonConvertLinqDemo()
77. {
78. User user =new User { UserId =1, UserName =周公, CreateDate = DateTime.Now.AddYears(8), Birthday = DateTime.Now.AddYears(32), Priority = Priority.Lowest, Salary =500, Urls =new List<string> { http://zhoufoxcn.blog.51cto.com, http://blog.csdn.net/zhoufoxcn } };
79. //JsonConvert类在Newtonsoft.Json.Net35.dll中,注意到http://www.codeplex.com/json/下载这个dll并添加这个引用
80. //JSON序列化
81. string result = JsonConvert.SerializeObject(user);
82. Console.WriteLine(使用JsonConvert序列化后的结果:{0},长度:{1}, result, result.Length);
83. //使用Linq to JSON
84. JObject jobject = JObject.Parse(result);
85. JToken token = jobject[Urls];
86. List<string> urlList =new List<string>();
87. foreach (JToken t in token)
88. {
89. urlList.Add(t.ToString());
90. }
91. Console.Write(使用Linq to JSON反序列化后的结果:[);
92. for (int i =0; i < urlList.Count 1;i++ )
93. {
94. Console.Write(urlList[i] +,);
95. }
96. Console.WriteLine(urlList[urlList.Count 1] +]);
97. }
98. }
99.
100. [DataContract]
101. publicclass User
102. {
103. ///<summary>
104. /// 编号
105. ///</summary>
106. [DataMember]
107. publicint UserId { get; set; }
108. ///<summary>
109. /// 用户名
110. ///</summary>
111. [DataMember]
112. publicstring UserName { get; set; }
113. ///<summary>
114. /// 创建时间
115. ///</summary>
116. [DataMember]
117. [JsonConverter(typeof(IsoDateTimeConverter))]
118. public DateTime CreateDate { get; set; }
119. ///<summary>
120. /// 生日
121. ///</summary>
122. [DataMember]
123. [JsonConverter(typeof(JavaScriptDateTimeConverter))]
124. public DateTime Birthday { get; set; }
125. ///<summary>
126. /// 相关URL
127. ///</summary>
128. [DataMember]
129. public List<string> Urls { get; set; }
130. ///<summary>
131. /// 薪水
132. ///</summary>
133. [ScriptIgnore]//使用JavaScriptSerializer序列化时不序列化此字段
134. [IgnoreDataMember]//使用DataContractJsonSerializer序列化时不序列化此字段
135. [JsonIgnore]//使用JsonConvert序列化时不序列化此字段
136. publicint Salary { get; set; }
137. ///<summary>
138. /// 权利级别
139. ///</summary>
140. [DataMember]
141. public Priority Priority { get; set; }
142.
143. public User()
144. {
145. Urls =new List<string>();
146. }
147. }
148. ///<summary>
149. /// 权利级别
150. ///</summary>
151. publicenum Priority:byte
152. {
153. Lowest=0x1,
154. BelowNormal=0x2,
155. Normal=0x4,
156. AboveNormal=0x8,
157. Highest=0x16
158. }
159. }

程序的运行结果如下:

  1. 使用JavaScriptSerializer序列化后的结果: {“UserId”:1,”UserName”:”李刚”,”CreateDate”:”\/Date(353521211984) \/”,”Birthday”:”\/Date(-277630788015)\/”,”Urls”:[],”Priority”:22},长度:127
  2. 使用JavaScriptSerializer反序列化后的结果:UserId:1,UserName:李刚,CreateDate:1981-3-15 16:20:11,Priority:Highest
  3. 使用DataContractJsonSerializer序列化后的结果: {“Birthday”:”\/Date(-277630787953+0800)\/”,”CreateDate”:” \/Date(353521212046+0800)\/”,”Priority”:8,”Urls”: [],”UserId”:1,”UserName”:”李刚”},长度:136
  4. 使用DataContractJsonSerializer反序列化后的结果:UserId:1,UserName:李刚,CreateDate:1981-3-16 0:20:12,Priority:AboveNormal
  5. 使用JsonConvert序列化后的结果:{“UserId”:1,”UserName”:”李 刚”,”CreateDate”:”1981-03-16T00:20:12.1875+08:00″,”Birthday”:new Date(-277630787812),”Urls”: [],”Priority”:2},长度:132
  6. 使用JsonConvert反序列化后的结果:UserId:1,UserName:李刚,CreateDate:1981-3-16 0:20:12,Priority:BelowNormal
  7. 使用JsonConvert序列化后的结果:{“UserId”:1,”UserName”:”周 公”,”CreateDate”:”2003-03-16T00:20:12.40625+08:00″,”Birthday”:new Date(290362812406),”Urls”: [“http://zhoufoxcn.blog.51cto.com”,”http://blog.csdn.net /zhoufoxcn”],”Priority”:1},长度:198
  8. 使用Linq to JSON反序列化后的结果:[“http://zhoufoxcn.blog.51cto.com”,”http://blog.csdn.net/zhoufoxcn”]

总结:通过上面的例子大家可以看出Newtonsoft类库提供的JSON序列化和反序列的方式更加灵活,在实际开发中周公也一直使用Newtonsoft作为JSON序列化和反序列化的不二选择。

[转载]Json 的日期格式与.Net DateTime类型的转换

mikel阅读(1162)

[转载]Json 的日期格式与.Net DateTime类型的转换 – CoolCode – 博客园.

Json 的日期形式大概是这样:”/Date(1242357713797+0800)/” , 甭管它的格式是多么不友好(因为单从形式看根本不知道何年何月),如果这个Date只是一个属性的话, Json.Net 已经为我们处理好了。但有些很特殊的时候,需要单独把这个Date转换为.Net的DateTime格式,那么下面的代码就可以帮到你了。这个代码我已经找了很多次,终于被我发现了,免去重复造轮子的劳动。

这里跟大家分享一下, 可以保留毫秒,完全与原来结果一致。

      static void Main(string[] args)
        { 
            string [] jsonDates = {"/Date(1242357713797+0800)/" , "/Date(1242357722890+0800)/"};
            foreach (string jsonDate in jsonDates)
            {
                Console.WriteLine("Json : {0}", jsonDate);
                DateTime  dtResult =   JsonToDateTime(jsonDate);
                Console.WriteLine("DateTime: {0}", dtResult.ToString("yyyy-MM-dd hh:mm:ss ffffff"));
            } 
            Console.Read();
        }

        public static DateTime JsonToDateTime(string jsonDate)
        {
            string value = jsonDate.Substring(6, jsonDate.Length - 8);
            DateTimeKind kind = DateTimeKind.Utc;
            int index = value.IndexOf('+', 1);
            if (index == -1)
                index = value.IndexOf('-', 1);
            if (index != -1)
            {
                kind = DateTimeKind.Local;
                value = value.Substring(0, index);
            }
            long javaScriptTicks = long.Parse(value, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture);
            long InitialJavaScriptDateTicks = (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Ticks;
            DateTime utcDateTime = new DateTime((javaScriptTicks * 10000) + InitialJavaScriptDateTicks, DateTimeKind.Utc);
            DateTime dateTime;
            switch (kind)
            {
                case DateTimeKind.Unspecified:
                    dateTime = DateTime.SpecifyKind(utcDateTime.ToLocalTime(), DateTimeKind.Unspecified);
                    break;
                case DateTimeKind.Local:
                    dateTime = utcDateTime.ToLocalTime();
                    break;
                default:
                    dateTime = utcDateTime;
                    break;
            }
            return dateTime ;
        }

[转载]JSON中的Date Format转换

mikel阅读(1019)

[转载]JSON Date Format – 经世沉淀 – 博客频道 – CSDN.NET.

JSON 是一种流行地、广泛地应用于Internet的数据格式,相对于XML而言,它更小、解析更快。但可能就是由于“小”,JSON规范并没有定义如何序列化 日期。尽管在社区已经有了很多这方面的讨论,但规范仍然未形成。争论的焦点在于日期序列化是否应直接采用数字或者ISO字符串日期,还是应该采用特殊分隔 符标记的字符串日期。因为如果没有分隔符,就没法自我描述自身是一个日期类型。先搁置争议,就各AJAX库和JSON库封装的日期格式作统一讨论。

(1)直接数字型日期。

因为 JavaScript 的时间类型是从1970年1月1日以来的毫秒数。这有点类似UNIX/Linux的时间是1970年1月1日以来的秒数。当然,为支持国际化,这里的1970年1月1日的毫秒数是UTC(GMT)格林威治时间。

如:

  1. {Date: new Date(1278903921551)}

JavaScript Parser:

  1. var obj = eval(‘(‘ + “{Date: new Date(1278903921551)}” + ‘)’);
  2. var dateValue = obj[“Date”];

C# Parser:

  1. long dateNumber = 1278903921551;
  2. long beginTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
  3. DateTime dateValue = new DateTime(beginTicks + dateNumber * 10000);

(2)直接字符串日期。

字符串日期,常见的是ISO8601 标准。

如:

  1. {Date:“2010-07-12T03:05:21Z”}

JavaScript Parser:

  1. // Parse JSON string value when the string value is ISO Date Format
  2. var obj = eval(‘(‘ + ‘{Date:”2010-07-12T03:05:21Z”}’ + ‘)’);
  3. scanDate(obj, isoDateParser);
  4. var dateValue = obj[“Date”];
  5. function scanDate(obj, dateParser) {
  6. for (var key in obj) {
  7. obj[key] = dateParser(key, obj[key]);
  8. if (typeof (obj[key]) === ‘object’) {
  9. scanDate(obj[key], dateParser);
  10. }
  11. }
  12. }
  13. function isoDateParser(key, value) {
  14. if (typeof value === ‘string’) {
  15. var a = /^(/d{4})-(/d{2})-(/d{2})T(/d{2}):(/d{2}):(/d{2}(?:/./d*)?)(?:([/+-])(/d{2})/:(/d{2}))?Z?$/.exec(value);
  16. if (a) {
  17. Var utcMilliseconds = Date.UTC(+a[1], +a[2] – 1, +a[3], +a[4], +a[5], +a[6]);
  18. return new Date(utcMilliseconds);
  19. }
  20. }
  21. return value;
  22. }

C# Parser:

string dateString = “2010-07-12T03:05:21Z” DateTime dateValue = DateTime.Parse(dateString);

(3)带分隔符的数字日期。

  1. /Date(NUMBER(+/-)TZD)/
  1. “//Date(NUMBER(+/-)TZD)//”

NUMBER是1970年1月1日以来的毫秒数,TZD是4位数时区的。+和-表示东、西时区。如果没有时区,则NUMBER是UTC时间。用 /Date()/分隔。//和//是对/的转义。JSON.NET和Microsoft AJAX Library用的就是这种格式。中间的数字也是格林威治时间1970年1月1日以来的毫秒数。和第一种不同是没有采用JavaScript的日期构造 器,而是采用了一种自定义的分隔符。

如:”//Date(1278903921551)//”。

JavaScript Parser:

  1. var obj = eval(‘(‘ + “{Date: //Date(1278903921551)//}”.replace(///Date/((/d+)/)///gi, “new Date($1)”) + ‘)’);
  2. var dateValue = obj[“Date”];

C# Parser:

  1. string dateString = “///Date(1278903921551)///”;
  2. int startPos = dateString.IndexOf(“(“)+1;
  3. int endPos = dateString.LastIndexOf(“)”)-1;
  4. long dateNumber = long.Parse(dateString.Substring(startPos, endPos – startPos + 1));
  5. long beginTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
  6. DateTime dateValue = new DateTime(beginTicks + dateNumber * 10000);

如:”//Date(1278903921551+0800)//”。

JavaScript Parser:

  1. // Parse JSON string value when the string value is JSON Date Format
  2. var obj = eval(‘(‘ + ‘{Date://Date(1278903921551+0800)//}’ + ‘)’);
  3. scanDate(obj, jsonDateParser);
  4. var dateValue = obj[“Date”];
  5. function scanDate(obj, dateParser) {
  6. for (var key in obj) {
  7. obj[key] = dateParser(key, obj[key]);
  8. if (typeof (obj[key]) === ‘object ‘) {
  9. scanDate(obj[key], dateParser);
  10. }
  11. }
  12. }
  13. function jsonDateParser(key, value) {
  14. if (typeof value === ‘string’ ) {
  15. var a = (/^///Date/((/d+)([/+/-](/d/d)(/d/d))?/)///gi).exec(value);
  16. if (a) {
  17. var utcMilliseconds = parseInt(a[1], 10) + ((a[3] == ‘-‘) ? -1 : 1) * (parseInt(a[4], 10) + (parseInt(a[5], 10) / 60.0)) * 60 * 60 * 1000;
  18. return new Date(utcMilliseconds);
  19. }
  20. }
  21. return value;
  22. }

C# Parser:

  1. string dateString = “///Date(1278903921551+0800)///”;
  2. int startPos = dateString.IndexOf(“(“) + 1;
  3. int endPos = dateString.LastIndexOf(“)”) – 1;
  4. string dateNumberString = dateString.Substring(startPos, endPos – startPos + 1);
  5. int timeZoneMilSeconds = 0;
  6. int? timeZoneIndex = null;
  7. if (dateNumberString.IndexOf(“+”) > -1) {
  8. timeZoneIndex = dateNumberString.IndexOf(“+”);
  9. timeZoneMilSeconds = 1;
  10. }
  11. if (dateNumberString.IndexOf(“-“) > -1) {
  12. timeZoneIndex = dateNumberString.IndexOf(“-“);
  13. timeZoneMilSeconds = -1;
  14. }
  15. long dateNumber = 0;
  16. if (timeZoneIndex.HasValue) {
  17. timeZoneMilSeconds = timeZoneMilSeconds * (int)((int.Parse(dateNumberString.Substring(timeZoneIndex.Value + 1).Substring(0, 2))
  18. int.Parse(dateNumberString.Substring(timeZoneIndex.Value + 1).Substring(2)) / 60.0) * 60 * 60 * 1000);
  19. dateNumber = long.Parse(dateNumberString.Substring(0, timeZoneIndex.Value)) + timeZoneMilSeconds;
  20. else {
  21. dateNumber = long.Parse(dateNumberString);
  22. }
  23. long beginTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
  24. DateTime dateValue = new DateTime(beginTicks + dateNumber * 10000);

以上就是常见的JSON的日期格式了。JSON库或者一些AJAX库已经封装了相应的JavaScript的日期的支持,在解析时应直接使用JSON库自带的解析器。如果需要自定义解析这些日期,可参考上述JavaScript和C#代码。

[转载]Easyui的DateBox日期格式化

mikel阅读(1199)

转载Easyui的DateBox日期格式化 – hotdog – ITeye技术网站.

DateBox 日期显示默认的格式为“dd/mm/yyyy”,如果想自定义成我们的格式需要实现两个函数,formatter和parser。

formatter函数使得选择日期后将其格式化为我们需要的格式,parser函数在选择好日期后告诉控件如何去解析我们自定义的格式。

定义如下:
formatter:A function to format the date, the function take a ‘date’ parameter and return a string value.
parser:A function to parse a date string, the function take a ‘date’ string and return a date value.

如将日期格式化为yyyy-mm-dd的格式:

Java代码  收藏代码
  1. $(‘$dd’).datebox({
  2. formatter: function(date){ return date.getFullYear()+‘-‘+(date.getMonth()+1)+‘-‘+date.getDate(); },
  3. parser: function(date){ return new Date(Date.parse(date.replace(/-/g,“/”))); }
  4. });

[转载]InfoQ: 看板和Scrum——相得益彰

mikel阅读(1663)

[转载]InfoQ: 看板和Scrum——相得益彰.

Scrum和看板是敏捷软件开发中的两股风潮 ── 内容简单,但力量强大。它们之间有什么关系呢?

本书的目的是拨开重重迷雾,让大家明白如何在自己的环境中应用看板和Scrum,进行改进。

全书分成两部分。第一部分讲述的是看板和Scrum之间的异同。这个比较只是为了让读者更好地理解它们,而不是判断孰优孰劣。工具没有好坏之分,只有不恰当的使用场合和使用方式。

第二部分是案例分析,它讲述了在使用Scrum方法的组织中,为运维和支撑团队实施看板的过程。

本书与“硝烟中的Scrum和XP”的风格保持一致,依然使用对话式的风格,伴以大量的实践和图示。

全书内容如下:

  • 看板和Scrum简介
  • 看板、Scrum及其它敏捷方法的比较
  • 实践案例及常见误区
  • 用卡通的方式展示每日工作
  • 在Scrum组织中实施看板的案例分析

免费下载

Henrik Kniberg和Mattias Skarin愿意把这本书放到InfoQ.com上提供免费 免费下载这本书(PDF) ,希望能够让更多的读者从中收益。

免费下载(PDF版本)

22.95美元购买此书

如果你喜欢它的电子版,请购买此书来支持作者和InfoQ图书系列。购买地址在这里

章节目录

序──Mary Poppendieck
序──David Anderson
引子

第一部分──二者对比

1. 究竟什么是Scrum,什么是看板?
2. Scrum和看板有什么关系?
3. Scrum规定了角色
4. Scrum规定了固定时长的迭代
5. 看板按流程状态限制WIP,Scrum按迭代限制WIP
6. 二者都是经验主义的
7. Scrum在迭代内拒绝变化
8. Scrum板在迭代之间重置
9. Scrum规定了跨功能团队
10. Scrum的backlog条目必须能跟Sprint搭配的上
11. Scrum规定了估算和生产率
12. 二者都允许在多个产品上并行工作
13. 二者都是既精益又敏捷
14. 小小差异
15. Scrum板 vs. 看板图──一个不大不小的例子
16. 小结── Scrum vs.看板

第二部分─案例分析

17. 技术支持的现状
18. 到底为什么要改变?
19. 我们从哪里开始?
20. 上路
21. 团队启动
22. 直面相关干系人
23. 做出第一个图
24. 设置第一个WIP上限
25.守住WIP上限
26. 什么任务能放到看板图上?
27. 怎样做估算?
28. 我们是怎么工作的,具体点?
29. 哪种做计划的方法好呢
30. 度量什么呢?
31. 忽然一切都不一样了
32. 经验心得

结束语

关于作者

Henrik Kniberg和Mattias Skarin是两位咨询师,在斯德哥尔摩的Crisp公司工作。他们喜欢从软件开发中技术和人的角度入手,帮助其他公司取得成功。他们已经让许多企业应用 了精益和敏捷软件开发。他们喜欢辅导、教学、写作。Henrik的前一本书“硝烟中的Scrum和XP”已经有了15万读者,在世界范围内,数百家公司以 此作为敏捷软件开发的首要向导。

[转载]SQLServer中的临时表和表变量

mikel阅读(1129)

[转载]临时表 Vs 表变量 – OK_008 – 博客园.

开始


说 临时表和表变量,这是一个古老的话题,我们在网上也找到很多的资料阐述两者的特征,优点与缺点。这里我们在SQL Server 2005\SQL Server 2008版本上通过举例子,说明临时表和表变量两者的一些特征,让我们对临时表和表变量有进一步的认识。在本章中,我们将从下面几个方面去进行描述,对其 中的一些特征举例子说明:

  • 约束(Constraint)
  • 索引(Index)
  • I/0开销
  • 作用域(scope)
  • 存儲位置
  • 其他

例子描述


约束(Constraint)

在临时表和表变量,都可以创建Constraint。针对表变量,只有定义时能加Constraint。

e.g.在Microsoft SQL Server Management Studio(MSSMS)查询中,创建临时表并建Constraint场景,<脚本S1.>

Use tempdb
go
if object_id('Tempdb..#1') Is Not Null 
   Drop Table #1                
Go
Create Table #1
(
 ID int,
 Nr nvarchar(50) not null,
 OperationTime datetime default (getdate()),
 Constraint PK_#1_ID Primary Key (ID)
)

Alter Table #1 Add Constraint CK_#1_Nr Check(Nr Between '10001' And '19999')
Go

< 脚本S1.>中,可以看出在临时表#1的创建时,创建Constraint如“Constraint PK_#1_ID Primary Key(ID)”,也可以在创建临时表#1后创建Constraint,如“Alter Table #1 Add Constraint CK_#1_Nr Check(Nr Between ‘10001’ And’19999′)”,下面我们来看表变量的场景,在定义表变量时不能指定Constraint名,定义表变量后不能对表变量创建 Constraint。

e.g. 在定义表变量时不能指定Constraint名<代码S2.>

Use tempdb
Go
Declare @1 Table
(
 ID int,
 Nr nvarchar(50) not null,
 OperationTime datetime default (getdate()),
 Constraint [PK_@1_ID] Primary Key (ID)
)
image

在定义表变量后不能对表变量创建Constraint,<代码S3.>

use tempdb
go
Declare @1 Table
(
 ID int primary key clustered,
 Nr nvarchar(50),
 OperationTime datetime default (getdate())
)

Alter Table @1 Add Constraint [CK_@1_Nr] Check(Nr Between '10001' And '19999')

image

在<代码S2.>和<代码S3.>中可以发现,在解析T-SQL语法过程就发生错误,也就是SQL Server不支持定义表变量时对Constraint命名,也不支持定义表变量后,对其建Constraint。

这里慎重提示下,在<代码S1.>给临时表建Constraint的时候,特别是在并发场景中,不要指定具体的Constraint名称,不然会发生对象已存在的错误提示。

e.g. 在MSSMS中我们先执行之前<代码S1.>的创建临时表#1,不关闭当前会话的情况下,另建一个查询,执行与<代码S1.>相同的代码,如图

image

左边的查询窗口,是执行原先的<代码S1.>,右边的查询窗口,是后执行相同的<代码S1.>。在这里,我们注意红色圈圈 部分,发现在创建临时表#1的过程,明确给了一个主键名称“PK_#1_ID”,当右边再创建相同临时表#1的时候就发生了对象重复错误问题。我们也可以 通过SQL Server提供的系统视图sys.objects查询约束“PK_#1_ID”的信息,

use tempdb

go

Select * from sys.objects Where name='PK_#1_ID'

image

在系统视图sys.objects,发现“PK_#1_ID”名称后面不加如何的随机数值表述不同会话有不同的对象。根据SQL Server对sys.objects的描述规则,sys.objects中的Name列数据是唯一的。当另一个会话创建相同的对象时就会发生对象重复的 错误。

在Constraint中,Foreign Key是不能应用与表变量,对于临时表,创建Foreign Key是没有意义的。也就是说临时表不受Foreign Key约束。下面我们通过例子来说明临时表的情况,

e.g.< 脚本S4.>

use tempdb
go
if object_id('Tempdb..#1') Is Not Null
    Drop Table #1                
Go
if object_id('Tempdb..#2') Is Not Null
    Drop Table #2                
Go
Create Table #1
(

    ID int,
    Nr nvarchar(50) not null,
    OperationTime datetime default(getdate()),
    Constraint PK_#1_ID Primary Key(ID)
)
Alter Table #1 Add Constraint CK_#1_Nr Check(Nr Between '10001' And '19999')
Create table #2
(
    ID int Primary Key,
    ForeignID int Not null ,foreign Key(ForeignID) References #1(ID)
)
Go

image

可以看出对于临时表不强制Foreign Key约束,我们也可以通过SQL Server系统视图sys.foreign_keys查询

use tempdb
go
Select * from sys.tables Where name like '#[1-2]%'
Select * From sys.foreign_keys
image

右边的查询,只看到在sys.tables表哦中存在刚才创建的临时表#1和#2,在sys.foreign_keys看不到有关Foreign Key约束信息。这也验证了左边SQL Server提示的,在临时表中无法强制使用Foreign Key约束。

索引(Index)

从索引方面看临时表和表变量,与从Constraint上分析有些类似,在临时表中,它与真实表一样可以创建索引。在表变量定义过程中,也可以创建一些类似唯一和聚集索引。

e.g.< 脚本S5.>

use tempdb

go

declare @1 Table(      

                ID int  primary key clustered,

                Nr nvarchar(50) unique Nonclustered

)

Insert into @1 (id,Nr) values(1,'10001')

Insert into @1 (id,Nr) values(2,'10002')

Insert into @1 (id,Nr) values(8,'10003')

Insert into @1 (id,Nr) values(3,'10004')

Insert into @1 (id,Nr) values(7,'10005')

Select top 2 *

                From sys.indexes As a

                                Inner Join sys.tables As b On b.object_id=a.object_id

                Order by b.create_date Desc

Select Nr From @1 Where Nr='10005'

go

image

image

上面截的是两张图,第一张图描述在表变量使聚集Primary Key,创建非聚集的Unique约束,第二张图描述查询语句”Select Nr From @1 Where Nr=’10005’” 应用到在表变量创建的唯一索引“UQ_#……”

是于临时表索引的例子,我们拿一个例子说明,与前边说的Constraint例子有点相似,这里我们对临时表创建索引,并给索引一个具体名称,测试是否会重复。

e.g.在MSSMS新增两个查询,编写下面的SQL语句:

< 脚本S6.>

Use tempdb
Go
if object_id('#1') is not null    
    Drop Table #1 
    
Create Table #1
(
 ID int primary key,
 Nr nvarchar(50) not null,
 OperationTime datetime default (getdate()),
)

create nonclustered index IX_#1_Nr on #1(Nr Asc)
go
Select b.name As TableName,
       a.* 
    from sys.indexes As a
        Inner join sys.tables As b On b.object_id=a.object_id
    Where b.name like '#1[_]%'
    Order by b.create_date Asc

image

从返回的结果,我们看到在系统视图表Sys.Indexes中,创建有两个相同的索引”IX_#1_Nr”,但注意下object_id数据不同。 在SQL Server中是允许不同的表索引名称可以相同的。在并发的环境下,按原理是可以对临时表创建的索引给明确名称的。除非并发的情况会发生重复的表名或重复 的Constraint,或其它系统资源不足的问题,才会导致出错。

I/0开销

临时表与表变量,在I/O开销的描述,我们直接通过一个特殊的例子去描述它们,在MSSMS上新增两个查询,分别输入临时表和表变量的测试代码:

e.g.< 脚本S7.>临时表:

Use tempdb
Go
if object_id('#1') is not null    
    Drop Table #1 
    
Create Table #1
(
 ID int primary key,
 Nr nvarchar(50) not null,
 OperationTime datetime default (getdate())
)

Insert into #1(ID,Nr,OperationTime)
Select top 50000 row_number()over (order by a.object_id),left(a.name+b.name,50) ,a.create_date
    from master.sys.all_objects As a ,sys.all_columns As b
    Where type='S'



Select Nr,count(Nr) As Sum_ 
    From #1 
    Where Nr like 'sysrscolss%'    
    Group by Nr

< 脚本S8.>表变量:

Use tempdb
Go
Declare @1 Table
(
 ID int primary key,
 Nr nvarchar(50) not null,
 OperationTime datetime default (getdate())
)

Insert into @1(ID,Nr,OperationTime)
Select top 50000 row_number()over (order by a.object_id),left(a.name+b.name,50) ,a.create_date
    from master.sys.all_objects As a ,sys.all_columns As b
    Where type='S'
    

Select Nr,count(Nr) As Sum_ 
    From @1 
    Where Nr like 'sysrscolss%'    
    Group by Nr

image

< 脚本S7.>和< 脚本S8.>,主要是看最后的查询语句I/O的开销,两者有何不同。通过上面的运行结果图形描述,可以看出查询开始,不管是临时表还是表变量,都使 用到了聚集索引扫描(Clustered Index Scan),两者虽然返回的数据一致,但I/O的开销不同。临时表的I/O开销是0.324606,而表变量只有0.003125 相差非常大。在临时表的执行计划图形中,我们发现一行“缺少索引(影响 71.9586):CREATE ……)”提示信息。我们对临时表#1,在字段“Nr”上创建一个非聚集索引,再看执行执行结果:

create nonclustered index IX_#1_Nr On #1(Nr)

image

我们在临时表#1上创建完索引“IX_#1_Nr”,运行看上面的图形显示,就感觉非常的有意思了。在临时表#1查询时用了索引搜索(Index Seek),而且I/O开销减少到了0.0053742。虽然开始查询的时候I/O开销还是比表变量开始查询的时候大一些,但执行步骤中比变变量少了一个 “排序(Sort)”开销,后最后的看回Select结果,估计子树的成本比使用表变量的大大减少。

这里的例子只是描述一个特殊的情况,在真实的环境中,要根据实际的数据量来判断是否使用临时表或表变量。倘若在存储过程中,当数据量非常少如只有不到50行记录,数据占的页面也不会超过1个页面,那么使用表变量是一个很好的解决方案。

作用域(scope)

表变量像局部变量(local variable)一样,有着很窄的作用域,只能应用于定义的函数、存储过程或批处理内。如,一个会话里面有几个批处理,那么表变量只能作用在它定义所在的批处理范围内。其他的批处理无法再调用它。

e.g.在MSSMS新增一个查询,编写< 脚本S9.>

use tempdb
Go
Set Nocount on
declare @1 Table(      
                ID int  primary key clustered,
                Nr nvarchar(50) unique Nonclustered
)
Insert into @1 (id,Nr) values(1,'10001')
Insert into @1 (id,Nr) values(2,'10002')
Insert into @1 (id,Nr) values(8,'10003')
Insert into @1 (id,Nr) values(3,'10004')
Insert into @1 (id,Nr) values(7,'10005')

Select * From @1

Go --批处理结束点

Select * From @1

image

< 脚本S9.>所在的查询相当于一个会话,”Go”描述的一个批处理的结束点。在”Go”之前定义的表变量,在”Go”之后调用是发生“必须声明变量@1”的错误提示。

临时表与表变量不同,临时表的作用域是当前会话都有效,一直到会话结束或者临时表被Drop的时候。也就是说可以跨当前会话的几个批处理范围。

e.g.< 脚本S10.>

Use tempdb
go
if object_id('Tempdb..#1') Is Not Null 
   Drop Table #1                
Go
Create Table #1
(
 ID int,
 Nr nvarchar(50) not null,
 OperationTime datetime default (getdate()),
 Constraint PK_#1_ID Primary Key (ID)
)
Select * from #1

go --批处理结束点

Select * from #1

image

< 脚本S10.>中可以看出在”GO”前后都可以查询到临时表#1。

在描述临时表与表变量的作用域时,有个地方要注意的是,当 sp_executesql 或 Execute 语句执行字符串时,字符串将作为它的自包含批处理执行. 如果表变量在sp_executesql 或 Execute 语句之前定义,在sp_executesql 或 Execute 语句的字符串中无法调用外部定义的表变量。

e.g.< 脚本S11.>

use tempdb
go
Set nocount on
declare @1 Table(      
                ID int  primary key clustered,
                Nr nvarchar(50) unique Nonclustered
)
Insert into @1 (id,Nr) values(1,'10001')
Insert into @1 (id,Nr) values(2,'10002')
Insert into @1 (id,Nr) values(8,'10003')
Insert into @1 (id,Nr) values(3,'10004')
Insert into @1 (id,Nr) values(7,'10005')

Select * From @1

Execute(N'Select * From @1')

go

image

< 脚本S11.>中,当执行到”Execute(N’Select * From @1′)”时候,同样发生与< 脚本S9.>一样的错误提示“必须声明变量@1”.

临时表是可以在sp_executesql 或 Execute 语句执行字符串中被调用。这里不再举例子,如果你有所模糊可以参考< 脚本S11.>把表变量转成临时表测试下就能加深理解与记忆。

存儲位置

说到临时表和表变量的存储位置,我们可以看到有很多版本的说法,特别是表变量。有的说表变量数据存储在内存中,有的说存储在数据库tempdb中, 有的说有部分存储在内存,部分存储在数据库tempdb中。根据我查到的官方资料,说的是在SQL Server 2000下:

A table variable is not a memory-only structure. Because a table variable might hold more data than can fit in memory, it has to have a place on disk to store data. Table variables are created in the tempdb database similar to temporary tables. If memory is available, both table variables and temporary tables are created and processed while in memory (data cache).

在SQL Server 2005\SQL2008的版本,表变量存储与临时表有相似,都会在数据库tempdb创建,使用到tempdb存储空间。

e.g.< 脚本S12.>临时表

use tempdb
go
Set nocount on

Exec sp_spaceused /*插入数据之前*/

if object_id('#1') Is not null 
    Drop Table #1 
    
create table #1(ID int ,Nr nvarchar(50))
Insert into #1  (ID,Nr)
    Select top(1) row_number() Over(order By a.object_id),left(a.name+b.name,50)
        From sys.all_objects As a,
            sys.all_columns As b    
                                
Select top(1) name,object_id,type,create_date from sys.tables Order by create_date Desc            

Exec sp_spaceused /*插入数据之后*/
Go

image

在< 脚本S12.>执行后,我们可以看到在数据库tempdb中的表sys.tables创建有表#1。我们接着看空间的使用情况,插入数据之前,数据 库未使用空间(unallocated space)为510.39MB,向临时表#1插入1条数据后,数据库未使用空间为501.38MB,未使用空间变小了。再来看整个数据库的数据 (data)使用的空间变化,从552KB变成560KB,使用了一页的数据空间(8kb)。这说明一点,临时表,即使你只插入一条数据都会使用到数据库 tempdb的空间。也许会有人问,要是我只建临时表#1,不插入数据,会如何。我们可以结果:

image

这里你会发现前后的空间大小不变,不过,不要认为没有使用到数据库tempdb数据空间,当你多用户创建临时表结构的时候,你就会发现其实都会应用到数据库tempdb的空间。我这里创建了10个#1后的效果如:

image

相同的原理,我们使用类似的方法测试表变量的情况,发现结论是与临时表的一致的,会使用到数据库tempdb的空间.

e.g.< 脚本S13.>表变量

use tempdb
go
Set nocount on
Exec sp_spaceused /*插入数据之前*/

Declare @1 table(ID int ,Nr nvarchar(50))
Insert into @1  (ID,Nr)
    Select top(1) row_number() Over(order By a.object_id),left(a.name+b.name,50)
        From sys.all_objects As a,
            sys.all_columns As b            
            
Select top(1) name,object_id,type,create_date from sys.objects Where type='U' Order by create_date Desc            

Exec sp_spaceused /*插入数据之后*/

Go
Exec sp_spaceused /*Go之后*/

image

< 脚本S13.>中,我多写了一个”GO”之后检查空间大小的存储过程sp_spaceused。这样为了了更能体现表变量使用空间变化情况。从插入 数据前和插入数据后的结果图来看,表变量不仅在数据库tempdb创建了表结构#267ABA7A类似的这样表,表变量也应用到了数据库tempdb的空 间。不过这里注意一点就是在”Go”之后,我们发现表变量@1,会马上释放所使用的数据空间。为了更能体现使用空间情况。我们可以向表变量@1插入大量数 据看空间变化情况(测试插入1000万的数据行)。

e.g.< 脚本S14.>

use tempdb
go
Set nocount on
Exec sp_spaceused /*插入数据之前*/

Declare @1 table(ID int ,Nr nvarchar(50))
Insert into @1  (ID,Nr)
    Select top(10000000) row_number() Over(order By a.object_id),left(a.name+b.name,50)
        From sys.all_objects As a,
            sys.all_columns As b            
            
Select top(1) name,object_id,type,create_date from sys.objects Where type='U' Order by create_date Desc            

Exec sp_spaceused /*插入数据之后*/

Go
Exec sp_spaceused /*Go之后*/

image

这里我们可清晰的看到数据库tempdb的大小(database_size)变化情况,从插入数据前的552.75MB变成插入数据之后的 892.75MB。非常有意思的是我们在”Go之后”发现数据库大小保存在892.75MB,但数据使用空间(data)从560KB— >851464KB—>536KB ,说明SQL Server自动释放为使用的数据空间,但不会马上自动释放数据库分配的磁盘空间。我们在实际的环境中,发现临时数据库tempdb使用的磁盘空间越来越 大,这是其中的原因之一。

其他

临时表与表变量,还有其他的特征,如临时表受事务回滚,而表变量不受事务回滚影响。对应事务方面,更为正确的说法是表变量的事务只在表变量更新期间存在。因此减少了表变量对锁定和记录资源的需求。

e.g.< 脚本S15.>

use tempdb
go
Set nocount on

if object_id('#1') Is not null 
    Drop Table #1     
create table #1(ID int ,Nr nvarchar(50))
Declare @1 table(ID int ,Nr nvarchar(50))

begin tran /*开始事务*/

Insert into #1  (ID,Nr)
    Select top(1) row_number() Over(order By a.object_id),left(a.name+b.name,50)
        From sys.all_objects As a,
            sys.all_columns As b    


Insert into @1  (ID,Nr)
    Select top(1) row_number() Over(order By a.object_id),left(a.name+b.name,50)
        From sys.all_objects As a,
            sys.all_columns As b    
            
rollback tran /*回滚事务*/

Select * from #1
Select * from @1

Go

image

这里发现”Rollback Tran”之后,临时表#1没有数据插入,而表变量@1还有一条数据存在。说明表变量不受”Rollback Tran”所影响。它的行为有类似于局部变量一样。

另外SQL Server对表变量不保留任何的统计信息,因为如此,我们在数据量大的时候使用表变量,发现比临时表要慢许多。前面在I/O开销那里我们取有一个特殊的例子,这里不再举例。

小结

无论如何,临时表和表变量有各自的特征,有自己优点和缺点。在不同的场景选择它们灵活应用。本文章是我对临时表和表变量的一些认识理解,可能有些地方说的不够好或者遗漏,你可以留言或Email与我联系,我会继续改进或纠正,我也不希望有些错误的见解会误导别人。正如Phil Factor说的一句” I’d hate to think of anyone being misled by my advice!”.

附参考:

http://support.microsoft.com/kb/305977/en-us

http://stackoverflow.com/questions/27894/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server

http://msdn.microsoft.com/en-us/library/aa175774(SQL.80).aspx

http://msdn.microsoft.com/en-us/library/cc966545.aspx

http://www.simple-talk.com/sql/t-sql-programming/temporary-tables-in-sql-server/

http://support.microsoft.com/kb/942661/en-us

[转载]Android和iOS自带的人脸检测API

mikel阅读(1195)

[转载]Android和iOS自带的人脸检测API – Range – 博客园.

说说Android和iOS里面自带的人脸检测API。

Android提供了一个人脸检测类 Android.media.FaceDetector,调用findFaces函数,它可以返回图片中的找到的人脸。人脸的属性封装在Face类,包括x, y, z三轴的人脸pose,还有两眼距离eyesDistance()。这个API从Android刚推出时Level 1就已经有了。

iOS以前是没有人脸检测模块的。去年苹果收购了Polar Rose,把他们人脸检测技术融入到新推出的iOS 5当中:CIDetector是个通用的检测器,构造时可以指定感兴趣的目标,目前只能检测人脸CIDetectorTypeFace。返回的人脸信息封装在CIFaceFeature类中,包含了:leftEyePosition, rightEyePosition, mouthPosition 5现在还在Beta测试版中,只对付费developer开放,估计很快就要正式发布了。

从功能上来看两者差不多。至于效果,我只看过WWDC上iOS的Demo,可以做实时Avatar。Android的API从初代Level 1就有了,如果用的人不多的话,猜测可能效果不能保证。

VIA 老杨

[转载]快速构建SVN局域网服务器

mikel阅读(1258)

[转载]快速构建SVN局域网服务器 – 游空 – 博客园.

先说一下初衷。

前一阵子想把自己的代码拷贝一份到女友的电脑上,这样无论在哪台电脑都可以弄代码了,然而却会有两边版本不一致的问题,但苦于没有找到解决的途径。

前两天做那GM回复工具,也需要用到数据共享,同事建议说用SVN局域网服务器来实现,顿时来了兴趣。于是,在同事的协助下,动手把SVN局域网服务器搞起来了。真的很方便,动起来其实也很简单,现在和大家分享一下。

1  先从官网下载SVN服务端,如果是安装包,则自动会设置好环境变量。如果是绿色版,则需要手动设置环境变量: 如:文件所在目录为 C:\Program Files\svn-win32-1.6.5\bin,则设置环境变量如图所示:

2  建立自己的SVN服务器根目录文件夹,如: E:\SvnRoot

3  在命令行在该文件夹下创建SVN的数据目录,如:

4 于是成功在SvnRoot目录下创建了 code 文件夹,现在看看该文件夹下自动生成的内容:

5 打开 conf 文件夹,有三个配置文件如下,svnserve配置指定哪个是账号文件,passwd配置账号和密码,authz 配置已有账号的权限:

6  svnserve具体配置如下,主要是将  password-db 前的#号去掉,即去掉注释使其生效:

7  passwd具体配置如下,主要是新增自己需要的账号和密码,也可以将原有的账号去掉注释使用

8 authz 具体配置如下,主要是设置账号的读写权限,即更新提交权限:

9 构建完毕,即可启动服务器:建一个任意名字的 .bat 文件,内容如下,后面的是刚才新设置的SVN根目录路径:

10 双击即可启动服务器,每次开机后第一次使用SVN服务器前就必须先启动,且不能关闭。

11 后来我嫌这个窗口一直得显示不方便,于是找到一个隐藏其窗口的途径,如:建一个 start.vbs 文件,内容如下:

12 双击该文件即可执行svnroot.bat,且隐藏了cmd窗口:

13 现在,在局域网下的其他电脑或者本机可以用下面的url来checkout数据目录,其中 192.168.0.101为服务器所在电脑的IP地址,如果是服务器本机也可用svn://localhost/data作为checkout地址来操作:

14 按checkout时弹出账号密码输入提示,用刚配置的账号密码即可,同时勾选左下角的框记录账号信息,以后就不用再输入:

15 checkout 成功:

16 现在,就可以在checkout 的code 目录下添加或修改删除文件了。SVN构建局域网服务器兼使用说明讲解完毕。

[转载]eval在JavaScript中的作用

mikel阅读(936)

[转载]eval在JavaScript中的作用 .

eval函数是强大的数码转换引擎,字符串经eval转换后得到一个JavaScript对象,
举简单例子:
var a = eval(“5”);等效于var a = 5;
var a = eval(“‘5′”);等效于var a = ‘5’;
var obj = eval(“({name:’cat’,color:’black’})”);等效于 var obj = {name:’cat’,color:’black’};
eval(“alert(‘hello world!’);”);等效于 alert(‘hello world!’);

js的数据类型为弱类型,可以在定义的时候指定数据类型,也可以在运算过程中强制数据类型转换

一个对象经过eval转换后数据类型不确定,在相加过程中自动与其他数据类型一致

[转载]使用Jquery EasyUi常见问题解决方案

mikel阅读(1019)

[转载]使用Jquery EasyUi常见问题解决方案.

/**
*清空指定表单中的内容,参数为目标form的id
*注:在使用JQuery EasyUI的弹出窗口录入新增内容时,每次打开必须清空上次输入的历史
*数据,此时通常采用的方法是对每个输入组件进行置空操作:$(“#name”).val(“”),这样做,
*当输入组件比较多时会很繁琐,产生的js代码很长,这时可以将所有的输入组件放入个form表单
*中,然后调用以下方法即可。
*
*@param formId将要清空内容的form表单的id
*/
function resetContent(formId) {
var clearForm = document.getElementById(formId);
if (null != clearForm && typeof (clearForm) != “undefined”) {
clearForm.reset();
}
}

/**
*刷新DataGrid列表(适用于JQuery Easy Ui中的dataGrid)
*注:建议采用此方法来刷新DataGrid列表数据(也即重新加载数据),不建议直接使用语句
*$(‘#dataTableId’).datagrid(‘reload’);来刷新列表数据,因为采用后者,如果日后
*在修改项目时,要在系统中的所有刷新处进行其他一些操作,那么你将要修改系统中所有涉及刷新
*的代码,这个工作量非常大,而且容易遗漏;但是如果使用本方法来刷新列表,那么对于这种修
*该需求将很容易做到,而去不会出错,不遗漏。
*
*@paramdataTableId将要刷新数据的DataGrid依赖的table列表id
*/
function flashTable(dataTableId) {
$(‘#’ + dataTableId).datagrid(‘reload’);
}
/**
*取消DataGrid中的行选择(适用于JQuery Easy Ui中的dataGrid)
*注意:解决了无法取消”全选checkbox”的选择,不过,前提是必须将列表展示
*数据的DataGrid所依赖的Table放入html文档的最全面,至少该table前没有
*其他checkbox组件。
*
*@paramdataTableId将要取消所选数据记录的目标table列表id
*/
function clearSelect(dataTableId) {
$(‘#’ + dataTableId).datagrid(‘clearSelections’);
//取消选择DataGrid中的全选
$(“input[type=’checkbox’]”).eq(0).attr(“checked”, false);
}

/**
*关闭jQuery EasyUi的弹出窗口(适用于jQuery Easy Ui)
*
*@paramdialogId将要关闭窗口的id
*/
function closeDialog(dialogId) {
$(‘#’ + dialogId).dialog(‘close’);
}

/**
*自适应表格的宽度处理(适用于Jquery Easy Ui中的dataGrid的列宽),
*注:可以实现列表的各列宽度跟着浏览宽度的变化而变化,即采用该方法来设置DataGrid
*的列宽可以在不同分辨率的浏览器下自动伸缩从而满足不同分辨率浏览器的要求
*使用方法:(如:{field:’ymName’,title:’编号’,width:fillsize(0.08),align:’center’},)
*
*@parampercent当前列的列宽所占整个窗口宽度的百分比(以小数形式出现,如0.3代表30%)
*
*@return通过当前窗口和对应的百分比计算出来的具体宽度
*/
function fillsize(percent) {
var bodyWidth = document.body.clientWidth;
return (bodyWidth – 90) * percent;
}

/**
* 获取所选记录行(单选)
*
* @paramdataTableId目标记录所在的DataGrid列表的table的id
* @paramerrorMessage 如果没有选择一行(即没有选择或选择了多行)的提示信息
*
* @return 所选记录行对象,如果返回值为null,或者”null”(有时浏览器将null转换成了字符串”null”)说明没有
*选择一行记录。
*/
function getSingleSelectRow(dataTableId, errorMessage) {
var rows = $(‘#’ + dataTableId).datagrid(‘getSelections’);
var num = rows.length;
if (num == 1) {
return rows[0];
} else {
$.messager.alert(‘提示消息’, errorMessage, ‘info’);
return null;
}
}

/**
* 在DataGrid中获取所选记录的id,多个id用逗号分隔
* 注:该方法使用的前提是:DataGrid的idField属性对应到列表Json数据中的字段名必须为id
* @paramdataTableId目标记录所在的DataGrid列表table的id
*
* @return 所选记录的id字符串(多个id用逗号隔开)
*/
function getSelectIds(dataTableId, noOneSelectMessage) {
var rows = $(‘#’ + dataTableId).datagrid(‘getSelections’);
var num = rows.length;
var ids = null;
if (num < 1) { if (null != noOneSelectMessage) $.messager.alert('提示消息', noOneSelectMessage, 'info'); return null; } else { for (var i = 0; i < num; i++) { if (null == ids || i == 0) { ids = rows[i].id; } else { ids = ids + "," + rows[i].id; } } return ids; } } /** *删除所选记录(适用于Jquery Easy Ui中的dataGrid)(删除的依据字段是id) *注:该方法会自动将所选记录的id(DataGrid的idField属性对应到列表Json数据中的字段名必须为id) *动态组装成字符串,多个id使用逗号隔开(如:1,2,3,8,10),然后存放入变量ids中传入后台,后台 *可以使用该参数名从request对象中获取所有id值字符串,此时在组装SQL或者hql语句时可以采用in *关键字来处理,简介方便。 *另外,后台代码必须在操作完之后以ajax的形式返回Json格式的提示信息,提示的json格式信息中必须有一个 *message字段,存放本次删除操作成功与失败等一些提示操作用户的信息。 * *@paramdataTableId将要删除记录所在的列表table的id *@paramrequestURL与后台服务器进行交互,进行具体删除操作的请求路径 *@paramconfirmMessage 删除确认信息 */ function deleteNoteById(dataTableId, requestURL, confirmMessage) { if (null == confirmMessage || typeof (confirmMessage) == "undefined" || "" == confirmMessage) { confirmMessage = "确定删除所选记录?"; } var rows = $('#' + dataTableId).datagrid('getSelections'); var num = rows.length; var ids = null; if (num < 1) { $.messager.alert('提示消息', '请选择你要删除的记录!', 'info'); } else { $.messager.confirm('确认', confirmMessage, function (r) { if (r) { for (var i = 0; i < num; i++) { if (null == ids || i == 0) { ids = rows[i].id; } else { ids = ids + "," + rows[i].id; } } $.getJSON(requestURL, { "ids": ids }, function (data) { if (null != data && null != data.message && "" != data.message) { $.messager.alert('提示消息', data.message, 'info'); flashTable(dataTableId); } else { $.messager.alert('提示消息', '删除失败!', 'warning'); } clearSelect(dataTableId); }); } }); } } [/js]