[转载]利用log4net记录操作日志

mikel阅读(1230)

[转载]利用log4net记录操作日志 – justconnor – 博客园.

1,目的:将用户操作日志写入SQL server 数据库中

2,实现步骤:

一,下载log4net.dll (推荐从官网下载 http://logging.apache.org/log4net/download_log4net.cgi

二,在项目中引用 log4net.dll

三,添加一个配置文件:我这里命名为 log4net.config(也可以在web.config里面配置为便于管理故新建了一个配置文件)

View Code

<!--?xml version="1.0"?-->
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,   log4net "></section>





<!--这里是表示是记录1 条到缓冲区,满1条后再写入SQL server 可根据需要自定义配置-->


























四,在项目的 AssemblyInfo.cs 文件的指定log4net 的配置文件路径

[assembly: log4net.Config.XmlConfigurator(ConfigFile = “log4net.config”, Watch = true)]

五,自定义记录函数

View Code 

  public static void Operate_Log(string operateType, string describe)
        {
            log4net.ILog logToSQL = log4net.LogManager.GetLogger("iNotes");
            log4net.MDC.Set("OperateType", operateType);
            log4net.MDC.Set("Describe", describe);
            log4net.MDC.Set("Userid", HttpContext.Current.Session["userid"].ToString());
            log4net.MDC.Set("OperateTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            logToSQL.Info("");
        }

转载LINQ学习扩展方法,委托,Lambda表达式 第二篇

mikel阅读(856)

转载LINQ学习扩展方法,委托,Lambda表达式 第二篇 – 韩迎龙 – 博客园.

  1. LINQ基本查询操作符-获取数据

(1) select()  语法是:

public static IEnumerable<TResult> select<TSource,TResult>(

this IEnumerbale<TSource> source.

Func<TSource,TResult> selector)

说明:1) select方法本身是一个泛型扩展方法

2) 它作用于IEnumerable<TSource>类型

3) 他只接受一个Func<TSource,TResult>类型参数

4) Func<TSource,TResult>是一个泛型委托,位于System名字的空间下,System.Core.dll中,在这里Selector是一个提取器。

 (2) 举例说明,先定义一个静态类ExtraClass,然后再静态类中在定义一个静态的扩展方法,实现输出信息。代码如下:

public static class ExtraClass

    {

        //为IEnumerable提供输出的方法

        public static void Print(this IEnumerable<string> ie)

        {

            IEnumerator<string> result = ie.GetEnumerator();

            while (result.MoveNext())

            {

                MessageBox.Show(result.Current);

            }

        }

}

然后如图所示,单击图上的按钮事件,在按钮事件中的代码是:

此事件下面的代码实现了将一个泛型集合中的数据循环显示出来,代码如下:

List<string> persons = new List<string>();

    persons.Add(“zhang san”);

    persons.Add(“zhang san feng”);

    persons.Add(“li si”);

    persons.Add(“wang wu”);

    persons.Add(“wang liu”);

    persons.Add(“li ba”);

    persons.Add(“lao wu”);

    persons.Add(“zhang xx”);

    //输出persons里面的所有的元素

    var result = persons.Select(p => p);

result.Print();

执行结果是按顺序循环输出。

2. LINQ基本查询操作符-过滤数据

(1) where() 语法是:

public static IEnumerable<TSource> where<TSource>(

this IEnumerable<TSource> source,

Func<TSource,bool> predicate)

说明:1) where方法是一个泛型扩展方法

2) 它和select()一样作用与IEnumerable<TSource>类型

3) 它只接受一个Func<TSource,bool>泛型委托参数,在这里predicate是一个判断条件。

(2) 举例说明,还是上面的例子,使用那个泛型集合,实现按照一定的条件输出信息。先创建一个方法,实现输出姓“zhang”的人的信息,代码如下:

public bool Judge(string s)

        {

            if (s.StartsWith(“zhang”))

            {

                return true;

            }

            return false;

        }

  在select控件的事件下面用LINQ代码输出只是姓张的各种各样的实现代码:

//输出persons里面姓“zhang”的人

     //var result = persons.Where(p => p.StartsWith(“zhang”));  //第一种方法

     //var result = persons.Select(p => p).Where(p => p.StartsWith(“zhang”)); //第二种方法

     //var result = persons.Where(p => p.StartsWith(“zhang”)).Select(p => p);  //第三种方法

     var result = persons.Where(p => Judge(p));   //第四种方法

     result.Print();

3. LINQ基本查询操作符-排序数据

(1) OrderBy()  语法是:

pblic static IOrderedEnumerable<TSource> orderBy<TSource,TKey>(

this IEnumerable<TSource> source

Func<TSource,TKey> keySelector)

注:1) orderBy方法也是一个泛型扩展方法

2) 它和select()一样作用与IEnumerable<TSource>类型

3) 它只接收一个Func<TSource,Tkey>类型参数,在这里keySelctor指定要排序的字段。

4) 如果想要降序排列可以使用orderbyDescending方法。

(2) 举例说明,同上例,实现排序的代码如下:

//var result = persons.OrderBy(p => p);

       //按照名字的最后一个字母排序

       //var result = persons.OrderBy(p => p.Substring(p.Length – 1, 1)).Select(p => p);

       //降序排列

       var result = persons.OrderByDescending(p => p);

       result.Print();

  1. Linq基本查询操作符-分组数据

(1) GroupBy()  语法是:

public static IEnumerable<IGrouping<Tkey,TSource>>

GroupBy<TSource,TKey>(

this IEnumerable<TSource> source,

Func<TSource,TKey> keySelector  )

说明:1) GroupBy()方式和OrderBy()方式非常类似,它也是一个泛型扩展方法。

2) 它和OrderBy()一样作用与IEnumerable<TSource>类型。

3) 它只接受一个Func<TSource,TKey>类型参数,在这里keySelector指定要分组的字段。

(2) 举例说明,同上例,实现分组的代码是:

//分组—按照姓名来分组¦–取出姓名中的空格前的部分

     var result = persons.GroupBy(p => p.Split(new char[] { ‘ ‘ })[0]);

    foreach (var group in result)

    {

         Console.WriteLine(“姓:” + group.Key);

         foreach (var name in group)

          {

               Console.WriteLine(“\t” + name);

          }

          Console.WriteLine();

     }

  1. 查询执行的时机

(1) 从前面的试验中,我们发现一次查询实际上经过以下3步。

1) 第一步:获取数据源  int[] numbers=new int[]{3,45,65,76,2,434,54,65,76,76,65,43};

2) 第二步:定义查询  var even=numbers.Where(p=>p%2==0).Select(p=>{

Console.WriteLine(“Hi!”+p.ToString());

return p;     });

3) 第三步:执行查询   foreach(var item in even){   }

  1. 查询执行的时机小节

(1) 查询分为以下三步,获取数据源,定义查询,执行查询

(2) 定义查询后,查询直到需要枚举结果时才被真正执行,这种方法称为”延迟执行”。

(3) 当查询结果返回单一值时,查询立即执行。举例,如代码:

         //查询时机—当返回值为单值时马上执行语句,负责延迟执行

      var result = persons.Select(p => p).Count();

      Console.WriteLine(“个数是” + result);

(4) 因此,可以通过以下技巧在定义查询时就强制执行查询

  1. Linq查询的两种方式

(1) Method syntax,查询方法方式

主要利用System.Linq.Enumerable类中定义的扩展方法和Lambda表达式方式进行查询。

(2) Query syntax ,查询语句方式

  1. 查询语句VS查询方法

注:查询语句和查询方法存在着紧密的关系

(1) CLR本身并不理解查询语句,它只理解查询方法。

