[转载]一篇讲述ASP.NET运行原理的很好的文章

mikel阅读(1218)

[转贴]原贴地址http://www.cnblogs.com/Heroman/archive/2005/05/12/153975.aspx

首先先感谢 菩提本非树

这一章是全书基础和精神所在,其后的例子章节是为了验证这章的讲述和实践讲述的内容
其 中第一节是讲述ASP.NET运行模式,这一节着眼于整个ASP.NET应用程序的运作模式,实际上,并不是在讲组件,但是却很重要,因为写组件的人必须 清楚的知道ASP.NET应用程序是如何启动.如何处理请求,如何处理SESSION等这些细节问题的,但这一节对于一般读者来讲,可能十分晦涩.下面的 讲解可能有助于你理解这一切.
一个ASP.NET的应用程序是开始于IIS的.
当你请求一个包含ASP.NET应用的网址时,IIS接受到请求(IIS是WEB服务守候进程),IIS收到请求后,会根据请求者请求的主机头或者IP或者端口号来找到对应的站点.
当 找到站点后,如果你请求的资源是以ASPX为结尾的WEBFORM,时,IIS会将控制权交给一个ISAPI扩展.,名叫 AspNet_ISAIP.DLL.这时,控制权由IIS交到ASPNET的ISAPI扩展上.,需要说明的是,ISAPI扩展的级别低于IIS,但高于 用户站点,它独立于站点之外
ISAPI收到处理请求后,会启动一个ASP.NET工作进程.然后将请求者 的请求信息转交给ASP.NET工作进程(名为ASPNET_WP.EXE).接下来,控制权由ASPNET_WP掌握.ASPNET_WP首先解出请求 者的信息,如果请求者请求的ASP.NET应用程序(站点或虚拟目录,通俗一点)尚未拥有APPDOMAIN,ASPNET_WP就会建立一个 APPDOMAIN,并且将被请求的ASP.NET应用所需的Assembly(就是那些DLL,例如System.Web.DLL等)载入到 APPDOMAIN中
以上的步骤可以看到一个结论和规律:控制权是以流水式在各个请求处理者间传递,并且,前一个处理请求者必须负责传递后一个处理请求者所需的信息.而且要负责装载或初始化后一个处理者,这很像我们生活中的接力赛.
问 题是,可能有许多人会问:干嘛要如此繁琐呢?直接由IIS把请求转交给ASPNET_WP如何呢?不是不可以,而是如此一来,这个处理过程的可扩展性就变 低了.ASPNET ISAPI是IIS和ASPNET_WP之间的桥梁.虽然看起来它仅仅负责转交请求等工作.可是这样一来,就大大扩展延展性.
另 外一个疑问是关于APPDOMAIN的,包括我,对于APPDOMAIN一开始的理解就曾陷入误区,APPDOMAIN这东东微软讲的也比较含糊,有人说 跟进程一样,但我一开始理解成了IIS里的应用程序池,所以,走了不少弯路,实际上,APPDOMAIN既不是进程,也不是IIS里的应用程序池概 念..NET下的所有应用程序都运行于APPDOMAIN之中(我自己的理解),每一个APPDOMAIN是一个执行的容器,每执行一个应用程序或者 ASP.NET应用,.NET执行环境就会建立一个APPDOMAIN,然后把应用程序需要的一些DLL载入.APPDOMAIN的功能很像进程,但绝不 是进程.你可以这样理解,APPDOMAIN就是ASP.NET应用程序的执行环境吧.
AspNet_WP 不光负责建立APPDOMAIN(当然,如果已经存在的话,就直接使用这个DOMAIN了),另外,它在APPDOMAIN建立后,还会将请求转发至对应 的APPDOMAIN中的ISAPIRuntime对象。(Isapiruntime对象是APPDOMAIN的一部分)。ISAPIRUNTIME专门 负责解出请求的必要信息。它将信息和请求转交给HttpRuntime。在这里,需要说明的是IsapiRuntime是一个类,它的全称是 System.Web.Hosting.ISAPIRuntime,而HttpRuntime也是一个类,它的全称是 System.Web.HttpRuntime。因此,可以说,这两个对象是APPDOMAIN运行环境的一部分,在ASPNET_WP建立 APPDOMAIN的同时,也会作为运行环境来建立这两个对象.
由于接二连三的讲述了几个对象,所以,当 我第一遍看这本书特别是看到这部分时,觉得特别晕,因为第一对.NET FRAMEWORK的类库不甚了解,第二,对ASP.NET的运行原理初次接触.摸不着头脑,总想把这些对象名称与某个DLL或者某个实际上的文件来对 应.其实不然,不管是ISAPIRuntime也好,还是HttpRuntime,它们在APPDOMAIN建立时,作为APPDOMAIN的一部分被实 例化.所以它们代表的是内存中的一个类的实例,也就是对象.并且,这上面的一部分运作原理,似乎跟ASP.NET应用程序没有直接联系.似乎不入正题,很 容易让初看者不知所云.实际上,可以说,由IIS到ISAPI是完成了请求的第一个部,也就是接纳客户请求.由ISAPI到APPDOMAIN,是第二部 分,也就是初始化部分,旨在建立处理请求的大环境,为下面处理请求和运行ASP.NET应用程序作好准备.
接 下来,当APPDOMAIN初始化完成后,接下来就需要建立会话了吧,因此,请求由HttpRuntime来接受,HttpRunTime主要的工作便是 为每一个提出请求的客户建立一个HttpContext对象.这个东东又管理着HttpSession对象.每一个访问者有各自的HttpContext 对象和HttpSession对象,这些对象,你可以在.NET FRAMEWORK库中找到对应的类名,像System.Web.HttpContext,System.Web.HttpSessionState等.
可以看出,请求的处理过程非常类似于.NET中事件模型的处理过程.若干个处理模块被串接到一个事件上.在ASP.NET运行原理里,也是,若干个模块依次轮流处理一个请求,像流水线操作一样.
另外,作为组件开发者,还要明确一个HttpRuntime,HttpContext,HttpSession这些对象的层次关系和调用创建关系.细节部分无需了解,只要知道谁创建了谁,谁被谁调用即可
HttpRuntime负责创建HttpContext和HttpSession,httpContext负责管理httpSession
到HttpRuntime创建完httpContext为止,实际上,你的应用程序仍然没有运行,或者说,请求者的请求实际上并未真正的被处理,前面的工作都是些准备性或者辅助性的工作.
HttpRuntime除了创建上面的对象外,还要创建HttpApplication.至于创建Application对象的过程,是比较复杂的.你可以把其作为一个分支流程涉略一下
接下来,HttpApplication调用ProcessRequest方法来处理用户请求,此方法会调用对应的HttpHandler来处理用户请求,HttpHandler根据用户请求的文件的扩展名处理请求,并把请求的结果,也就是HTML发送到客户浏览器
另 外,过程的复杂性远远超出了上面的描述,基本上,黄先生这本书的第三章第一节用了十几页文本在描述ASP.NET运行过程及原理,以及处理请求时用的一些 手法,但总体上的过程如上面的描述那样,只不过,我没有将建立各种对象时的细节剥离出来展示给大家.黄先生原著上的这节内容实际上非常详细.但为何大家看 起来均言吃力呢?一方面是因为原理部分一向比较麻烦,另外一方面,是因为黄先生在讲述时,没有先向大家概要的描述过程和纲领,然后再描述细节,再是直接把 细节和纲领融合在一起.这样,如果看的时候,没有去将这节的各个小标题和内容串联起来并先总结出纲领来的话.看完后,就会头晕.实际上,整个讲述就是在描 述ASP.NET处理请求的过程.如果隐藏所有技术性的细节,而只讲流程的话,大家可能很快理解.然后再将流程中的每一部分的技术细节展现出来,我想,容 易理解的多.这好比讲故事,先将故事梗概说一下比较好吧.
当然,我不是说黄先生写的不好,实际上,这一节写的很透彻,看懂了,就很受用.流程是很重要的,它的重要性在于你知道了在何时发生何事,就可以在指定的时间点做一些处理.这一点,在黄先生本书以后的章节中讲述ASP.NET PAGE对象执行流程中更显重要.
下面的图对整个ASP.NET应用运行过程中的各个对象的职能以及流程做了图解.当然,图解抛弃了技术性的细节,例如,像HttpApplication如何建立等

[转载]模拟谷歌今日使用的css动画

mikel阅读(946)

[转载]模拟谷歌今日使用的css动画 – 胡尐睿丶 – 博客园.

不知道大家有没有注意到谷歌今天官网上的logo,刚开始一看还以为是gif,在仔细一看,发现并非如此,原来是使用CSS Sprite技术,利用一个初始图片和一张画满各个动作的拼接图片,从而实现了动画效果。

本人一时手痒,就想把这个扒下来,但发现谷歌的js写的太牛逼了,无奈,只能自己用自己的思维去模拟一个了。首先,需要两张图,分别是:

当有这两张图后,我们就可以开始模拟了。

我先通过firebug观察,发现google首页在运行的时候会循环加载以下html代码:

<div id="hplogo0" style="left:307px;top:48px;width:88px;height:89px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll 0px 0px transparent;"></div>
<div id="hplogo1" style="left:307px;top:48px;width:89px;height:89px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -88px 0px transparent;"></div>
<div id="hplogo2" style="left:307px;top:48px;width:91px;height:89px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -177px 0px transparent;"></div>
<div id="hplogo3" style="left:305px;top:49px;width:93px;height:89px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -268px 0px transparent;"></div>
<div id="hplogo4" style="left:305px;top:50px;width:93px;height:88px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -361px 0px transparent;"></div>
<div id="hplogo5" style="left:305px;top:50px;width:93px;height:88px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -454px 0px transparent;"></div>
<div id="hplogo6" style="left:306px;top:52px;width:92px;height:86px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -547px 0px transparent;"></div>
<div id="hplogo7" style="left:305px;top:53px;width:93px;height:84px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -639px 0px transparent;"></div>
<div id="hplogo8" style="left:305px;top:54px;width:94px;height:83px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -732px 0px transparent;"></div>
<div id="hplogo9" style="left:306px;top:54px;width:93px;height:83px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -826px 0px transparent;"></div>
<div id="hplogo10" style="left:307px;top:54px;width:92px;height:83px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -919px 0px transparent;"></div>
<div id="hplogo11" style="left:307px;top:54px;width:92px;height:83px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -1011px 0px transparent;"></div>
<div id="hplogo12" style="left:308px;top:54px;width:90px;height:83px;background:url(http://www.google.com.hk/logos/2011/graham11-hp-sprite.png) no-repeat scroll -1103px 0px transparent;"></div>
...
...

  实际上这就是实现动画效果的因素,但我发现,我可以循环生成,但是我无法循环生成每个div里的样式,因为样式的宽高、偏移像素都是无规律的,所以我的做法就是,把谷歌生成好的代码复制过来,然后默认全部隐藏,然后循环让其显示出来。

  原理就是这样,js的实现也更为简单,所以我就没用JQuery,以下是js实现代码:

var i=0;
window.setInterval(google,83);
function google(){
if(i<=154){ var logo = document.getElementById("hplogo"+i); logo.style.display = 'block'; } i++; } [/js]   大功告成,看下demo吧。 现代舞先驱玛莎·葛兰姆 117 周年诞辰   顺便把源码也附上吧,没太多技术含量,如果有问题,希望赐教。源码下载   附1:后来我发现google原来是把坐标等信息存在js数组里,然后循环添加div元素的时候,把值一并写进去,相关阅读《喜欢今天的Google LOGO 玛莎·葛兰姆》   附2:补充知识   Google今日涂鸦是为了纪念现代舞先驱玛莎·葛兰姆(Martha Graham,1894年5月11日-1991年4月1日)117周年诞辰,他是美国舞蹈家和编舞家,也是现代舞蹈史的创始人之一。其作品多以美国人文或是希腊古典神话为主题,代表作有《原始的神秘》(Primitive Mysteries,1936年)、《给世界的信》(Letter to the World,1940年)、《阿帕拉契山脈之春》 (Appalachian Spring,1944年)、《夜旅》(Night Journey,1947年)。

[转载]android使用Activity

mikel阅读(958)

[转载]android使用Activity – skyme – 博客园.

第一个例子,显示网址

首先创建工程

按照提示填入

我使用的是2.3版本,所以Min SDK Version填10

修改/res/layout/下main.xml文件

加入按钮

对应的程序文件如下:

<button></button>

这样就在页面上绘制了一个按钮,然后给按钮添加事件,就是点击后做什么

我的类信息是ActivityUse,这个类继承自Activity

文件中程序如下:

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

submit_data_tonewactivity();

}

private void submit_data_tonewactivity() {
Button button_start_browser = (Button) findViewById(R.id.submit_to_net);

button_start_browser.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
Uri myUri = Uri.parse("http://www.baidu.com");
Intent openBrowseIntent = new Intent(Intent.ACTION_VIEW, myUri);
startActivity(openBrowseIntent);
}
});

}

看这几句

Uri myUri = Uri.parse(“http://www.baidu.com“);
Intent openBrowseIntent = new Intent(Intent.ACTION_VIEW, myUri);
startActivity(openBrowseIntent);

Intent是用于多个Activity之间进行跳转的,Activity可以理解成web开发中的form.

程序调用浏览器,显示网址。

第二个例子,跳转页面并提交数据

用刚才建好的工程

复制一个main.xml并且更名为welcome.xml

配置界面如下,并且在main.xml中加入文本框和登陆按钮

welcome.xml中设置如下,需要对应修改配置属性 并在main.xml中加入如下设置


<!--?xml version="1.0" encoding="utf-8"?-->
<button></button>


<button></button>
<button></button>
<button></button>

Activity,需要在AndroidManifest.xml中添加设置


Welcome.java类

public class Welcome extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome);
Bundle myBundleForGetName = this.getIntent().getExtras();
String name = myBundleForGetName.getString("key_name");
final EditText resultName = (EditText) findViewById(R.id.logintext);
resultName.setText("欢迎你" + name);
click_button();
}

private void click_button() {
final Button btnExit = (Button) findViewById(R.id.btnexit);
btnExit.setOnClickListener(btnexit_listener);
}
//返回到main页
private Button.OnClickListener btnexit_listener = new Button.OnClickListener() {
public void onClick(View v) {
Intent main = new Intent();
main.setClass(Welcome.this, ActivityUse.class);
startActivity(main);
}
};

}
private void submit_data_tonewactivity() {
final EditText inName = (EditText) findViewById(R.id.name);
final TextView result = (TextView) findViewById(R.id.result);
Button button_start_browser = (Button) findViewById(R.id.submit_to_net);
Button button_login = (Button) findViewById(R.id.show_login);
Button button_showLoginName = (Button) findViewById(R.id.submit_to_showloginname);

button_start_browser.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
Uri myUri = Uri.parse("http://www.baidu.com");
Intent openBrowseIntent = new Intent(Intent.ACTION_VIEW, myUri);
startActivity(openBrowseIntent);
}
});