(2) 编译器负责在编译时将查询语句翻译为查询方法。

(3) 大部分查询方法都有对应的查询语句形式,如:Select()对应select,OrderBy()对应orderby。

(4)部分查询方法目前在C#中还没有对应的查询语句:如:Count()和Max()这时只能采用以下替代方案

1) 查询方法

2) 查询语句+查询方法的混合方式

(5) 一般情况下,建议使用可读性更好的查询语句。举例说明:

还是用上面多定义的泛型集合数组persons,用查询语句实现几个简单的功能,代码如下:

//输出persons中的所有的元素

var result = from p in persons select p;

    //输出persons中姓zhang的人—-语句和方法的混合编排?

     var result = (from p in persons select p).Where(p => p.StartsWith(“zhang”));

     //排序

      var result = from p in persons orderby p select p;

      result.Print();

  1. 高级查询方法

(1) 聚合类  Count(),Max()/Min(),Average(),Sum()。举例说明:

重新定义一个数组来实现上面的各种各样的方法,代码如下:

   //LINQ to Objects查询高级方法

      //数组数据arr

      int[] arr = { 23, 34, 5, 5, 23, 45, 65, 33, 43, 76, 67, 87 };

      //聚合类

      Console.WriteLine(“arr的最大值: + arr.Max());

      Console.WriteLine(“arr的最小值¦: ” + arr.Min());

      Console.WriteLine(“arr的平均值¦: ” + arr.Average());

      Console.WriteLine(“arr的数组元素个是” + arr.Count());

      Console.WriteLine(“arr的总和是: ” + arr.Sum());

(2) 排序类  thenBy()  代码如下:

      //排序类

      var result = arr.OrderBy(p => p.ToString().Substring(0, 1));

      //2次排序混编模式没有达到要求

      var result = arr.OrderBy(p => p.ToString().Substring(0, 1)).ThenBy(p => p);

      //按照语句排序

      var t = arr.OrderBy(p => p.ToString().Substring(0, 1));

      var result = from p in t orderby p descending select p;

(3) 分区类  Take,TakeWhile,Skip,SkipWhile   代码如下:

      //分区类

      var result = arr.Skip(3).Take(3);  //跳过三个值取三个值

      var result = arr.Skip(3);  //跳过几个值

var result = arr.SkipWhile(p => p > 4); //方法体部分是该Linq语句不在往后执行的条件,当第一次遇到条件成立时,取剩下的所有元素

      var result = arr.TakeWhile(p => p > 4); //方法体部分是该Linq语句提取数据的条件,当第一次遇到条件不成立的情况就停止执行

(4) 集合类   Distinct   代码如下:

      //集合类

      var result = arr.Distinct();

(5) 生成类   Range,Repeat   代码如下:

      //生成类—–静态类

       var result = System.Linq.Enumerable.Range(10, 50);

       var result = System.Linq.Enumerable.Range(‘a’, 50); //生成连续的序列

       var result = System.Linq.Enumerable.Repeat(40, 10);

       result.Print();

  1. 生成类查询方法小结

注:使用生成类查询方法时,需要注意以下几点:

(1) 和其它几类方法不同,Range/Repeat不是扩展方法,而是普通的静态方法

(2) Range只能产生整数序列。

(3) Repeat可以产生泛型序列。

(4) 所有的查询方法都存放在System.Linq.Enumerable静态类中。

[转载]SQL调优日记之发挥SQL性能与你的写法有关

mikel阅读(1125)

[转载]SQL调优日记之发挥SQL性能与你的写法有关--对比三种方式实现相同功能 – 谢堂文(Darren Xie) – 博客园.

今天再次改老系统,看着前边的师兄留下的SQL,就想起了MS SQL 7.5和SQL2000。可能很多人都还没有习惯新版本(05版之后)的SQL语法,还是用以前开发MS SQL2000的方式实现功能,但是多少人会明白,换一种写法后,性能却相差十倍百倍呢!

我用来做例子的是我们MES系统用到的一段简单功能T-SQL,都是使用同一个库、相同的表、相同的逻辑:

开始前先记录时间,计算完成后看用了多少时间。

我先用推荐的语法来写的方式,代码1是好的写法,由于是在我们系统的情景下描述的,看管不可照抄,只说明性能的差别。

 

代码1:

用WITH,把各个逻辑分开处理,再终合出最后结果,推荐!

1: declare @P INT,@T DATETIME;

2: SELECT @P=1,@T=GETDATE();

3: ;WITH R0 --

4: AS (

5: SELECT TOP 1 M.WPCODE,t.RID,MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO FROM MES_WFCIO M,MES_WFCIODTL t

6: WHERE M.RID=t.RID AND WFCNO='JSAC00334D-033-001'

7: ORDER BY t.RID DESC

8: )

9: ,R1

10: AS (

11: SELECT TOP 1 M.WPCODE,t.RID,M.MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO FROM MES_WFCIO M,MES_WFCIODTL t,R0

12: WHERE M.RID=t.RID

13: AND M.MACNO=R0.MACNO

14: AND M.RID&lt;&gt;R0.RID

15: AND M.WPCODE=R0.WPCODE

16: ORDER BY t.RID DESC

17: )

18: ,R2

19: AS (

20: SELECT WO FROM R0

21: UNION

22: SELECT WO FROM R1

23: )

24: ,R3

25: AS (

26: SELECT DISTINCT MASTERNUM FROM R2,WO WHERE R2.WO=WO.WONUM

27: )

28: SELECT @P=COUNT(*) FROM R3;

29: select @P AS [計算結果1];

30: SELECT DATEDIFF(ms,@T,getdate()) as [方法1用時];

代码2:

这是2000的时候多数人用的方式,计算过程多用临时表,不推荐!

1: declare @P INT,@T DATETIME;

2: SELECT @P=1,@T=GETDATE();

3: SELECT TOP 1 M.WPCODE,t.RID,MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO

4: INTO #R0

5: FROM MES_WFCIO M,MES_WFCIODTL t

6: WHERE M.RID=t.RID AND WFCNO='JSAC00334D-033-001'

7: ORDER BY t.RID DESC;

8:

9: SELECT TOP 1 M.WPCODE,t.RID,M.MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO

10: INTO #R1

11: FROM MES_WFCIO M,MES_WFCIODTL t,#R0 R0

12: WHERE M.RID=t.RID

13: AND M.MACNO=R0.MACNO

14: AND M.RID&lt;&gt;R0.RID

15: AND M.WPCODE=R0.WPCODE

16: ORDER BY t.RID DESC;

17:

18: SELECT WO INTO #R2 FROM #R0

19: UNION

20: SELECT WO FROM #R1;

21:

22: SELECT DISTINCT MASTERNUM

23: INTO #R3

24: FROM #R2 R2,WO

25: WHERE R2.WO=WO.WONUM;

26:

27: SELECT @P=COUNT(*) FROM #R3;

28: select @P AS [計算結果2];

29: SELECT DATEDIFF(ms,@T,getdate()) as [方法2用時];

30:

31: drop table #R0,#R1,#R2,#R3;

代码3:

强逻辑人员的写法,子查询方式,不推荐!

1: declare @P INT,@T DATETIME;

2: SELECT @P=1,@T=GETDATE();

3: SELECT @P=COUNT(*)

4: FROM (SELECT DISTINCT MASTERNUM

5: FROM (SELECT WO

6: FROM (SELECT TOP 1 M.WPCODE,t.RID,MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO

7: FROM MES_WFCIO M,MES_WFCIODTL t

8: WHERE M.RID=t.RID AND WFCNO='JSAC00334D-033-001'

9: ORDER BY t.RID DESC) x

10: UNION

11: SELECT WO FROM (SELECT TOP 1 M.WPCODE,t.RID,M.MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO

12: FROM MES_WFCIO M,MES_WFCIODTL t,(SELECT TOP 1 M.WPCODE,t.RID,MACNO,LEFT(WFCNO,CHARINDEX('-',WFCNO)-1) WO

13: FROM MES_WFCIO M,MES_WFCIODTL t

14: WHERE M.RID=t.RID AND WFCNO='JSAC00334D-033-001'

15: ORDER BY t.RID DESC) R0

16: WHERE M.RID=t.RID

17: AND M.MACNO=R0.MACNO

18: AND M.RID&lt;&gt;R0.RID

19: AND M.WPCODE=R0.WPCODE

20: ORDER BY t.RID DESC)R1) R2,WO

21: WHERE R2.WO=WO.WONUM)R3;

22: select @P AS [計算結果3];

23: SELECT DATEDIFF(ms,@T,getdate()) as [方法3用時];

看看执行的结果对比:

第一种写法用时不到1毫秒;

第二种写法用时56毫秒;

第三种写法用时不到1毫秒;

image

 

 

再单独执行,代码1用了3毫秒,从Messages中看到只有两条信息,也就是只操作了两个结果表对象;

image

image

 

代码2用了63毫秒,从Messages中看到只有两条信息,也就是只操作了六个结果表对象;

image

image

 

代码3用了3毫秒,从Messages中看到只有两条信息,也就是只操作了两个结果表对象;

image

image

 

从以上的对比结果来看,用with和用子查询的方式性能差不多,但是子查询的写法代码很难维护,用WITH的方式逻辑明确,代码重用高,易维护,性 能优越;用临时表的方式逻辑也明确,但是性能差。用WITH和用子查询的方式都可以用到SQL的同时执行,用临时表就只能是按顺序执行了。

当你要对SQL进行性能调优时,除了考虑索引、统计信息、分区表、硬件升级和归档数据外,也建议考虑评估SQL的写法。

 

原创,转载请注明出处:http://www.cnblogs.com/YIYUMENG

[转载]ASP.NET MVC 让Html.RenderAction支持Lamda表达式

mikel阅读(916)

[转载][ASP.NET MVC]让Html.RenderAction支持Lamda表达式 – dudu – 博客园.

今天在ASP.NET MVC代码时用到了Html.RenderAction,代码如下:

@{Html.RenderAction("RecentNews")}

通过字符串指定Action的名称,有两点不爽:

1. 输入时不能智能感知;

2. 输错了不能实时提示。

有这两点不爽,写代码的乐趣就大减。有享受感觉的代码应该是这样的:

@{Html.RenderAction<AggSiteController>(c => c.RecentNews());}

是的,Lamda,给你写代码带来畅快感觉的Lamda!

微软不让我们享受,我们就自己动手,丰衣足食。自己写一个支持Lamda表达式的Html.RenderAction,代码如下:

using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Linq.Expressions;

namespace System.Web.Mvc.Html
{
public static class HtmlHelperExtensions
{
public static void RenderAction(this HtmlHelper htmlHelper,
Expression&gt; operation)
where TController : Controller
{
var actionName = ((MethodCallExpression)operation.Body).Method.Name;
htmlHelper.RenderAction(actionName);
}
}
}

注:其中”((MethodCallExpression)operation.Body).Method.Name”代码来自Get Method Name From Action

顺带分享一篇文章When to use Html.RenderPartial and Html.RenderAction in ASP.NET MVC Razor Views,通过这篇文章你可以清楚的知道Html.RenderPartial与Html.RenderAction之间的区别。

比如:博客园首页的最新随笔列表就适合用Html.RenderPartial,而右侧的“新闻列表”就适合用Html.RenderAction。

简单的理解就是:Html.RenderPartial用的到PartialView只用一次(虽然实际可以多次使用,但比较麻烦,每次都要传 Model),Html.RenderAction用的到PartialView被多个视图使用(有自己的Action提供Model)。

[转载]程序员的常见健康问题

mikel阅读(814)

[转载]程序员的常见健康问题.

转自:原文链接

原始出处: 英文链接

其实这些问题不仅见于程序员,其他长期经常坐在电脑前的职场人士(比如:网络编辑、站长等),都会有其中的某些健康问题。希望从事这些行业的朋友,对自己的健康问题,予以重视。以下是全文。

我最近在写《Learn Python The Hard Way》的最后几节课,我还要加一课:关于程序员在其职业生涯中普遍的健康问题。我发现诸多代码人在敲代码的时候好像不在乎他们的身体状况, 很可能是太过于全神贯注。我希望人们可以通过知晓一些与程序员相关的健康问题而获益,并可以避免曾经发生在我身上,而且就我知道也发生在很多人身上的问 题。

我可能不会把这篇博文全部放进该书里,因为有点多。但我会写个缩减版。请您惠知喜好,或有我可以引用的附加资源。

我的背景和资历

我以前是一等合格美国士兵,并学习过多种武术。近年来我未像过去学武术一样奋力工作,而是专注于瑜伽、入定和一些简单的活动。我小时候是异常健康的,现在依然如故,这归功于我早已根深蒂固的锻炼习惯。

zed shaw

首先先列一下我学过的武术:忍术(Ninjitsu),合气道(Aikido),柔术(Judo),泰拳(Muay Thai),咏春(Wing Tsung),卡波耶拉(Capoeira),阿尼斯(Arnis),其排序不分先后。我要讲只有泰拳我是连贯学习的,大概有六年时间。其他的用了一到两 年时间。我去了很多地方,因此学习之道就是那儿有什么便学什么。

而且,在部队里我是体能测试优秀,几乎是连续两年满分通过的。如没记错,这其中有几乎每天两至四小时的训练,这在部队里不算什么。除此之外,别无他事可做。

然后,不论我干不干活,我如今一直保持着同样的体重、灵敏及力量。所以我无法告诉你怎么减肥。我很可能先天基因就是如此。这意味着你要根据自身情况来调整我的建议。

有着前述的体魄,当我渐老我更喜欢侵略性弱以及更灵活的一些运动。瑜伽是不错的,常被误认为很难。我同样把票投给普拉提(Pilates),游泳,舞蹈等一切对我身体无直接影响的运动。我尤其注意我的手,缘由我也会说到。

好,写这么多是让你知道我还有点能耐,但是更重要的是,在干这些的同时,我是一个职业编程者。在退役后,我平均每天学习八到十六个小时。 我使用盲打而且玩吉他,我还避免了腕道综合征,以及重复性劳损问题。

希望我保健的经验能帮你恢复或保持健康。

程序员的常见健康问题

编程乍一看是个耗人的领域,一方面似乎你没有做很多,另外和很多代码人对待其身体的态度有关。 你要一贯地保持健康,因为身体好时会减少对精神的摩擦损害,而将注意力集中到要事上,而不是你生理上的小毛病。

显然建议就是大多人说的饮食,外出活动。我这里不会教你怎么吃或健身,或者哪种武术。如你对这些感兴趣,找一个职业的来帮助你锻炼。

这里要说的程序员们平日的职业病。他们相当明显而且平常,由于某些原因他们并不在意这些本不该发生的事情:

▲ 腕部疼痛(重复性劳损)

▲ 盯着看移动的打印进度以及其后的句点造成的眼部问题

▲ 姿势不当造成的背部不适,尤其是背下侧,肩上侧。

▲ 肠道和尿道的问题(不能正常大小便)

▲ 摄入太多咖啡因,而且喝水少造成的脱水

▲ 坐姿保持太久,造成男性的痔疮或前列腺问题(我一会再细说)

▲ 光照不足造成维生素D缺乏