button_login.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
// 接受数据
Intent openWelcomeActivityIntent = new Intent();
Bundle myBundelForName = new Bundle();
myBundelForName.putString("key_name", inName.getText()
.toString());
openWelcomeActivityIntent.putExtras(myBundelForName);
openWelcomeActivityIntent.setClass(ActivityUse.this,
Welcome.class);
startActivity(openWelcomeActivityIntent);
}
});

button_showLoginName.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
result.setText(inName.getText() + "欢迎您进入......");
}
});
}

注意这几句

// 接受数据
Intent openWelcomeActivityIntent = new Intent();
Bundle myBundelForName = new Bundle();
myBundelForName.putString(“key_name”, inName.getText()
.toString());
openWelcomeActivityIntent.putExtras(myBundelForName);
openWelcomeActivityIntent.setClass(ActivityUse.this,
Welcome.class);
startActivity(openWelcomeActivityIntent);

新用到了Bundle,这个是在对个Activity之间传递数据用的,这个例子中将信息放入的方法是putExtras

在接受端,即Welcome.java中

  Bundle myBundleForGetName = this.getIntent().getExtras();
String name = myBundleForGetName.getString(“key_name”);
final EditText resultName = (EditText) findViewById(R.id.logintext);
resultName.setText(“欢迎你” + name);

接收数据并显示,同样的方法可以传递多个值

页面样例如下:

输入111,点击登陆



跳转后的页面如下:



点击退出可以返回原页面



第三个例子,跳转页面并且得到返回值

还是用刚才的工程

加入login.xml,和Login.java文件

并在AndroidManifest.xml指定



添加的登陆页面效果

使用的是TableLayout



login.xml中信息

<!--?xml version="1.0" encoding="utf-8"?-->



<button></button>
<button></button>

Login.java中信息