▲ 熬夜或者喝咖啡过多导致的睡眠失调

▲ 缺乏伸展导致普遍的僵硬和疼痛

我一直跟这些问题作抗争,因为编程,弹吉他,或者举重时误伤。每当我重获健康的时候,我就知道了此后怎样避免。只有一小部分问题是周期性的。你可能觉得这里的某些问题无关紧要,但请相信我,许多程序员都有这样那样的问题,且原因不一,即使你还没有。

普遍原因

一般来说,可以总结成嗜编程为命。你可能想成为个中翘楚,就像我一样,因此除了生活除了编程别无其他。你不去卫生间,你勇猛地进行10小时连续编程。而且你饮食不规,只神笃“真正的代码人”这一信条。

事实是真正的编程者都是有点傻蛋。他们从来吃不到正点,ML也没有准。跑步从来都气喘吁吁,他们的内脏有一些严重问题,但不是疾病原因。真的,在你精通某件事之前,灭了自己可不是很值。

所以,在你看到这些问题以及我怎么解决的时候,记住这都是为了有一个均衡的生活习惯,而不是沉溺于编码或者其他什么事。相信我你会实实在在地好起来,如果你给你自己减负并且保持健康。

腕部疼痛

这个可能是我用心最多的。因为频繁且长时间地编码、拨弦,我的腕部有着周期性的疼痛。那年我22岁,刚开始职业性地编码。但是我一直有一个合气道的功课,这样我的腕部就会恢复如初。

你知道,合气道有着绝佳的腕部练习,从而让你的腕部变得结实又柔软。他们创造的这些练习可以避免伤害,原本的许多技巧就有扭、撕扯、手臂和肩关节的脱节。

这些练习治好了我的所有关节错位和疼痛,并让我长时间编程且没有任何大问题。我唯一可能出现问题是因为我要把现在的键盘换成新的古怪布局的键盘,但如果我练习一周合气道我就有可以重返代码并依然强健。

现在如果你有严重的腕道综合征或者其他类型的重复性劳损问题,先咨询你的医师再行尝试这里的技巧。如你要做的话,开始时要轻慢,不要让你感到疼。伸展应该不会疼,只会轻度有点不适。如果你感觉疼,是过度拉伸了。.

你实际想每次伸展运动得到放松。这有点难解释,但不是强迫你的关节在某个固定位置,而是先到达一个位置,想一想放松而后再到更远的位置。

记住这一点,怎么做练习则有很多视频:

▲ 翻转手腕 (Youtube的视频,须翻墙)

▲ 扭腕

▲ 手腕外侧弯曲

▲ 手腕内侧弯曲

下面介绍当你坐下来打字的时候怎么去做锻炼(每次都要这样):

1. 首先要热身,将手伸向前方在空中尽可能快速地抓20次。然后甩手,再做手腕单侧弯曲10次,然后换方向弯曲10次。

2. 用你最擅长的,以中速做5至10次。

3. 继续做各项动作,但甩手和甩胳膊,弯曲手腕后到要归位。这些动作会移动手腕中的骨头,甩的时候它们就会归位。

4. 千万不要做过头,让你手腕感到损伤。要适度恰好,并放松。那个“没有付出就没有收获”只会伤害你。

每次敲代码前做这系列动作,每天要做,而且停下来的时候也做一次。用不了多长时间,一段时间的不适之后你的手腕就会开始适应并回到正常,并感到好许多。

还有:在做这些之前先咨询一下医生。你做这些可是自己冒风险,所以自己不小心搞坏了手腕不要来起诉我。 这些是千年武术中的家常便饭,所以我知道它们不会有危险,但各人情况不同。如果你做法不对可能后果严重,如果感到疼痛立即停止并咨询医师。

吉他手更糟糕

在吉他手或贝司手跟前,程序员的重复性劳损可是小菜。这起因是诸多愚蠢的理由,许多著名的音乐家讲一天八小时或十六小时学习法。正因如此,吉他手们糟践自己,最后不能演奏。

吉他对于手来讲是硬乐器,所以有一点点疼痛你就歇菜了。我在学校的时候,像个傻比一样轻信我的老师自己一天练八个小时的琴。我字面理解就是一下子就八个小时,我这样折磨自己一个月然后就崩了。

我的拇指有了赘骨,其他的指头疼痛难止。我的手腕还耐得住,但指头已经不行了。 二逼呵呵的我没有听那句话,任何新的运动需要循序渐进。

我解决这个的唯一办法,而且用了一年半,是做以下的事情:

1. 找把不伤手的吉他。说你啥样吉他都能玩是屁话。去找个最好的不伤你手的吉他。

2. 做上面的锻炼,我的指头做得更多。

3. 通过做练习,慢慢开始恢复指头的力度并注意放松。

4. 在弹的时候注意放松,拨弦的时候更轻巧。

5. 避免弯曲,这些曾导致我的手受伤。

6. 变换姿势和演奏风格,不抓紧吉他就能快速移动,舒服地把拇指压在琴颈背面。

7. 调整吉他高度,让我的肩和手都觉得舒服。

8. 站着,很少长时间坐下,长时间摆一个姿势是很别扭的。

去年做完这些后我的手最终痊愈了,并且感觉良好。我还没有不让我弄伤自己的好习惯。我已经老大不小了,所以这些对我很重要,但这也意味着我不能做那些可能弄伤我手的活计。

我的手现在是我的命根子,所以不能再打拳了,或者其他我还想学习的事情。因为打沙袋我手上已经有多处凹陷了。

眼疲劳

我觉得这对我不是问题,但你最好悠着点。我年轻的时候比20/20还要好,但用了几十年电脑有点偏了,曾经用过眼镜矫正,我用得着的时候一直戴着,没有它们看周围的世界真是恼人的模糊。

在黑暗时期,我们天天还瞅的是CRT显示器,烦人的闪烁已经把一些人的眼睛整垮了。现在的问题是多数LCD屏幕对字体的糟糕渲染。 我想归功于苹果公司的专利,多数LCD屏都不能正常渲染字体。尽管有人认为苹果的字体看起来毛茸茸的,所以对于你的好处将很难说。

我想每天两个小时不看电脑。要么我去玩吉他不用费眼力,要么去公园散步。我可能不是整整两个小时都去这样干,但是加起来要保持两个小时。

这对于你可能有的头痛有助益。多数时候程序员可能会想玩电脑的时候开着灯导致了头痛,但其实是因为体位不对,还有糟糕的字体,饮水不足,而且是跟电脑打持久战。

不是把你房间的灯都关掉,只需要合理的照明,选择适合你液晶屏和室内灯光的色彩方案。 即融合室内照明,液晶屏亮度和字体,以及让你感觉更舒服的色彩方案。

但还是先休息一下吧。

背部问题

我挺走运的,背一直还可以。尽管如此,我相当多时间是坐办公室,并保持着灵活强健的脊背。

我的问题是背的上半部分,脖子,肩部。我习惯猫在键盘上,所以必须强迫自己坐直。事实是,刚刚敲这段话的时候我就没坐直,才想起矫正一下。

现在选择你的座椅很重要,我喜欢艾伦椅(Aeron),那种硬质小凳子或长凳。现在非常热衷我的40美元的钢琴凳,过去我坐着它弹钢琴的。因为没有后背,凳子会时时逼迫你坐端正 ,并调用我的核心肌肉(肚子和背部)。

我的肩部完全处于压/迫状态。我习惯于在我全神贯注的时候收紧双肩,这样让我的整个背上部感到疼痛,一直蔓延到脖子和头部。当我长时间玩吉他的时候问题更糟。

我发现最有效的解决办法是伸展上肢,做俯卧撑。伸展办法很简单,抓住门框,然后双臂同向或反向拉伸。你觉得身体有点僵硬的时候试试下面这些招数:

1. 用一只手抓紧门框,手心朝向你的身体,然后向前挺胸,越过肩位。

2. 用另一只手握紧门框,胳膊交叉在前,手心继续朝里,然后伸展肩部,使背部得到伸展。

3. 两只手都抓住门框,高举过头,稍向后站呈倾斜,然后来回拉伸。(就像站着做俯卧撑)

如果你做了,同时做抡臂,摇摆,你就会觉得好一些。或许在你开始干活之前加一些腕部伸展。

另外就是做真正的俯卧撑了。我工作的时候并不做这个,因为它会让你很累,难于工作。在睡前我做十次,这十下足以对付胸、背、肩、腕。 不要过快,要慢,注意在做的时候使身体平衡。

脱水

这个问题不大,我时常有点内疚。我发现我一天狂喝咖啡,正因为这样我想我也该喝点水。如果我没有头疼那倒有点不对。脱水的问题很难发觉,直到你发现的时候已经晚了。

我的建议(我也要多做的)是,喝其他非纯净水的饮料时也喝一杯水。同样请勿喝苏打水。它们只是一堆伪糖,让你变胖导致糖尿病,还有它并没有给你产生水。喝纯黑咖啡吧,它们真他妈好,记着再喝些水。

肠道及尿道问题

好吧,接下来的两个问题确实不雅,所以就不提发生在我身上的事了,但我要说这句话:“上厕所的时候他妈赶紧去,别犹豫。

你不知道这条提示有多有用,我真希望我年轻的时候知道这句话。因为我是一个拼命汉从不间断,跳过上厕所,憋相当长时间。 肠道问题就是你的机体不再告诉你你该拉屎了,只是愈积愈多。

这样的话最后会导致便秘,这将终结你的健康状态。对于尿道倒次要,但是你依然可能会有感染和其他令你惊奇的事情。

如果你已经搞砸了,你去弄一些纤维片,待在家里然后吃掉,不要去外面,因为后果很囧的。

然后,你觉得是时候了,拾起身去拥抱上帝吧。我告诉你,在你拉完屎之后你的伟大想法才会自然迸发。

痔疮和前列腺问题

另外一个不上厕所会导致的就是痔疮。我知道够恶心的,我保证只提这一次。但是,许多编程者有这个问题,并羞于启齿,他们并不知道为什么。下面听我一一道来,我做过下述所有事情,但是只得过一两次痔疮:

1. 长时间坐着。

2. 举重东西,不用辅助。

3. 该去解决内急的时候不去。

4. 强迫自己去拉屎,实际上不需要。

5. 最糟糕的:坐在厕所里看书。

最后一条就是罪魁祸首。如果你不是必须要大C,可别老泡在那。这相当于将你整个身体和肠子的重量压进已经泻完的直肠上,并试图挤出来。恶心至极!这导致痔疮因为你的血管中的血压不自然地升高。

确实臭哄哄的,但潜在危害很大。恩,危急情形是血流一地,这时候谁都知道去看大夫。你可能需要手术,但做无妨。我没有做但也差点:有一年我在举重,然后在库房工作,不间断编程,没有用过厕所。

是,我是个大笨蛋。你可别学我。为了你的屁屁的健康,请做以下的事:

1. 多吃果蔬,至少吃点纤维片。

2. 该解决个人问题时赶紧的!

3. 任何情况下不要压/迫直肠。

还有一个导致前列腺的问题,如果整天坐在屁股上的话。站起来转转就可以。如果尿血或者排尿困难,去看医生,否则会更危险。

维生素D不足

维生素D有点怪。的确只能通过晒太阳产生,但你并不必去专门为此去暴露在阳光下。5到30分钟就好,取决于光照的强度。还与你的钙水平和磷缺乏程度有关。但你要是饮食规律,并非只吃些薯片的话,就问题不大。

还有一些事比如消沉,搞坏的牙齿,一些奇怪部位的疼痛比如臂肘的骨头,肌肉痉挛,总体来讲就是跟烂泥一样。同样,如果你觉得不行的话去看医生,正常情况下在日头正盛的时候,去外面溜达半个小时足矣。

事实上,我觉得一个问题是硅谷里很多刚起步公司提供的餐饮。因为你要泡在办公室,经常吃残汤剩饭,而且照明也不好,太阳高照的时候你也不出去晒下。加上你的睡眠习惯你的维生素D状况就糟糕透了。

不要吃盒饭,在中午去外面吃一顿。好处你自知,而且外面的食物好多了。

我在温哥华和西雅图的时候有轻微的维生素D缺乏,那儿光照不足,对于我来说简直要我命。有人能搞定,但是像我这样青年时代在热带岛屿上度过的人,不足的光照确实就是杀手。

所以,你趁有太阳的时候出去晒晒。

睡眠失调

我的睡眠时间一向很灵活,跟季节和地域有关。有时候我如猫头鹰附体,熬夜熬到很晚才睡。最近搬到旧金山后开始早睡,不再晚睡了,最近感觉很好。

有时候,我不确定为何在夜里创作音乐或编程倒多产。我认为在一个疲惫的状态下我的大脑确是在休息的。我还觉得是因为夜里更安静,没有滋扰。

不管怎样,早睡晚睡已经把我的睡眠机制搞砸了。当我渐长我更喜欢早起,我觉得白天更清醒更放松。熬夜后再睡往往觉得自己有遗留反应,而且头疼。

如果你也有睡眠问题,我有一些简单的调适方法助你入睡。需要实践,但很有效。

首先,花你的血本买个好床,2000+美元不算多。我买了2200块的Tempur-Pedic。 的确很值。

有了床,开始练习助睡法,有点自我催眠的意味:

1. 关掉你房内的所有灯光和音响。

2. 躺下,让手放在让你舒服的位置。

3. 缓慢地深呼吸,并想象空气流进身体及逸散出体外的场景。

4. 当你能注意到你的呼吸之时,想象你在看窗外辽阔的太空,悬星满布。

5. 然后伴随呼吸幻想自己漂浮在空中,渐入巨幅的星系,一切星辰,皆伴随你左右。

6. 持续幻想,感觉你的床也在漂浮,直到皆不见。

你或许在四五点睡觉,但不是要出去的话,就幻想自己漂浮直到你真感觉融化了。

如果你有重度失眠,还请咨询医师。但还是试下这招,一天做一到两个小时。练习后绝对会让你入睡。

刚柔并济

如果浑身不适难于活动,这时就该做下伸展运动。当然最好莫过于去瑜伽馆每周做练习,并回家自己练习。如果没有时间,可以买书或在图书馆借N多教程。入门级就可以,你真的不需要太多。

我想如果你晚上入睡前做5-6个大幅的伸展练习就够了。你会觉得相当放松,你的健康状况和自我感觉也会有提升。

伸展身体的时候同样要放松大脑,增长创造性的一大妙法就是做瑜伽或半个小时的伸展运动,然后早晨冲澡。 伴随禅定你就会精神自适并发觉个中未曾体验之奥妙。

我也不知为何,但是精神之松弛对于突发的灵感多有助益。

迈出第一步

上面的内容可能对于你有点多,我当然希望你不会都有这些问题缠身。然而我建议,尽管你可能没有那些毛病,但要避免它们的发生。如果你要开始编码,请采用“编前热身”。

下面就是我在敲代码前要干的,或者玩吉他前,以及我变僵需要休息的时候。

1. 活动身体各关节,只需将腕、臂、颈、臀转摇几下。比如正向五次,然后反向五次。

2. 在各部分前做一些腕部练习,摇一下手腕。