public class Login extends Activity {

/*
* (non-Javadoc)
*
* @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.login);

Button btnLogin = (Button) findViewById(R.id.btnLogin);
Button btnExit = (Button) findViewById(R.id.btnExit);

// 取值
final EditText etName = (EditText) this.findViewById(R.id.tname);
final EditText etPass = (EditText) this.findViewById(R.id.tpass);

btnLogin.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
Intent backIntent = new Intent();
Bundle stringBundle = new Bundle();
stringBundle.putString("loginName", etName.getText().toString());
stringBundle.putString("logPass", etPass.getText().toString());
backIntent.putExtras(stringBundle);
setResult(RESULT_OK, backIntent);
finish();
}
});

btnExit.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
Intent backIntent = new Intent();
setResult(RESULT_CANCELED, backIntent);
finish();
}
});
}

}

修改main.xml,增加 同时修改ActivityUse.java,并且加入get_returnvalue();函数 接受返回值通过重写

<button></button>
private void get_returnvalue() {
Button btnReturn = (Button) findViewById(R.id.btnReturn);
tv = (TextView) this.findViewById(R.id.textViewReturn);

btnReturn.setOnClickListener(new OnClickListener() {

public void onClick(View v) {
Intent toNextInt = new Intent();
toNextInt.setClass(ActivityUse.this, Login.class);
startActivityForResult(toNextInt, REQUESR_ASK);
}
});
}

/*
* 通过重载这个方法,得到返回的结果 requestCode 开启请求Intent时对应的请求码 resultCode 返回的结果验证码 data
* 返回的Intent
*
* @see android.app.Activity#onActivityResult(int, int,
* android.content.Intent)
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUESR_ASK) {
if (resultCode == RESULT_CANCELED) {
setTitle("cancel......");
} else if (resultCode == RESULT_OK) {
showBundle = data.getExtras();// 得到返回的包
name = showBundle.getString("loginName");
pass = showBundle.getString("logPass");
tv.setText("您的用户名是 " + name + " 您的密码是 " + pass);
}
}
}

需要在ActivityUse中加入,这个是设置请求,REQUESR_ASK可以设定任何值

  Intent toNextInt = new Intent();
toNextInt.setClass(ActivityUse.this, Login.class);
startActivityForResult(toNextInt, REQUESR_ASK);

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)

在login.java端可以取值并返回

Intent backIntent = new Intent();
Bundle stringBundle = new Bundle();
stringBundle.putString(“loginName”, etName.getText().toString());
stringBundle.putString(“logPass”, etPass.getText().toString());
backIntent.putExtras(stringBundle);
setResult(RESULT_OK, backIntent);

Run一下看下结果

点击“得到返回的数据”按钮



输入信息并点击登陆



返回的结果为刚才输入的结果。

[转载]用SQL SERVER 2005新提供的命令实现行列转换

mikel阅读(990)

[转载]用SQL SERVER 2005新提供的命令实现行列转换 – 空空儿 – 博客园.

昨天一朋友问我一个问题,需要将一张表里指定的编号(2-4个),按照名称统计编号的数量,仅有一个编号数据的不显示。
模拟表结构如下:

CREATE TABLE TEMP
(
    ID        INT IDENTITY(1,1),
    T_ID    INT,
    T_NAME    NVARCHAR(5)
)
INSERT TEMP    SELECT 1,'A'
UNION ALL    SELECT 2,'B'
UNION ALL    SELECT 3,'C'
UNION ALL    SELECT 4,'D'
UNION ALL    SELECT 1,'C'
UNION ALL    SELECT 4,'B'
UNION ALL    SELECT 4,'C'
UNION ALL    SELECT 2,'A'

实际应得到的数据为:

T_ID1       T_ID2       T_ID3       T_ID4       T_NAME
----------- ----------- ----------- ----------- ------
1           1           0           0           A
0           1           0           1           B
1           0           1           1           C

因为编号是给出的,那么得想办法得到符合条件的T_NAME,这样的话需要根据 T_ID和T_NAME分组数据然后将有多个编号的数据过滤出来,这里需要将结果集自连一下,这里使用SQL SERVER 2005 提供了一个新的语法 CTE(COMMON TABLE EXPRESSION)公共表表达式,不用创建临时表,并且可以进行JOIN操作,遗憾的是必须紧跟着使用,在后面的语句就不能用了.用CTE实现这个功能:

WITH _TEMP AS
(
    SELECT T_ID,T_NAME FROM TEMP WHERE T_ID IN (1,2,3,4) GROUP BY T_ID,T_NAME
) 
SELECT DISTINCT _TEMP.T_NAME FROM _TEMP JOIN _TEMP TEMP_TEMP
    ON _TEMP.T_NAME=TEMP_TEMP.T_NAME WHERE _TEMP.T_ID<>TEMP_TEMP.T_ID

查询的数据为:

T_NAME
------
A
B
C

这样符合条件的T_NAME数据就取出来了,现在定义一个变量,将这个数据组合起来作为条件去取出符合条件的数据:

DECLARE @NAMES NVARCHAR(20) 
SET @NAMES = '';
WITH _TEMP AS
(
    SELECT T_ID,T_NAME FROM TEMP WHERE T_ID IN (1,2,3,4) GROUP BY T_ID,T_NAME
) 
SELECT @NAMES = @NAMES + '''' + _TEMP.T_NAME + ''',' FROM _TEMP JOIN _TEMP TEMP_TEMP
    ON _TEMP.T_NAME=TEMP_TEMP.T_NAME WHERE _TEMP.T_ID<>TEMP_TEMP.T_ID
SET @NAMES = LEFT(@NAMES,LEN(@NAMES)-1)
EXEC('SELECT T_ID,T_NAME FROM TEMP WHERE T_ID IN (1,2,3,4) AND T_NAME IN ('+@NAMES+')')
--查询出的数据为:
T_ID        T_NAME
----------- ------
1           A
2           B
3           C
1           C
4           B
4           C
2           A

现在需要做的事情就是按T_NAME统计T_ID并实现行列转换,在SQL 2005之前的版本可能需要些CASE语块,如果列数不确定的话就更麻烦了,现在SQL 2005提供了 PIVOT 运算符来实现行列转换,完整的SQL语句:

DECLARE @NAMES NVARCHAR(20) 
SET @NAMES = '';
WITH _TEMP AS
(
    SELECT T_ID,T_NAME FROM TEMP WHERE T_ID IN (1,2,3,4) GROUP BY T_ID,T_NAME
) 
SELECT @NAMES = @NAMES + '''' + _TEMP.T_NAME + ''',' FROM _TEMP JOIN _TEMP TEMP_TEMP
    ON _TEMP.T_NAME=TEMP_TEMP.T_NAME WHERE _TEMP.T_ID<>TEMP_TEMP.T_ID
SET @NAMES = LEFT(@NAMES,LEN(@NAMES)-1)
DECLARE @EXEC_SQL VARCHAR(1000)
SET @EXEC_SQL =('SELECT [1][T_ID1],[2][T_ID2],[3][T_ID3],[4][T_ID4],T_NAME FROM
(SELECT T_ID,T_NAME FROM TEMP WHERE T_ID IN (1,2,3,4) AND T_NAME IN ('+@NAMES+'))G
PIVOT
(
    COUNT(T_ID) 
    FOR T_ID IN ([1],[2],[3],[4])
)P')
EXEC( @EXEC_SQL)

因为符合条件的T_NAME不会很多,所以这里使用 IN 运算符,并用SQL 2005 的一些新特性实现要求。
另一种实现方法不使用CTE,使用表自连抓取数据然后再使用PIVOT 运算符来实现行列转换:

SELECT [1][T_ID1],[2][T_ID2],[3][T_ID3],[4][T_ID4],T_NAME FROM 
(SELECT MAIN.T_ID,TEMP.T_NAME FROM TEMP MAIN JOIN TEMP ON MAIN.T_NAME=TEMP.T_NAME
WHERE MAIN.T_ID IN (1,2,3,4) AND TEMP.T_ID IN (1,2,3,4) AND MAIN.T_ID<>TEMP.T_ID
GROUP BY MAIN.ID,MAIN.T_ID,TEMP.T_NAME)G
PIVOT
(
    COUNT(T_ID) 
    FOR T_ID IN ([1],[2],[3],[4])
)P

发送过去后,在真实环境(一百二十多万条数据)执行了下,速度还是很快的。

[转载]SQL Server2008:FOR XML PATH 语句的应用

mikel阅读(895)

[转载]DianPing IT » Blog Archive » FOR XML PATH 语句的应用.

大家都知道在SQL Server中利用 FOR XML PATH 语句能够把查询的数据生成XML数据,下面是它的一些应用示例。

DECLARE @TempTable table(UserID int , UserName nvarchar(50));
insert into @TempTable (UserID,UserName) values (1,'a')
insert into @TempTable (UserID,UserName) values (2,'b')
 
select UserID,UserName from @TempTable FOR XML PATH

运行这段脚本,将生成如下结果:

<row>
  <UserID>1</UserID>
  <UserName>a</UserName>
</row>
<row>
  <UserID>2</UserID>
  <UserName>b</UserName>
</row>

大家可以看到两行数据生成了两个节点,修改一下PATH的参数:

select UserID,UserName from @TempTable FOR XML PATH('lzy')

再次运行上述脚本,将生成如下的结果:

<lzy>
  <UserID>1</UserID>
  <UserName>a</UserName>
</lzy>
<lzy>
  <UserID>2</UserID>
  <UserName>b</UserName>
</lzy>

可以看到节点变成,其实PATH() 括号内的参数是控制节点名称的,这样的话大家可以看一下如果是空字符串(不是没有参数)会是什么结果?

select UserID,UserName from @TempTable FOR XML PATH('')

执行上面这段脚本将生成结果:

<UserID>1</UserID>
<UserName>a</UserName>
<UserID>2</UserID>
<UserName>b</UserName>

这样就不显示上级节点了,大家知道在 PATH 模式中,列名或列别名被作为 XPath 表达式来处理,也就是说,是列的名字,这样大胆试验一下不给指定列名和别名会是怎么样?

select CAST(UserID AS varchar) + '',UserName + '' from @TempTable FOR XML PATH('')

运行上面这句将生成结果

1a2b
大家现在明白了吧,可以通过控制参数来生成自己想要的结果,例如:

select '{' + CAST(UserID AS varchar) + ',','"' +UserName + '"','}' from @TempTable FOR XML PATH('')

生成结果

{1,”a”}{2,”b”}

还可以生成其他格式,大家可以根据自己需要的格式进行组合。

下面是一个数据统计的应用,希望大家可以通过下面的实例想到更多的应用

DECLARE @T1 table(UserID int , UserName nvarchar(50),CityName nvarchar(50));
insert into @T1 (UserID,UserName,CityName) values (1,'a','上海')
insert into @T1 (UserID,UserName,CityName) values (2,'b','北京')
insert into @T1 (UserID,UserName,CityName) values (3,'c','上海')
insert into @T1 (UserID,UserName,CityName) values (4,'d','北京')
insert into @T1 (UserID,UserName,CityName) values (5,'e','上海')
 
SELECT B.CityName,LEFT(UserList,LEN(UserList)-1) FROM (
SELECT CityName,
    (SELECT UserName+',' FROM @T1 WHERE CityName=A.CityName  FOR XML PATH('')) AS UserList
FROM @T1 A
GROUP BY CityName
) B

生成结果(每个城市的用户名)

北京 b,d
上海 a,c,e

[转载]ASP.NET MVC3.0 入门指南 5 从控制器访问模型数据

mikel阅读(870)

[转载]ASP.NET MVC3.0 入门指南 5 从控制器访问模型数据 – cn_大斌哥 – 博客园.

从控制器访问模型数据

本节,您将创建一个新的MoviesController类并编写代码读取电影数据

并用视图模板在浏览器中显示他们。在继续前,请确保您的应用程序被编

译。

右键Controllers文件夹新建一个MoviesController控制器。选择下面的

选项:

  • Controller name: MoviesController. (默认. )
  • Template: Controller with read/write actions and views, using Entity Framework.
  • Model class: Movie (MvcMovie.Models).
  • Data context class: MovieDBContext (MvcMovie.Models).
  • Views: Razor (CSHTML). (默认.)

单击“Add”。Visual Studio创建了下面的文件夹和文件:

  • 在项目的Controller文件夹下MoviesController.cs文件
  • 在项目的View文件夹下Movies文件夹
  • 在新创建的文件夹Views\MoviesCreate.cshtml, Delete.cshtml,
    Details.cshtml, Edit.cshtml, and Index.cshtml。

ASP.NET MVC 3架构机制自动创建CRUD(create, read, update, and delete)

响应方法和视图。您现在拥有了全部的web应用程序的功能,支持增加、显示、

编辑、删除电影作品。

运行应用程序并通过在浏览器地址栏中URL后追加/Movies来浏览Movies控制器。

因为应用程序依托默认的路由(在Global.asax文件中定义),浏览请求

http://localhost:xxxxx/Movies被路由到Movies控制器的默认方法Index。

换句话说,http://localhost:xxxxx/Movies实际上和http://localhost:xxxxx/Movies/Index

是一样的。因为您还没有添加任何东西,所以电影列表是空的。

创建电影

选择“Create New”链接。输入一个电影的详细信息然后单击“Create”按钮。

单击“Create”按钮使页面回发到服务器端(那里的电影信息

保存在数据库中)。您别重定向到/Movies URL,在列表里您

能看到刚被添加的电影信息。

创建一些电影作品,测试全部的功能,编辑、明细、删除。

审视代码

打开Controllers\MoviesController.cs文件并审视生成的Index方法

代码。部分控制器Index方法的代码如下所示:

public class MoviesController : Controller
{
    private MovieDBContext db = new MovieDBContext();

    //
    // GET: /Movies/

    public ViewResult Index()
    {
        return View(db.Movies.ToList());
    }
}

如前面所述,下面的行在MoviesController类中实例化了一个电影

数据库的内容。

private MovieDBContext db = new MovieDBContext();

Movies控制器返回数据库中的所有电影资料实体并把结果传递给Index

视图。

强类型模型和@model关键字

在教程的前面部分,您了解了如何使用ViewBag对象把数据通过控制器

传递给视图。ViewBag是一个动态对象,提供了方便的迟绑定方式将信

息传递给视图。

ASP.NET MVC也支持传递强类型数据给视图模板。这种强类型的方式支

持编译时检查代码和丰富的智能感知。我们将在MoviesController类

Index.cshtml视图模板中采用这种方式。

请注意该代码创建一个List对象时调用Index方法中View助手方法。代码

通过控制器传递电影列表给视图:

public ViewResult Index()
{
    return View(db.Movies.ToList());
}

通过在视图模板文件的顶部包含@model表达式,您可以指定在视图中 您期望使用的对象类型。当您创建电影控制器的时候,Visual Studio自 动在视图模板文件Index.cshtml的顶部包含@model表达式:

@model IEnumerable.Models.Movie

@model指令允许您访问由控制器使用强类型Model对象传递给 视图的电影列表。比如,Index.cshtml模板,代码通过foreach表 达式遍历了基于强类型的电影资料。

@foreach (var item in Model) {

            @Html.DisplayFor(modelItem => item.Title)

            @Html.DisplayFor(modelItem => item.ReleaseDate)

            @Html.DisplayFor(modelItem => item.Genre)

            @Html.DisplayFor(modelItem => item.Price)

            @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })

}

由于实体对象是强类型(被用作可枚举对象),循环中的每个item对象

都是强类型的Movie。其他好处指的是编译时检查代码和全部的智能感知

支持。

使用SQL SERVER精简版

实体框架代码优先(Entity Framework Code First)检测到数据库连接字符串

指向Movies数据库的不存在,所以代码优先自动创建数据库。您可以通过查看

App_Data文件夹来验证它被创建。如果您没有看到Movies.sdf文件,在解决方案

资源管理器的工具栏中单击显示“所有文件”按钮,单击“刷新”按钮,然后展开

App_Data文件夹。

双击Movies.sdf文件打开服务器资源管理器。然后展开Table文件夹,

您可以看到被创建的表。

注意:如果您双击Movies.sdf文件时报错,请确保您已经安装了

SQLServer Compact 4.0(运行时+工具支持)。如果您现在安装,您

不得不关闭在重新打开visual studio。

有两个表,一个对应Movie实体集,(EdmMetadata)一个用来存储实体和

数据库之间映射关系的对应版本。EdmMetadata表被用来检测实体和数据库

是否同步。

右键Movies表,选择编辑表结构。

注意Movies表结构和Movie类对应。实体框架代码优先(Entity Framework Code First)

依据Movie类自动创建这个结构。

完成时,关闭链接。(如果不关闭链接,您下次运行这个项目的时候可能会得到一个错误)

您现在拥有了数据库并通过简单的列表展现了他们。在下一节里,我们将审视剩下的

代码并增加一个SearchIndex查找方法和一个SearchIndex视图允许您查找数据

库中的电影资料。

下一节:ASP.NET MVC3.0 入门指南 6 审视编辑方法和视图

微笑

原文网址:http://www.asp.net/mvc/tutorials/getting-started-with-mvc3-part5-cs

[原创]关于Iframe中使用thickbox调用parent.tb_remove()方法无效的解决办法

mikel阅读(997)

最近在网站开发过程中,涉及到thickbox弹出选择商品对话框然后添加到购物清单,并关闭弹出框的功能,因为后台是iframe框架结构,代码如下:


上方是导航nav,左侧是菜单menu,右侧才是操作区域,要实现的弹出thickbox框的操作是在右侧iframe中进行的,首先利用按钮弹出thickbox层,代码如下:

function Search() {
//tb_init("search");
tb_show("搜索结果", "/goods/search?width=800&amp;telOrder=1&amp;keyType=" + $("#keyType").val() + "&amp;keywords=" + encodeURI($("#keywords").val()), null);

}

然后search.aspx页面中选中checkbox的click事件,异步提交商品信息到后台保存,然后关闭当前层,代码如下:

function AddToOrder(id) {
if($("#"+id).attr("checked")) {
//alert($("#" + id).attr("checked"));
$.post("/order/addtoorder", { goodsId: id }, function(data) {
//alert(data);
parent.tb_remove(); //注意这里是错误的,因为iframe的原因parent获取的是整个窗口,而不是当前的iframe中的页面
}, "json");

}
}

注意:parent.tb_remove();这句是不能关闭当前窗口的,因为当前页面是在iframe中,parent获取的是整个窗口,需要再调用右侧iframe才是真正的thickbox的parent页面

改成如下代码,可以成功关闭thickbox:

parent.frames[2].tb_remove();

[转载]非常棒的Web标准学习资源推荐

mikel阅读(822)

[转载]非常棒的Web标准学习资源推荐 – 梦想天空(山边小溪) – 博客园.

Web标准,或者说是网站标准,不是一种单一的标准规范,而是由一些规范共同组成的 标准集合,是由W3C和其它的标准化组织共同制定,用来创建和解释基于Web的内容。这些规范是专门为了那些在网上发布的可向后兼容的文档所设计,使其能 够被大多数人所访问。近年来,这个术语也时常和一套建立网站的标准化的最佳实践方法、网页设计的原理、以及上述方法的衍生物连系在一起。这篇文章向大家推 荐一些非常棒的Web标准化学习资源。

Web 标准和可访问性学习资源

World Wide Web Consortium (W3C)

Web Standards Project

Web Accessibility in Mind

学习教程、参考指南和社区论坛

W3Schools

JavaScript Kit

The JQuery Project

HTML5 Demos

HTML5 Reset

Web Safe Font Tester

Web Style Guide

960 Grid System

HTML/XHTML 代码在线验证工具

W3C Markup Validator

W3C Link Checker

W3C Log Validator

WDG HTML Validator

CSS 代码在线验证工具

W3C CSS Validator

Browser compatibility verification

Browershots

Browser Cam

(编译来源:梦想天空 原文来自:Important Web Standards Resources For Developers

[转载]发个免费的搜群软件

mikel阅读(821)

[转载]发个免费的搜群软件 – hackren – 博客园.

最近急需个搜群的软件,网上的功能都不尽人意,要么最大支持30页,要么就需要验证码。我只是急用一下而已,向群里200多同行求助,希望能给我个使下,竟然没一个人说话。大家在谈论技术、苍井空、MT时都那么活跃,每到谈到共享源码时都鸦雀无声了。

用了半夜时间写了这个软件,希望对需要的人有所帮助!

搜群小妖精使用说明

本程序运行基于.net framework 2.0. 如打开程序报错,请安装.net framework 2.0。

本程序基于webqq3.0开发,使用完全免费。

程序功能:

1、支持多帐号轮换

2、支持单个关键词大批量搜群

3、不依赖浏览器,节省内存开销

4、支持单线程和多线程切换。

5、支持挂机操作

6、可按页码搜索

7、可选多种格式导出群

8、程序永久免费,无广告,无弹窗,无插件

注意:

挂机操作请尽量导入本地小号操作。

如不能自动拨号,请按如下步骤设置宽带连接:

控制面板-网络连接-宽带连接-右键属性-选项-把“提示名称密码和证书等”前面的勾 勾掉
这是本程序首个版本,难免出现bug。

如您对本程序有改进建议,请给我发Email
Email:hackren@vip.qq.com blog:http://hackren.cnblogs.com

下载地址:http://www.gokuai.com/f/2O0ixlF83eu6kRex

下图 使用迅雷或旋风之类的下载软件下载,然后改为RAR文件 即为软件压缩包

[转载]WordPress精美免费主题分享系列全集

mikel阅读(875)

[转载]WordPress精美免费主题分享系列全集 – 山边小溪 – 博客园.

WordPress 是最流行的博客系统,插件众多,易于扩充功能。安装和使用都非常方便,而且有许多第三方开发的免费模板,安装方式简单易用。今天推出系列文章与大家分享142款精美的WordPress免费主题。
WordPress免费精美主题分享系列之简洁风格篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress免费精美主题分享系列之艺术风格篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress免费精美主题分享系列之朴素风格篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress精美免费主题分享系列之杂志风格篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress精美免费主题分享系列之新闻风格篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress精美免费主题分享系列之作品集风格篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress精美免费主题分享系列之游戏风格篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress精美免费主题分享系列之商业风格篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress精美免费主题分享系列之电子商务篇

instantShift: 140+ Brilliant Free WordPress Themes Around
WordPress精美免费主题分享系列之终结篇

instantShift: 140+ Brilliant Free WordPress Themes Around