3. 将臂举过头顶尽可能高,然后向后伸展尽可能远,然后伸到身体前面来。

4. 最后,小心地用手扶着头分别向右、左、前、后摇几下。

如果你做这些的话,将避免一些编程会带来的伤害。因为编程并不会大伤体能,避免受伤还是很容易的,因此上述部分就够了。

然而,如果有特殊问题的话,继续去咨询医疗师,如果得到他们允许可以试试我的这些方法。我这儿说的无过激或奇异的方法,只是些基本的练习和一些常识,因此是个医生都会许可的。我告诉你要咨询别人是只是因为我不想吃官司。

真希望这些能让你变好,如果没有的话,记下建议,以防出现这些状况。如果你够好运,连一个问题都不会有,但我觉得是个程序员都有或多或少的问题。

如果对上述的事情持有疑问,可以给我发邮件,我会给你一些建议。

保重。

作者Zed Shaws是一位作家、软件开发人员、音乐人(下文中提到吉他手),于2010年发布《Learn Python The Hard Way》一书,他也是 Mongrel Web 服务器系统的作者之一。

[转载]五幅图演示ASP.NET编译过程

mikel阅读(1193)

[转载]五幅图演示ASP.NET编译过程 – keepfool – 博客园.

No 1. 源代码 > 编译 > 本地代码

image

No 2. 语言编译器

image

No 3. 编译成MSIL

image

No 4. MSIL的组成(中间语言和元数据)

image

No 5. Web Application和Website的区别

image

简单概括一下:

语言编译器:无论是VB code还是C# code都会被Language Compiler转换为MSIL
MSIL的作用:MSIL包含一些元数据和中间语言指令
JIT编译器的作用:根据系统环境将MSIL中间语言指令转换为机器码

第一次运行Website时,CLR会将MSIT通过JIT进行编译,最终转换为执行速度非常快的Native Code。这也可以解释为什么ASP.NET网站第一次运行时会较慢,而后面的执行速度则会相对快很多。

本文已经同步至我的个人博客站点:积累吧|五幅图演示ASP.NET编译过程
本文PPT下载:ASP.NET编译过程

[转载]浅谈SQL Server中统计对于查询的影响

mikel阅读(1155)

[转载]浅谈SQL Server中统计对于查询的影响 – CareySon – 博客园.

简介

SQL Server查询分析器是基于开销的。通常来讲,查询分析器会根据谓词来确定该如何选择高效的查询路线,比如该选择哪个索引。而每次查询分析器寻找路径 时,并不会每一次都去统计索引中包含的行数,值的范围等,而是根据一定条件创建和更新这些信息后保存到数据库中,这也就是所谓的统计信息。

如何查看统计信息

查看SQL Server的统计信息非常简单,使用如下指令:

DBCC SHOW_STATISTICS(‘表名’,’索引名’)

所得到的结果如图1所示。

1

图1.统计信息

统计信息如何影响查询

下面我们通过一个简单的例子来看统计信息是如何影响查询分析器。我建立一个测试表,有两个INT值的列,其中id为自增,ref上建立非聚集索引,插入100条数据,从1到100,再插入9900条等于100的数据。图1中的统计信息就是示例数据的统计信息。

此时,我where后使用ref值作为查询条件,但是给定不同的值,我们可以看出根据统计信息,查询分析器做出了不同的选择,如图2所示。

3

图2.根据不同的谓词,查询优化器做了不同的选择

其实,对于查询分析器来说,柱状图对于直接可以确定的谓词非常管用,这些谓词比如:

where date = getdate()
where id= 12345
where monthly_sales < 10000 / 12
where name like “Careyson” + “%”

但是对于比如

where price = @vari
where total_sales > (select sum(qty) from sales)
where a.id =b.ref_id

where col1 =1 and col2=2

这类在运行时才能知道值的查询,采样步长就明显不是那么好用了。另外,上面第四行如果谓词是两个查询条件,使用采样步长也并不好用。因为无论索引有多少列,采样步长仅仅存储索引的第一列。当柱状图不再好用时,SQL Server使用密度来确定最佳的查询路线。

密度的公式是:1/表中唯一值的 个数。当密度越小时,索引越容易被选中。比如图1中的第二个表,我们可以通过如下公式来计算一下密度:

4

图3.某一列的密度

根据公式可以推断,当表中的数据量逐渐增大时,密度会越来越小。

对于那些不能根据采样步长做出选择的查询,查询分析器使用密度来估计行数,这个公式为:估计的行数=表中的行数*密度

那么,根据这个公式,如果我做查询时,估计的行数就会为如图4所示的数字。

5

图4.估计的行数

我们来验证一下这个结论,如图5所示。

6

图5.估计的行数

因此,可以看出,估计的行数是和实际的行数有出入的,当数据分布均匀时,或者数据量大时,这个误差将会变的非常小。

统计信息的更新

由上面的例子可以看到,查询分析器由于依赖于统计信息进行查询,那么过时的统计信息则可能导致低效率的查询。统计信息既可以由SQL Server来进行管理,也可以手动进行更新,也可以由SQL Server管理更新时手动更新。

当开启了自动更新后,SQL Server监控表中的数据更改,当达到临界值时则会自动更新数据。这个标准是:

  •     向空表插入数据时
  •     少于500行的表增加500行或者更多
  •     当表中行多于500行时,数据的变化量大于20%时

上述条件的满足均会导致统计被更新。

当然,我们也可以使用如下语句手动更新统计信息。

UPDATE STATISTICS 表名[索引名]

列级统计信息

SQL Server还可以针对不属于任何索引的列创建统计信息来帮助查询分析器获取”估计的行数“.当我们开启数据库级别的选项“自动创建统计信息”如图6所示。

7

图6.自动创建统计信息

当这个选项设置为True时,当我们where谓词指定了不在任何索引上的列时,列的统计信息会被创建,但是会有以下两种情况例外:

  •     创建统计信息的成本超过生成查询计划的成本
  •     当SQL Server忙时不会自动生成统计信息

我们可以通过系统视图sys.stats来查看这些统计信息,如图7所示。

8

图7.通过系统视图查看统计信息

当然,也可以通过如下语句手动创建统计信息:

CREATE STATISTICS 统计名称 ON 表名 (列名 [,…n])

总结

本文简单谈了统计信息对于查询路径选择的影响。过时的统计信息很容易造成查询性能的降低。因此,定期更新统计信息是DBA重要的工作之一。

[转载]世界上第一本交互式时间管理电子书-时间管理

mikel阅读(937)

[转载]世界上第一本交互式时间管理电子书-时间管理-时间管理行动家.

3d59c74ejw1dsnezfcppzj

我在这次的杭州时间管理研习会上发布了这本交互式时间管理教科书,大家都觉得很酷~我也一样  :)

回到西安之后立刻写这篇文章和大家分享!

关于这本书

我打算制作三本时间管理教科书,分别是:

  1. 《邮件狂人》
  2. 《手机控》
  3. 《笔纸达人》

分别介绍如何用邮件、用手机、用笔纸管理好自己的行动(GTD方法)

这次放出的是第一本:《邮件狂人》,这种方法适合于想要管理好每天50+邮件的人~

制作方法当然是用iBook author了,苹果提供的这个工具真的很酷!!

可是因为著作权的关系,目前发现中国区上传的电子书不能被中国区下载,其他区域的账号可以,我不太清楚解决的方法,所以只能把电子书放在网站和网盘上提供下载,如果您知道解决的办法,欢迎用最下面的邮箱联系我,谢谢。

如何下载与阅读

对系统的要求:

  1. ibook2+iOS5
  2. iPad

阅读方法:

  1. 下载电子书
  2. 拖入到iPad里
  3. 打开ibook阅读

电子书下载地址(共300M):

  1. 我的博客
  2. 115网盘

这里有视频可以预览:

http://v.youku.com/v_show/id_XMzk0MTE2NDE2.html

[转载]通过ASP.NET Web API + JQuery创建一个简单的Web应用

mikel阅读(1102)

[转载]通过ASP.NET Web API + JQuery创建一个简单的Web应用 – Artech – 博客园.

看了dudu的《HttpClient + ASP.NET Web API, WCF之外的另一个选择》一文,想起多很久之前体现ASP.NET Web API而创建的一个Demo。这是一个只涉及到简单CRUD操作的Web应用,业务逻辑以Web API的形式定义并以服务的形式发布出来,前台通过JQuery处理用户交互并调用后台服务。[源代码从这里下载]

目录
一、一个简单的基于CRUD
二、通过ASP.NET Web API提供服务
三、通过JQuery消费服务

一、一个简单的基于CRUD的Web应用

这个简单的Demo应用用于模拟“联系人管理”。当页面加载的时候,所有的联系人列表被列出来。在同一个页面中,我们可以添加一个新的联系人,也可以修改和删除现有联系人信息。整个应用唯一的页面在浏览器中的呈现效果如下图所示。

image

二、通过ASP.NET Web API提供服务

我们来简单介绍作为Web API形式发布的联系人管理服务的定义,先来看看用于表示联系人的Contact类型的定义。

1: public class Contact

2: {

3: public string Id { get; set; }

4: public string FirstName { get; set; }

5: public string LastName { get; set; }

6: public string PhoneNo { get; set; }

7: public string EmailAddress { get; set; }

8: }

“联系人服务”以具有如下定义的ContactController的形式定义,它是ApiController的子类。简单起见,我们采用静态字段作为对联系人信息的存储。ContactController定义了Get、Put、Post和Delete用于进行对联系人的获取、添加、修改和删除操作。我想对Web API不了解的人会感概,为了什么采用常用的四个HTTP方法作为操作的名称,因为它们在默认的情况下就可以映射为HTTP请求的方法。

1: public class ContactController : ApiController

2: {

3: private static Listcontacts = new List

4: {

5: new Contact{ Id="001", FirstName = "San", LastName="Zhang", PhoneNo="123", EmailAddress="zhangsan@gmail.com"},

6: new Contact{ Id="002",FirstName = "Si", LastName="Li", PhoneNo="456", EmailAddress="lisi@gmail.com"}

7: };

8:

9: public IEnumerableGet()

10: {

11: return contacts;

12: }

13:

14: public Contact Get(string id)

15: {

16: return contacts.FirstOrDefault(c =&gt; c.Id == id);

17: }

18:

19: public void Put(Contact contact)

20: {

21: if (string.IsNullOrEmpty(contact.Id))

22: {

23: contact.Id = Guid.NewGuid().ToString();

24: }

25: contacts.Add(contact);

26: }

27:

28: public void Post(Contact contact)

29: {

30: Delete(contact.Id);

31: contacts.Add(contact);

32: }

33:

34: public void Delete(string id)

35: {

36: Contact contact = contacts.FirstOrDefault(c =&gt; c.Id == id);

37: contacts.Remove(contact);

38: }

39: }

ASP.NET MVC Web应用一样,我们同样采用URL路由机制来实现请求地址与目标Controller和Action的映射,而针对API默认注册的路有如下所示。

1: public class MvcApplication : System.Web.HttpApplication

2: {

3: //...

4: public static void RegisterRoutes(RouteCollection routes)

5: {

6: //...

7: routes.MapHttpRoute(

8: name: "DefaultApi",

9: routeTemplate: "api/{controller}/{id}",

10: defaults: new { id = RouteParameter.Optional }

11: );

12: }

按照注册的路由规则和Action方法名称与HTTP方法的默认影射机制,我们可以直接在浏览器中分别访问地址“/api/contact”和“/api/contact/001”得到所有联系人列表和ID为“001”的联系人信息。得到的结果如下图所示。

image

三、通过JQuery消费服务

我们通过ASP.NET MVC来构建Web应用,默认的HomeController定义如下,默认的Index操作仅仅是将默认的View呈现出来而已。

   1: public class HomeController : Controller

   2: {

   3:     public ActionResult Index()

   4:     {

   5:         return View();

   6:     }

   7: }

View中对用户操作的相应和对后台服务的调用都通过jQuery来完成,整个View的定义如下所示。

   1: <script type="text/javascript">

   1:  

   2:     $(function () {

   3:         loadAllContacts();

   4:        }

   5:      )

   6:  

   7:     function loadAllContacts() {

   8:         $.ajax({

   9:             url     : "api/contact",

  10:             type    : "GET",

  11:             dataType: "json",

  12:             success : function (data) { renderContactList(data) }

  13:            }

  14:         );        

  15:     }

  16:  

  17:     function renderContactList(contacts) {

  18:         var html = "<table>";

  19:         html += "<tr><th>First Name</th><th>Last Name</th><th>Phone No.</th><th>Email Address</th><th></th></tr>";

  20:         for (i = 0; i < contacts.length; i++) {

  21:             html += "<tr><td>" + contacts[i].FirstName + "</td><td>"

  22:                  + contacts[i].LastName + "</td><td>" + contacts[i].PhoneNo + "</td><td>"

  23:                  + "<input type=\"text\" class=\"textbox long\" id=\"" + contacts[i].Id + "\" value =\"" + contacts[i].EmailAddress + "\"/>" + "</td><td>"

  24:                  + "<a href=\"#\" onclick = \"updateContact('" + contacts[i].Id + "')\">Update</a> &nbsp;&nbsp;&nbsp;&nbsp;"

  25:                  + "<a href=\"#\" onclick = \"deleteContact('" + contacts[i].Id + "')\">Delete</a>" + "</td></tr>";

  26:         }

  27:         html += "<tr><td>" + "<input id=\"firstName\" type=\"text\" class=\"textbox\"/>" + "</td><td>"

  28:             + "<input id=\"lastName\" type=\"text\" class=\"textbox\"/>" + "</td><td>"

  29:             + "<input id=\"phoneNo\" type=\"text\" class=\"textbox\"/>" + "</td><td>"

  30:             + "<input id=\"emailAddress\" type=\"text\" class=\"textbox long\"/>" + "</td><td>" 

  31:             + "<a href=\"#\" id=\"add\" onclick=\"addContact();\">Create</a> " + "</td></tr>";

  32:         html += "</table>";

  33:         $("#contacts").html(html);

  34:         $("table tr:odd").addClass("oddRow");

  35:     }

  36:  

  37:     function deleteContact(id) {

  38:         $.ajax({

  39:             url     : "api/contact/" + id,

  40:             type    : "DELETE",

  41:             success : function () { loadAllContacts();}

  42:         });

  43:     }

  44:  

  45:     function updateContact(id) {

  46:         var emailAddress = $("#" +id).attr("value");

  47:         $.ajax({

  48:             url     : "api/contact/" + id,

  49:             type    : "GET",

  50:             success : function (contact) {

  51:                 contact.EmailAddress = emailAddress;

  52:                 update(contact);

  53:             }

  54:         });

  55:     }

  56:  

  57:     function update(contact) {

  58:         $.ajax({

  59:             url         : "api/contact/",

  60:             type        : "POST",

  61:             data        : contact,

  62:             contentType : "application/json",

  63:             success     : function () { loadAllContacts(); }

  64:         });

  65:     }

  66:  

  67:     function addContact() {

  68:         var contact = new Object();

  69:         contact.FirstName       = $("#firstName").attr("value");

  70:         contact.LastName        = $("#lastName").attr("value");

  71:         contact.PhoneNo         = $("#phoneNo").attr("value");

  72:         contact.EmailAddress    = $("#emailAddress").attr("value");

  73:         $.ajax({

  74:             url         : "api/contact/",

  75:             type        : "PUT",

  76:             data        : contact,

  77:             contentType : "application/json",

  78:             success     : function () { loadAllContacts(); }

  79:         });

  80:     }

</script>

   2: <div id="contacts"></div>

[转载]译 命名有意义的版本号2.0.0

mikel阅读(986)

[转载][译] 命名有意义的版本号2.0.0-rc1 – yaoxing – 博客园.

原文链接:http://semver.org/

在软件管理的世界里有一个可怕的地方叫“依赖地狱(dependency hell)”。你的系统越是成长壮大,你越是整合更多的软件包到你自己的系统中,你越有可能在将来的某天发现自己已经掉进了这个绝望的深渊。

在一个有着众多依赖的系统里,发布新版本可能很快成为一个恶梦。如果依赖定义得过于紧密,你就有可能进入版本锁定(version lock)的状态(版本锁定是指一旦更新一个软件包,就不得不更新其他所有依赖于它的包)。如果依赖定义得过于松散,你又难免会被版本穿插 (version promiscuity)所伤(让人以为会与多得不合理的未来版本兼容)。当你被版本锁定或版本穿插所阻挠而不能容易地让你的项目顺利前进时,你就身处依 赖地狱中了。

作为这个问题的解决方案之一,我提议用一组简单的规则和要求来约束版本号的分配和增长规则。为了让这套理论运作,你必须预先定义好自己的公共 API。这可以通过文档定义或代码强制要求来实现。无论如何,这套API的清楚明了是十分重要的。一旦你定义了公共API,你就可以通过修改相应的版本号 来通知大家你的修改。考虑使用这样的版本号格式:X.Y.Z(主版本号,次版本号,补丁版本号)修复Bug但不影响API时增长补丁版本号;API保持向 下兼容的增加/修改时增长次版本号;进行不向下兼容的修改时增长主版本号。

我把这套规则称为“语义版本命名(Semantic Versioning)”。在这套工作模式下,版本号和它们的增长模式就会传达从当前版本向下一个版本进行了怎样的修改。

语义版本(SemVer)命名规范

在篇文章里出现的关键字“必须”,“必须不”,“要求”,“应该”,“不应该”,“一定要”,“一定不要”,“推荐”,“可以”和“可选”将在RFC2119中描述和解释。(以下译文中原样使用这些关键字看上去会比较生硬,但为了清楚地传达作者的意图和保持RFC2119关键字的意义,仍然照这里的翻译来使用——译者注)

  1. 使用语义版本命名的软件系统必须定义一套公共API。这套API可以是在代码中申明或是用严格的文档定义。不管怎样做,它都应该清楚明了。
  2. 正常的版本号必须使用X.Y.Z的形式并且X/Y/Z是非负整数。X是主版本号,Y是次版本号,Z是补丁版本号。版本号每次必须只能增长1。例如:1.9.0->1.10.0->1.11.0。
  3. 当主版本号增长时,次版本号和补丁版本号必须清零。当次版本号增长时,补丁版本号必须清零。例如:1.1.9->2.0.0,2.1.7->2.2.0。
  4. 一旦发布了具有版本的包,那个版本的内容必须不能再更改。任何修改必须发布成一个新版本。
  5. 主版本号0 (0.y.z)是用来进行初始开发时使用的。任何东西都可能在任何时候改变。公共API此时应该被认为是经常变动的。
  6. 版本1.0.0开始定义公共API。这个版本及以后的版本号的增长方式将依赖于公共API以及它如何变化。
  7. 如果有任何向下兼容的bug修复发生,补丁版本号Z (x.y.Z | x > 0)必须增长1。“bug修复”被定义为内部进行的修复非正常行为的修复工作。
  8. 如果进行了新的并且向下兼容的公共API添加和修改,次版本号Y (x.Y.z | x > 0)必须增长1。如果任何公共API被标记为“过期”,次版本号必须增长1;如果有大量的新功能或改进在内部代码中发生,次版本号可以增长1;这其中也可以包含补丁级别的修改。当次版本号增长时补丁版本号必须清零。
  9. 如果对公共API有任何向下不兼容的修改,主版本号X (X.y.z | X > 0)必须增长1。这其中也可以包含次版本和补丁版本级别的修改。当主版本号增长时次版本号和补丁版本号必须清零。
  10. 预览版本(pre-release version)可以通过在补丁版本号后追加中横线以及由点分隔开的一系列标识来表达。标识必须由ASCII字符和中横线[0-9A-Za-z-]组成。预览版本能满足相关版本的要求,但优先级低于相关版本。例如:1.0.0-alpha,1.0.0-alpha.2,1.0.0-0.3.7,1.0.0-x.7.z.92。
  11. 构建版本(build version)可以通过在补丁版本号或预览版本后追加一个加号和一系列由点分隔标识来表达。标识必须由ASCII字符和中横线[0-9A-Za-z-]组成。构建版本能够满足相关版本的要求,并且优先于相关版本。例如:1.0.0+build.1,1.3.7+build.11.e0f985a。
  12. 将版本号分为主版本号、次版本号、补丁版本号,预览版本,构建版本,必须按这样的按顺序分别逐级考虑来确定版本顺序。主版本号、次版本号,补丁版本号总是通过数字大小来确定顺序。预览版本和构建版本的顺序必须由 比较由点分隔标识来确定,规则如下:如果标识只有数字,则由数字大小决定;如果标识包含字符和中横线,则由比较字符的字典顺序来确定。数字标识的顺序永远 低于非数字标识。例如:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 < 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a。

为什么使用语义版本命名?

这并不是一个全新的革命性的想法。事实上,你可能已经做了和这差不多的事情了。问题是“差不多”还不够好。如果不服从某种正式的规范,版本号对于版 本依赖管理就失去了本质上的意义。通过给以上的想法一个清楚的定义和命名,与你的软件用户沟通你的意图就变得容易了。一旦这些意图明确表达出来,灵活(但 不是过于灵活)的依赖定义就可以最终被制定出来。

一个简单的例子可以演示语义版本命名如何让版本地狱成为过去。考虑有一个库叫做“救火车”。它需要一个语义版本命名的包“云梯”。当救火车被制造的 时候,云梯的版本是3.1.0。因为救火车一开始使用了由云梯3.1.0提供的某些功能,你可以安全地知道对云梯的正确依赖是在3.1.0以后并且 4.0.0之前。现在,当云梯版本3.1.1和3.2.0发布时,你就可以把它们放到你的软件包管理系统中并且知道它们会与依赖它的软件兼容。

作为一个有责任的开发人员,你当然一定会想要确保所有软件包更新都被广而告之。现实世界是一个混乱的地方,除了提高警惕我们别无他法。你所能做的是 让语义版本命名为你提供一个健全的方式来发布版本更新软件包,而不必更新所有的依赖软件包,这将会节省你的时间,少为你添麻烦。

如果这些听起来让你满意的话,你所需要对语义版本命名做的事情就是:申明你正在使用它并且按它的要求办事。在你的README文档中链接到这个网站,让其他人知道这些规则并且从中受益。

FAQ

【内容太多,过两天再补】

关于

语义版本命名规范由Tom Preston-Werner提出,他是Gravatars的创始人和GitHub的合作创始人。

如果你想留下一些反馈,请在GitHub提交一个新的问题

License

Creative Commons – CC BY 3.0 http://creativecommons.org/licenses/by/3.0/