[转载]C# 序列化与反序列化几种格式的转换 - 深山居士 - 博客园

mikel阅读(971)

[转载]C# 序列化与反序列化几种格式的转换 – 深山居士 – 博客园.

这里介绍了几种方式之间的序列化与反序列化之间的转换

首先介绍的如何序列化,将object对象序列化常见的两种方式即string和xml对象;

第一种将object转换为string对象,这种比较简单没有什么可谈的;

 

 public string ScriptSerialize<T>(T t)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            return serializer.Serialize(t);
        }

第二种将object转换为xml对象:

public string ScriptSerializeToXML<T>(T t)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            MemoryStream mem = new MemoryStream();
            XmlTextWriter writer = new XmlTextWriter(mem,Encoding.UTF8);
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("","");
            serializer.Serialize(writer,t,ns);
            writer.Close();
            return Encoding.UTF8.GetString(mem.ToArray());
        }

下面我主要讲string对象反序列化为对应的对象;

一、将string对象反序列化为object对象

public T ScriptDeserialize<T>(string strJson)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            return serializer.Deserialize<T>(strJson);
        }

二、将string对象反序列化为list对象

 public List<T> JSONStringToList<T>(string strJson)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            List<T> objList = serializer.Deserialize<List<T>>(strJson);
            return objList;
        }

三、将string对象反序列化为datatable对象

public DataTable JSONStringToDataTable<T>(string strJson)
        {
            DataTable dt = new DataTable();
            if (strJson.IndexOf("[") > -1)//如果大于则strJson存放了多个model对象
            {
                strJson = strJson.Remove(strJson.Length - 1, 1).Remove(0, 1).Replace("},{", "};{");
            }
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            string[] items = strJson.Split(';');

            foreach (PropertyInfo property in typeof(T).GetProperties())//通过反射获得T类型的所有属性
            {
                DataColumn col = new DataColumn(property.Name,property.PropertyType);
                dt.Columns.Add(col);
            }
            //循环 一个一个的反序列化
            for (int i = 0; i < items.Length; i++)
            {
                DataRow dr = dt.NewRow();
                //反序列化为一个T类型对象
                T temp = serializer.Deserialize<T>(items[i]);
                foreach (PropertyInfo property in typeof(T).GetProperties())
                {
                    dr[property.Name] = property.GetValue(temp,null);
                }
                dt.Rows.Add(dr);
            }
            return dt;
        }

四、将xml对象反序列化为object对象

public T JSONXMLToObject<T>(string strJson)
        {
            XmlDocument xdoc = new XmlDocument();
            try
            {
                xdoc.LoadXml(strJson);
                XmlNodeReader reader = new XmlNodeReader(xdoc.DocumentElement);
                XmlSerializer ser = new XmlSerializer(typeof(T));
                object obj = ser.Deserialize(reader);
                return (T)obj;
            }
            catch
            {
                return default(T);
            }
        }

现在用具体的实例来如何调用他们呢?特别要注意的是将xml对象反序列化objcet对象

 public class LoginObject
    {
          public string Account { get; set;}
          public string Password { get; set;}
     }
LoginObject loginObject = new LoginObject { Account = account, Password = password };
             ExTools.Manage.Class.CScriptSerialize Serialize = new Class.CScriptSerialize();
             //将object对象转换为string
              string strJson=Serialize.ScriptSerialize(loginObject);
           
             //将object对象转换为xml对象
             string strJson = Serialize.ScriptSerializeToXML(loginObject);
            
 
             //转换为list对象
              List<LoginObject> list = Serialize.JSONStringToList<LoginObject>(strJson);
             //将一个xml对象转换为object对象
            strJson = strJson.Substring(1, strJson.Length - 1);
             loginObject = Serialize.JSONXMLToObject<LoginObject>(strJson);
             //将字符串转换为dataTable
             DataTable dt = Serialize.JSONStringToDataTable<LoginObject>(strJson);
             //将字符串转换为object对象
             loginObject = Serialize.ScriptDeserialize<LoginObject>(strJson);

[转载]C#中的Json的序列化和反序列化 - chen110xi - 博客园

mikel阅读(1425)

[转载]C#中的Json的序列化和反序列化 – chen110xi – 博客园.

Json是一种通用的数据格式,我们在数据交换的时候,经常会用到,下面介绍C#中的 json序列化和反序列化,当然也可用在ASP.NET,silverlight,wpf中。我们在下面实例讲解如何进行Json的序列化和反序列化,本 文介绍两种方案,.net 3.5原生Json操作和Json.net中的Json操作。

首先,我们先建立一个测试对象,用来序列化和反序列化。

 

public class Person

{

public int ID { get; set; }

public string Name { get; set; }

public int Age { get; set; }

public DateTime BirthDay { get; set; }

}

第 一种,利用.Net Framework 3.5中原生的Json操作类库,特点就是不需要导入第三方类库,比较方便,速度上一般,而且需要.Net Framework的支持,我们知道现在还有很多服务器没有升级到.Net Framework 3.5,就用不了这个了。

首先导入下面类库,并加入下面代码
System.ServiceModel
System.ServiceModel.Web

 

class Program

{

static void Main(string[] args)

{

//创建测试对象

Person p = new Person();

p.ID = 1;

p.Name = "张三";

p.Age = 20;

p.BirthDay = DateTime.Now.AddYears(-20);

//将对象转化成Json字符串

DataContractJsonSerializer ds = new DataContractJsonSerializer(typeof(Person));

using (MemoryStream ms = new MemoryStream())

{

ds.WriteObject(ms, p);

string output = Encoding.UTF8.GetString(ms.ToArray());

Console.WriteLine(output);

}

}

}

输出结果

这个是.Net Framework 3.5原生的序列化方式,接着,我们介绍反序列化方式,还是同样的加入下面代码

 

class Program

{

static void Main(string[] args)

{

//创建测试对象

Person p = new Person();

p.ID = 1;

p.Name = "张三";

p.Age = 20;

p.BirthDay = DateTime.Now.AddYears(-20);

//将对象转化成Json字符串

string output = string.Empty;

DataContractJsonSerializer ds = new DataContractJsonSerializer(typeof(Person));

using (MemoryStream ms = new MemoryStream())

{

ds.WriteObject(ms, p);

output = Encoding.UTF8.GetString(ms.ToArray());

}

//将Json字符串转化成对象

DataContractJsonSerializer outDs = new DataContractJsonSerializer(typeof(Person));

using (MemoryStream outMs = new MemoryStream(Encoding.UTF8.GetBytes(output)))

{

Person outPerson = outDs.ReadObject(outMs) as Person;

Console.WriteLine("ID:" + outPerson.ID);

Console.WriteLine("Name:" + outPerson.Name);

Console.WriteLine("Age:" + outPerson.Age);

Console.WriteLine("Birthday:" + outPerson.BirthDay);

}

}

}

输出结果

我 们从.Net Framework 3.5原生的Json序列化及反序列化方式中,可以看出,还是相当麻烦的。很多网友也会问如果是.Net Framework 2.0该怎么办呢?下面,我们介绍一个第三方的Json序列化和反序列化类库,来完成上面操作,这个类库是有.Net Framework 2.0的版本的哦,而且这个类库还可以支持xml的序列化和反序列化操作(本文不做讲解)。下面看操作。

 

class Program

{

static void Main(string[] args)

{

//创建测试对象

Person p = new Person();

p.ID = 1;

p.Name = "张三";

p.Age = 20;

p.BirthDay = DateTime.Now.AddYears(-20);

//将对象转化成Json字符串

string output = JsonConvert.SerializeObject(p);

Console.WriteLine(output);

}

}

输出结果

这个是Json序列化方法,是不是简单了很多呢?

 

class Program

{

static void Main(string[] args)

{

//创建测试对象

Person p = new Person();

p.ID = 1;

p.Name = "张三";

p.Age = 20;

p.BirthDay = DateTime.Now.AddYears(-20);

//将对象转化成Json字符串

string output = JsonConvert.SerializeObject(p);

//将Json字符串转化成对象

Person outPerson = JsonConvert.DeserializeObject<Person>(output);

Console.WriteLine("ID:" + outPerson.ID);

Console.WriteLine("Name:" + outPerson.Name);

Console.WriteLine("Age:" + outPerson.Age);

Console.WriteLine("Birthday:" + outPerson.BirthDay);

}

}

输出结果

这个是Json反序列化方法,简单吧,而且据说这个类库的速度比.Net原生的Json序列化和反序列化方法要快很多。下载地址http://json.codeplex.com/

原创文章,转载请注明: 转载自.NET开发者

本文链接地址: c#中的Json的序列化和反序列化

文章的脚注信息由WordPress的wp-posturl插件自动生成

Related posts:

  1. Javascript中的Json序列化和反序列化
  2. JSON数据格式详解
  3. Json第三方类库Json.Net,声称超过其他Json序列化机制

[原创]ASP.NET MVC调用美图秀秀开放平台拼图实现

mikel阅读(1753)

项目中涉及到图片的美化和拼接的功能,于是用了美图秀秀开放平台的api

美图秀秀开放平台地址:http://open.web.meitu.com/

具体步骤如下:

1.创建MeiTuUpload.aspx视图页面:

页面代码:


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>图片编辑</title>
    <% List<NewTang.Models.Entity.PicInfo> pics = new List<NewTang.Models.Entity.PicInfo>();
       if (ViewData["Pics"] != null)
       {
            pics=(List<NewTang.Models.Entity.PicInfo>)ViewData["Pics"];
       }

         %>
 <script src="http://open.web.meitu.com/sources/xiuxiu.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript" >
window.onload=function(){
    xiuxiu.setFlashvars("localFileEnabled", 1);
	xiuxiu.embedSWF("altContent",2,"100%","100%");
	/*第1个参数是加载编辑器div容器,第2个参数是编辑器类型,第3个参数是div容器宽,第4个参数是div容器高*/

	xiuxiu.setUploadURL("http://localhost:4657/Components/stream.ashx"); //修改为您自己的上传接收图片程序
	xiuxiu.onInit = function ()
	{
	    <% if(pics.Count>0){ %>
		xiuxiu.loadPhoto("<%=pics[0].Path %>");
		<%} %>
	}
	xiuxiu.onUploadResponse = function (data)
	{
		 //alert("上传响应" + data);
		 parent.setfilePath(data);
		 parent.meitu.close();
	}
	xiuxiu.onClose = function() {
	    parent.meitu.close();
	}
}

    function closewbox() {

    }

    function setfilePath(data)
    {

    }
</script>
<style type="text/css">
	html, body { height:100%; overflow:hidden; }
	body { margin:0; }
</style>
</head>
<body >
<form id="upload" action="/Shop/UpLoadImage" method="post"
enctype="multipart/form-data">
<div id="altContent">

	<h1>美图秀秀</h1>
</div>
</form>
</body>
</html>

2.创建MeiTuUpload的Action
代码如下:

        /// <summary>
        /// 美图秀秀拼图
        /// </summary>
        /// <param name="newsInfoId"></param>
        /// <returns></returns>
        public ActionResult MeiTuUpload(string newsInfoId)
        {
            try
            {
                ViewData["title"] = "美图拼图";
                PicInfo pic = new PicInfo();
                pic.NewsInfoId = newsInfoId;
                ViewData["Pics"] = business.Select<PicInfo>(pic);
                //主题信息
                NewsInfo news = new NewsInfo() { NewsInfoID=newsInfoId };
                ViewData["News"] = business.Select<NewsInfo>(news);

            }
            catch (Exception e)
            {
                return new BaseController().Error("Error", "错误信息", e.Message);
            }
            return View();

        }

3.创建文件上传stream.ashx文件,可以从官方下载:备注:setUploadURL(“”) 参数为接收图片文件。php示例可参考 流式上传 或者 标准表单上传C#示例可参考 流式上传 或者 标准表单上传
代码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Configuration;
using System.IO;
using System.Drawing;
using XiuXiuWeb.XiuXiuStream;

namespace XiuXiuWeb
{
    /// <summary>
    /// Summary description for stream
    /// </summary>
    public class stream : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            //config 配置节点可以将图片保存至指定目录,未配置将保存至 /XiuXiuUpload
            //<appSettings>
            //  <add key="XiuXiuImageSavePath" value="/upload"/>
            //</appSettings>
            string name = null;
            if (context.Request.TotalBytes > 0)
            {
                XiuXiuStreamImage img = new XiuXiuStreamImage(context);
                name = img.Save();
            }
            else
            {
                name = "非法访问";
            }
            context.Response.ContentType = "text/plain";
            context.Response.Write(name);
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }

    namespace XiuXiuStream
    {

        /// <summary>
        /// 上传抽象类
        /// </summary>
        public abstract class XiuXiuImage
        {

            public String ImageUrl { get;set;}
            /// <summary>
            /// 基类保存
            /// </summary>
            /// <returns>返回保存路径+文件名</returns>
            public virtual string Save()
            {
                string fileName = this.GetFileName();
                if (null == fileName) return null;

                //string root = HttpContext.Current.Server.MapPath(path);
                string thisDate = "";
                thisDate = DateTime.Now.Year.ToString();
                if (DateTime.Now.Month < 10)
                {
                    thisDate += "0" + DateTime.Now.Month.ToString();
                }
                else
                {
                    thisDate += DateTime.Now.Month.ToString();
                }
                if (DateTime.Now.Day < 10)
                {
                    thisDate += "0" + DateTime.Now.Day.ToString();
                }
                else
                {
                    thisDate += DateTime.Now.Day.ToString();
                }
                string relativePath = System.Web.HttpContext.Current.Server.MapPath(ConfigurationSettings.AppSettings["UploadDirectory"] + "pic/" + thisDate.ToString().Replace(" ", ""));
                if (!Directory.Exists(relativePath))
                {
                    Directory.CreateDirectory(relativePath);
                }
                //if (!Directory.Exists(root))
                //{
                //    Directory.CreateDirectory(root);
                //}
                this.ImageUrl=ConfigurationSettings.AppSettings["WebSiteUrl"] + "/UploadFiles/pic/" + thisDate.ToString().Replace(" ", "") + "/" + fileName;

                this.FileName = Path.Combine(relativePath, fileName);
                string[] paths = { relativePath, fileName };
                return string.Join("/", paths);
            }

            public XiuXiuImage()
            {
                path = path == null ? "/XiuXiuUpload" : path;
            }

            /// <summary>
            /// 确定上传类型
            /// </summary>
            protected bool IsUplodType
            {
                get
                {
                    string extension = this.GetExtension();
                    return ".jpg .gif .png .icon .bmp .tiff .wmf .emf .exif".IndexOf(extension) >= 0 ? true : false;
                }
            }
            private string _fileName = null;
            /// <summary>
            /// 最终保存路径
            /// </summary>
            protected string FileName
            {
                set { _fileName = value; }
                get { return _fileName; }
            }

            /// <summary>
            /// 配置文件路径 无配置上传到XiuXiuUpload
            /// </summary>
            protected string path = ConfigurationManager.AppSettings["UploadDirectory"];

            /// <summary>
            /// 获取拓展名
            /// </summary>
            /// <returns></returns>
            protected abstract string GetExtension();

            /// <summary>
            /// 获取最终保存文件名
            /// </summary>
            /// <returns></returns>
            protected string GetFileName()
            {
                string extension = this.GetExtension();
                if (null == extension) return null;
                else
                {
                    string name = this.GetName();
                    string[] imgName = { "news", name, extension };
                    return string.Join("", imgName);
                }
            }
            /// <summary>
            /// 获取保存文件名
            /// </summary>
            /// <returns></returns>
            private string GetName()
            {
                DateTime uploadTime = DateTime.Now;
                string[] times = { uploadTime.Year.ToString(), uploadTime.Month.ToString(), uploadTime.Day.ToString(),
                                 uploadTime.Hour.ToString(), uploadTime.Millisecond.ToString(), uploadTime.Second.ToString() };
                return string.Join("", times);
            }
        }
        /// <summary>
        /// Stream接收
        /// </summary>
        public sealed class XiuXiuStreamImage : XiuXiuImage
        {
            private MemoryStream stream = null;

            //图片的url路径
            private String webPath=null;

            public XiuXiuStreamImage(HttpContext context)
            {
                int count = context.Request.TotalBytes;
                if (count > 0)
                {
                    byte[] bytes = context.Request.BinaryRead(context.Request.TotalBytes);
                    this.stream = new MemoryStream(bytes);
                }
            }

            private Image File
            {
                get
                {
                    return this.stream == null ? null : Image.FromStream(this.stream);
                }
            }
            /// <summary>
            /// 保存图片,成功返回文件路径,失败null
            /// 非图片格式返回错误信息
            /// </summary>
            /// <returns>成功返回文件路径 失败null</returns>
            public override string Save()
            {
                if (!this.IsUplodType)
                {
                    this.stream.Dispose();
                    return "Only allowed to upload pictures.";
                }
                string returnName = base.Save();
                if (this.FileName != null)
                {
                    this.File.Save(this.FileName);
                    this.stream.Dispose();
                    return ImageUrl;
                }
                return null;
            }

            protected override string GetExtension()
            {
                if (this.File != null)
                {
                    string fileExtension = this.File.RawFormat.ToString().Substring(14),
                           jpgExtension = System.Drawing.Imaging.ImageFormat.Jpeg.Guid.ToString(),
                           gifExtension = System.Drawing.Imaging.ImageFormat.Gif.Guid.ToString(),
                           pngExtension = System.Drawing.Imaging.ImageFormat.Png.Guid.ToString(),
                           iconExtension = System.Drawing.Imaging.ImageFormat.Icon.Guid.ToString(),
                           bmpExtension = System.Drawing.Imaging.ImageFormat.Bmp.Guid.ToString(),
                           tiffExtension = System.Drawing.Imaging.ImageFormat.Tiff.Guid.ToString(),
                           wmfExtension = System.Drawing.Imaging.ImageFormat.Wmf.Guid.ToString(),
                           emfExtension = System.Drawing.Imaging.ImageFormat.Emf.Guid.ToString(),
                           exifExtension = System.Drawing.Imaging.ImageFormat.Exif.Guid.ToString();
                    fileExtension = fileExtension.Substring(0, fileExtension.Length - 1);
                    if (fileExtension == jpgExtension)
                    {
                        return ".jpg";
                    }
                    else if (fileExtension == gifExtension)
                    {
                        return ".gif";
                    }
                    else if (fileExtension == pngExtension)
                    {
                        return ".png";
                    }
                    else if (fileExtension == iconExtension)
                    {
                        return ".icon";
                    }
                    else if (fileExtension == bmpExtension)
                    {
                        return ".bmp";
                    }
                    else if (fileExtension == tiffExtension)
                    {
                        return ".tiff";
                    }
                    else if (fileExtension == wmfExtension)
                    {
                        return ".wmf";
                    }
                    else if (fileExtension == emfExtension)
                    {
                        return ".emf";
                    }
                    else if (fileExtension == exifExtension)
                    {
                        return ".exif";
                    }
                }
                return null;
            }
        }
    }
}

4.调用页面,重点在这儿,官方用的是prettify.js的弹窗,我用的wbox.js的iframe加载MeiTuUpload.aspx页面来实现的调用,官方封装了个插件用于执行示例代码来动态加载美图秀秀插件,下面是代码:
页面代码:

   <tr>
    <td class="bg1" height="25" align="right">缩略图:</td>
    <td class="bg2"><img id="imgNewsInfo" src="<%=newsInfo.NewsInfoImage %>" width="220" height="200" />
   </td>
  </tr>
   <tr>
    <td class="bg1" height="25" align="right">缩略图上传:</td>
    <td class="bg2"><input type="hidden" id="filePath" name="filePath" value="<%=newsInfo.NewsInfoImage %>" /><a id="meitu" class="btngreen" href="javascript:;">拼图</a>
   </td>
  </tr>

js弹窗代码:

    var meitu = $("#meitu").wBox({ noTitle:true,title: "拼图", requestType: "iframe", iframeWH: { width: 420, height: 400 }, target: "/NewsInfoManager/MeiTuUpload?InfoClass=2&newsInfoId=<%=newsInfo.NewsInfoID %>" });
    //设置返回值的路径
    function setfilePath(data) {
        $('#filePath').val(data);
        $('#imgNewsInfo').attr('src',data);
    }

[转载]lucene .NET 搜索图片 功能实现 - searchDM - 博客园

mikel阅读(871)

[转载]lucene .NET 搜索图片 功能实现 – searchDM – 博客园.

关于搜索部分

 1想建立索引。构建jpg图片解析器,在索引时将jpg图片的exif信息及其文本信息如名称,存放路径,大小,日期等等加入索引!具体实现代码如下:

public void BulidIndex(string path)//创建索引

        {

            DateTime biStart = DateTime.Now;//创建索引开始

            DirectoryInfo[] ChildDirectory;//子目录集

            FileInfo[] files;//当前所有文件

            DirectoryInfo FatherDirectory = new DirectoryInfo(path); //当前目录

            ChildDirectory = FatherDirectory.GetDirectories(“*.*”); //得到子目录集

            files = FatherDirectory.GetFiles(“*.jpg”);//得到jpg文件集,可以进行操作

 

            Analyzer analyzer = new MyAnalyzer();//声明一个分词器,

IndexWriter indexWriter = new IndexWriter(“index”, analyzer, true);/*建立一个IndexWriter的实例,这个类是负责创建索引的,有很多构造函数,这里使用的是其中的一个。三个参数分别是:索引建立到哪个目录,用什么分词器,还有就是是否创建。如果是否创建为false,那么就是以增量的方式来创建。*/

            for (int i = 0; i < files.Length; i++)

            {

                string maker = “unkown”, explord = “unkown”,

                       iso = “unkown”, aperture = “unkown”, focalLength=“unkown”;

                Document doc = new Document();//声明一个document并将图片的名称,存放路径,大小,日期,

                                             相机制造商,曝光度,ISO,焦距,光圈值依次通过field 添加入document中。

 

                FindExifinfo(files[i].FullName, ref maker, ref explord, ref iso, ref focalLength, ref aperture);

                doc.Add(new Field(“Name”, files[i].Name, Field.Store.YES, Field.Index.TOKENIZED));

                doc.Add(new Field(“FullName”, files[i].FullName, Field.Store.YES, Field.Index.NO));

                doc.Add(new Field(“Length”, files[i].Length.ToString(), Field.Store.YES, Field.Index.NO));

                doc.Add(new Field(“LastWriteTime”, files[i].LastWriteTime.ToString(), Field.Store.YES, Field.Index.NO));

                doc.Add(new Field(“CreationTime”, files[i].CreationTime.ToString(), Field.Store.YES, Field.Index.NO));

                doc.Add(new Field(“Maker”, maker, Field.Store.YES, Field.Index.UN_TOKENIZED));

                doc.Add(new Field(“Explord”, explord, Field.Store.YES, Field.Index.UN_TOKENIZED));

                doc.Add(new Field(“ISO”, iso, Field.Store.YES, Field.Index.UN_TOKENIZED));

                doc.Add(new Field(“FocalLength”, focalLength, Field.Store.YES, Field.Index.UN_TOKENIZED));

                doc.Add(new Field(“Aperture”, aperture, Field.Store.YES, Field.Index.UN_TOKENIZED));

   indexWriter.AddDocument(doc); /*调用了AddDocument方法,在AddDocument方法中,先组织一个Docuement对象,然后把这个对象交给IndexWriter*/

 

            }

 

            indexWriter.Optimize();//Optimize优化索引           

indexWriter.Close();//最后关闭创建过程

            DateTime biStop = DateTime.Now;//创建索引结束

            this.status1.Text = 创建索引用时: + (biStop – biStart).TotalSeconds + ;

        }

2 执行搜索并获取结果:

 private void button1_Click(object sender, EventArgs e)

        {

 

            listView1.Items.Clear();

            Hits hits = null;

            Query query = null;

            Analyzer analyzer = new MyAnalyzer();

            DateTime Start = DateTime.Now;//索引开始时间

            string TEXT= this.tbkey.Text;

            BooleanQuery BQ = new BooleanQuery( );   //使用Boolean 查询  

            if (TEXT == “”)

                return;

            try

            {

              switch (this.comboBox1.SelectedIndex)

                {

                    case 0:

                        QueryParser parser = new QueryParser(“Name”, analyzer);

                        query = parser.Parse(tbkey.Text);

     

                        break;

                    case 1: //使用Boolean 查询含有某个关键词或其他关键词 should 表示“或”的关系

                        Term T2 = new Term(“Maker”, TEXT);

                        TermQuery q2 = new TermQuery(T2);

                        BQ.Add(q2, BooleanClause.Occur.SHOULD);

                        break;

                    case 2: //按照片的ISO速率进行搜索

                        Term T3 = new Term(“ISO”, TEXT);

                        TermQuery q3 = new TermQuery(T3);

                        BQ.Add(q3, BooleanClause.Occur.SHOULD);

                        break;

                    case 3: //按照片的 曝光度进行搜索

                        Term T4 = new Term(“Explord”, TEXT);

                        TermQuery q4 = new TermQuery(T4);

                        BQ.Add(q4, BooleanClause.Occur.SHOULD);

                        break;

                    case 4: //按照片的 焦距进行搜索

                        Term T5 = new Term(“FocalLength”, TEXT);

                        TermQuery q5 = new TermQuery(T5);

                        BQ.Add(q5, BooleanClause.Occur.SHOULD);

                        break;

                    case 5: //按照片的光圈进行搜索

                        Term T6 = new Term(“Aperture”, TEXT);

                        TermQuery q6 = new TermQuery(T6);

                        BQ.Add(q6, BooleanClause.Occur.SHOULD);

                        break;

                    default: break;

               

                }

            }

            catch (Exception)

            {

                throw;

            }

 

            IndexSearcher searcher = new IndexSearcher(“index”);

 

            if (searcher != null)

            {

                if( 0 == this.comboBox1.SelectedIndex) //使用if语句对搜索方式进行分类,如果是按照相片或图片名称进行搜索则进行关键字匹配查询

                    hits = searcher.Search(query);

                else

                    hits = searcher.Search(BQ); //如果不是按名称搜索,则进行严格匹配查询搜索!

 

                if (hits.Length() > 0)

                {

                    this.status1.Text = ” 共检索 + hits.Length().ToString() + 个对象;

                }

                this.imageList.Images.Clear();

                for (int i = 0; i < hits.Length(); i++)

                { //将搜索结果分别添加入listview和imagelist中,此过程比较耗时间!无奈!!!

                    Document doc = hits.Doc(i);

                    int itemNumber = this.listView1.Items.Count;

                    //string fullname = doc.Get(“FullName”);

                  string[] subItem = { doc.Get(“Name”), doc.Get(“FullName”), (Convert.ToInt32(doc.Get(“Length”)) >> 10).ToString() + “KB”, doc.Get(“LastWriteTime”) }; //使用右移 加快程序的执行速度!

                  this.imageList.Images.Add(doc.Get(“FullName”), Bitmap.FromFile(doc.Get(“FullName”)));

                  this.listView1.Items.Add(new ListViewItem(subItem, doc.Get(“FullName”)));//显示结果较慢的元凶!

                }

            }

            else

            {

                this.status1.Text = ” 共检索 0 个对象;

            }

 

            DateTime Stop = DateTime.Now;//索引完成时间

            this.status1.Text += 搜索用时: + (Stop – Start).TotalSeconds + ;

运行效果图:

版本高于所引用的程序集“System.Web.Abstractions

mikel阅读(2330)

类库编译时提示:

错误    166    程序集“xxx.Controllers.Store, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”所使用的“System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”版本高于所引用的程序集“System.Web.Abstractions, Version=0.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”的版本    f:\Tang\xxx.Controllers.Store\bin\Debug\xxx.Controllers.Store.dll    Controllers.News

需要将xxx.Controller.News的引用的System.Web.Abstractions的版本重新引用下就行了

未能加载文件或程序集“System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”错误原因是因为PublicKeyToken的值和系统的PublicKeyToken

修改成一致:

<add assembly=”System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>
<add assembly=”System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>
<add assembly=”System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>

[转载]文件上传控件第二波 - tebato - 博客园

mikel阅读(1192)

[转载]文件上传控件第二波 – tebato – 博客园.

上次分享了一款文件上传控件(网址:http://www.cnblogs.com/ushou/archive/2013/01/17/2865332.html),功能也比较多,但总觉得不够完美,经过近几天的发酵,酝酿,终于生产啦,吼吼~~~

这次的上传控件加入新的元素,比如附件列表展示、排序拖动、批量更新等。

俗话说,独乐乐不如众乐乐,现将关键代码分享。

一,首先在MVC中新建分部视图。

<link href="@Url.Content("~/Content/Uploadify/uploadify.css")" rel="stylesheet" type="text/css" />
<script type="text/JavaScript" src="@Url.Content("~/Content/Uploadify/swfobject.js")"></script>
<script type="text/JavaScript" src="@Url.Content("~/Content/Uploadify/JQuery.uploadify.v2.1.4.min.js")"></script>
<script src="@Url.Content("~/Content/zDialog/zDialog.js")" type="text/JavaScript"></script>
<script src="@Url.Content("~/Content/zDialog/zDrag.js")" type="text/javascript"></script>
<script type="text/javascript">
    $(document).ready(function () {
        $("#uploadify").uploadify({
            'uploader': '/Content/Uploadify/uploadify.swf',
            'script': '/Ashx/UploadHandler.ashx',
            'cancelImg': '/Content/Uploadify/cancel.png',
            'folder': '/UploadFile',
            'queueID': 'fileQueue',
            'multi': true,
            'auto': true,
            'fileExt': '*.jpg;*.gif;*.png',
            'fileDesc': 'Image Files (.JPG, .GIF, .PNG)',
            'queueID': 'custom-demo',
            'queueSizeLimit': 9999,
            'simUploadLimit': 9999,
            'buttonText': '选择文件',
            'removeCompleted': true,
            'onSelectOnce': function (event, data) {
            },
            'onComplete': function (event, queueId, fileObj, response, data) {                  
                AddFiles(response.split('|')[1], response.split('|')[2]);
            },
            'onAllComplete': function (event, data) {
            }
        });
    });
</script>

二:创建两个ashx文件,两个足矣,本来还想压缩到一个的,后来想想还是算了。

这两个ashx,分别拥有以下功能。

1,对数据库中的附件增、删、改、查。

关键代码如下:

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/html";
    string action = RequestExtension.GetQueryString<String>("action", "");
    if (action == "")
        return;
    MethodInfo methodInfo = this.GetType().GetMethod(action);
    if (methodInfo != null)
    {
        context.Response.Clear();
        context.Response.Write(methodInfo.Invoke(this, null));
        context.Response.End();
    }
}

这里action是传入函数名称,然后通过反射调用执行。

用法也是相当简捷:

如下示例:

修改:

$.post("/Ashx/Attachment.ashx?action=Modify", { fileID: fileID, fileName: fileName, fileDesc: fileDesc }, function (txt) {
    if (txt == "OK") {
        diag.close();
    }
    else {
        Dialog.alert(txt);
    }
}, "text");

删除:

//发送请求到服务器删除文件
var fileID = $(obj).parent().parent().attr("id");
$.post("/Ashx/Attachment.ashx?action=DelFile", { fileID: fileID }, function (txt) {
    if (txt == "OK") {
        Dialog.close();
        var p = $(obj).parent().parent();
        p.css('display', 'none');
    }
    else {
        Dialog.alert(txt);
    }
}, "text");

其他如新建、获取用法也如此,不再细述。

三:JS中操作生成元素、与数据库交互。

这里是新增附件、批量修改、删除附件的关键代码,中间还有页面元素拖动的功能。

function AddFilesUseTb(fileName, fileID, imgUrl) {
    var cloneTb = $('#tbTemplete').clone().attr('id', fileID);
    $('#uploadMsg').append(cloneTb.wrap('<div></div>').parent().html());
    $("#" + fileID).find("input:eq(0)").val(fileName);
    if (imgUrl != null) {
        $("#" + fileID).find("img:eq(0)").attr("src", imgUrl);
    }
    //文件上传完成后启用sortable
    $('.gbin1-list').sortable().bind('sortupdate', function () {
        
    });
            
    //文件上传完成后,自动更新序列号
    var fileList = $('#uploadMsg').find("table");
    var fileCount = $('#uploadMsg').find("table").length;
    $.post("/Ashx/Attachment.ashx?action=Modify", { fileID: fileID, fileName: fileName, fileDesc: "", IsMove: "N", sequenceNum: fileCount }, function (txt) {
        if (txt != "OK") {
            Dialog.alert("保存名称为:" + fileName + "的文件时出错,请重试");
        }
    }, "text");
}
function EditAllFiles(obj) {
    var fileList = $('#uploadMsg').find("table");
    var fileCount = $('#uploadMsg').find("table").length;
    for (var i = 0; i < fileCount; i++) {
        var fileID = $(fileList[i]).parent().attr("id");
        var fileName = $(fileList[i]).find("input:eq(0)").val();
        var fileDesc = $(fileList[i]).find("textarea:eq(0)").val();
        var IsMove = $(fileList[i]).find('input:checkbox:checked').val();
        if (IsMove == "on") {
            IsMove = "Y";
        }
        else {
            IsMove = "N";
        }
        $.post("/Ashx/Attachment.ashx?action=Modify", { fileID: fileID, fileName: fileName, fileDesc: fileDesc, IsMove: IsMove, sequenceNum: i+1 }, function (txt) {
            if (txt != "OK") {
                Dialog.alert("保存名称为:" + fileName + "的文件时出错,请重试");
            }
        }, "text");
    }
    $(obj).val("已保存");
};
function DelAllFiles(obj) {
    Dialog.confirm('警告:确定要删除附件?', function () {
        var fileList = $('#uploadMsg').find("table").each(function () {
            var fileID = $(this).parent().attr("id");
            var fileName = $(this).find("input:eq(0)").val();
            $.post("/Ashx/Attachment.ashx?action=DelFile", { fileID: fileID }, function (txt) {
                if (txt != "OK") {
                    Dialog.alert("删除名称为:" + fileName + "的文件时出错,请重试");
                }
            }, "text");
        });
    });
}
function DelFiles(obj) {
    Dialog.confirm('警告:确定要删除附件?', function () {
        //发送请求到服务器删除文件
        var tbSelect = $(obj).parent().parent().parent().parent().parent();
        var fileID = tbSelect.attr("id");
        $.post("/Ashx/Attachment.ashx?action=DelFile", { fileID: fileID }, function (txt) {
            if (txt == "OK") {
                Dialog.close();
                tbSelect.css('display', 'none');
            }
            else {
                Dialog.alert(txt);
            }
        }, "text");
    });
}

四:页如引用分部视图,只需一句话:@Html.Action(“Index”, “File”)

话说这MVC还真是牛掰,比ASP.NET简捷多了。

五:分享一下使用Dapper的分页代码。

public KeyValuePair<Pagination, IList<AttachmentModel>> AttachmentPagination(Pagination pagin, AttachmentModel condition)
{
    using (SQLConnection conn = DapperFactory.CrateOpenConnection())
    {
        String executeQuery = @"WITH pagintable AS(
                                SELECT ROW_NUMBER() OVER(ORDER BY CreateDate DESC )AS RowID, ID, FileID, TabName, TabID, FileName, FileDesc, FilePath, FileTypeID, FileSize, CreateDate, CreateMan, EditDate, EditMan, IsValid, NeedMoveToMoss, IsMoveToMoss, IsTemp,SequenceNum FROM Attachment
                                WHERE 1= 1)
                                SELECT * FROM pagintable where RowID between ((@CurrentPageIndex - 1)  * @PageSize) + 1  and (@CurrentPageIndex  * @PageSize)";
        String executeCount = "SELECT COUNT(*) AS CountNum FROM Attachment WHERE 1= 1";
        var mixCondition = new
        {
            CurrentPageIndex = pagin.CurrentPageIndex,
            PageSize = pagin.PageSize
        };
        List<AttachmentModel> listScore = conn.Query<AttachmentModel>(executeQuery, mixCondition).ToList();
        pagin.TotalItemCount = conn.Query<Int32>(executeCount, mixCondition).SingleOrDefault<Int32>();
        KeyValuePair<Pagination, IList<AttachmentModel>> result =
            new KeyValuePair<Pagination, IList<AttachmentModel>>(pagin, listScore);
        return result;
    }
}

这是使用CodeSmith自动生成的代码,秒秒钟搞定,并且相当灵活及高效。

上张图:

备注:这张图的两个附件顺序是可以拖动变更的,呵呵。

老样子,提供Demo网址,供用户试用及扒源码。

网址:www.qicheba.net

[转载]微信公众平台消息接口开发(1)启用接口 - txw1958 - 博客园

mikel阅读(1001)

[转载]微信公众平台消息接口开发(1)启用接口 – txw1958 – 博客园.

微信 平台 消息 接口 启用
作者:http://txw1958.cnblogs.com/

 

本系统教程以微信公众平台应用天气神(账号WeatherGod,支持国内近400个城市天气查询)为例,讲解微信接口开发过程。欢迎大家关注该账号,二维码见底部图。

使用前提条件:拥有一个公网上的HTTP服务器主机空间,具有创建目录、上传文件等权限。免费的也可以,但须有二级域名。想快速的申请一个免费稳定好用的,可以先使用新浪的SAE。但免费时间有限。

 

一、注册微信公平平台账号
地址:http://mp.weixin.qq.com/
过程略。

 

二、上传代码

以下代码是消息接口认证代码,将下列PHP代码保存为index.php(其中的mytoken改为你想要的的token名称),并上传到HTTP服务器指定的目录中,

复制代码
<?php define("TOKEN", "mytoken"); $wechatObj = new wechatCallbackapiTest(); $wechatObj->valid(); class wechatCallbackapiTest { public function valid() { $echoStr = $_GET["echostr"];        //随机字符串

        if($this->checkSignature()){ echo $echoStr; exit; } } private function checkSignature() { $signature = $_GET["signature"];    //微信加密签名
        $timestamp = $_GET["timestamp"];    //时间戳
        $nonce = $_GET["nonce"];            //随机数

        $token = TOKEN; $tmpArr = array($token, $timestamp, $nonce); sort($tmpArr);      //进行字典序排序 //sha1加密后与签名对比
        if( sha1(implode($tmpArr)) == $signature ){ return true; }else{ return false; } } } ?>
复制代码

或者直接下载微信的示例代码。地址 http://mp.weixin.qq.com/mpres/htmledition/res/wx_sample.zip

 

二、启用消息接口
进入微信公众平台,选择 设置关键词自动回复 ,选择启用 ,点击 公众平台消息接口 旁边的 编辑,进入接口配置界面:
按照要求如实填写下列选项。特别注意是URL是你上传index.php的路径,必须以http://开头,且为80端口。

填好后点击提交,这会有两种结果
1. 服务器没有响应Token验证,这样回头检查一下各项配置是否正确。

2. 提交成功

恭喜你,配置成功了。

 

 

关注天气神(账号WeatherGod)方法:

1. 依次进入以下路径:朋友们—>添加朋友—>搜号码,输入WeatherGod,不区分大小写,点击查找,然后点击关注

2. 扫描二维码:

 

[转载]ASP.NET MVC中Autofac实现的自动注入模式 - Nic Pei - 博客园

mikel阅读(1016)

转载ASP.NET MVC中Autofac实现的自动注入模式 – Nic Pei – 博客园.

熟悉IoC容器的都知道,在开发过程中,最郁闷的莫过于当你新增一个Service时,你需要对该Service进行注册,有的是使用代码注入,有的是XML配置注入,不管是哪种类型的注入,经常会出现开发人员忘记注入的情况,

如果你的页面是直接发送请求的,那么会得到类似于如下页面的错误:

image  <- _<-

 

如果该服务是用于AJAX请求实用的,那么你就悲剧了,因为页面只是没反应,只有查看错误日志了。

 

于是我试着去想办法去避免每次的服务都需要注入,而是系统自动注入。

image

 

红色线条框住的地方就是自动注入的代码实现。很高兴Autofac提供一个RegisterAssemblyTypes方法。它回去扫描所有的dll并把每个类注册为它所实现的接口。。。。

既然能够自动注入,那么接口和类的定义一定要有一定的规律。 从上面的代码可以看到baseType这个变量,它是IDependency接口的类型。

IDependency接口如下:

image

 

其他任何的接口都需要继承这个接口,例如我们定义一个接口IModelCar:

image

 

IModelCar的实现类:

 

image

 

自动注入原理说明:

 

 

 

首先我们去找到所有Dll,再去找到实现了IDependency接口的类,然后使用RegisterAssemblyTypes进行注入。

 

在Controller中调用试试:

image

 

可以看到_carmodel解析后为ModelCar的实例。。 微笑

 

Demo下载: https://github.com/nicholaspei/MvcApplication5

[转载]WEB站点性能优化实践(加载速度提升2s) - 大CC - 博客园

mikel阅读(1100)

[转载]WEB站点性能优化实践(加载速度提升2s) – 大CC – 博客园.

 进行优化前,关键是剖析当前的web性能,找到性能瓶颈,从而确定最需改进的地方;如果精力有限,首先将精力放在能明显提升性能的改进点上;

高性能网站建设指南》提出了一个性能黄金法则:

只有10%-20%的最终用户响应时间花在了下载HTML文档上;其余的80%-90%的时间花在了下载页面中的所有组件上。

由于本文将实施一个完整的优化流程,所以,我们还是从后台开始;

 

案例说明:

优化之前的网站规模:

2个js、一个页头、一个页脚;3个css;

类型:博客类站点;后台逻辑简单;首页不到10个SQL查询;

首页html文档52kb;

 

第一步:后台优化,启用页面缓存;

实验站点首页后台逻辑并不复杂,不超 过10个SQL查询,通过查看时间线,本站在获取HTML文档时,花费的时间不到总响应时间的20%,优化之前没有使用缓存,所有的数据都是从数据库读 取,这里,我们使用静态页面缓存,将首页整个页面完全的存放在缓存中(关于YII静态页面缓存的使用,参考这里);

通过查看html文档的生成时间来检测优化效果;

首字节时间为376ms;html生成的时间大大缩短,后台时间减少了一倍。

优化前:

wps_clip_image-20655

优化后:

wps_clip_image-4529

 

第二步,DNS域名解析加速:

DNS解析是用户访问站点的第一步,在此之前,你的网站无法做任何事情;

站点的DNS解析时间不应该超过500ms,如果站点原始DNS解析时间过长,就该考虑考虑使用第三方解析加速服务;

实验站点的原始DNS解析较慢,平均耗时1017ms,算是非常长的;对于DNS加速,可以使用DNS域名解析加速服务,本站点采用的国内的一款免费DNS加速服务DNSPOD,效果还不错,使用后平均耗时降到370ms;

加速前测试:

wps_clip_image-14761

使用DNS域名解析服务之后的测试:

wps_clip_image-16186

 

第三步:使用CDN加速;

采用第三方CDN加速,时间缩短到2.1s;从下图中看到主要的耗时在于并行下载的个数有些低,如果能够提升并行下载量的个数,那么整体加载时间就会降低;

注:个人建议,启用CDN最好放在最后一步,等将站点本身的优化都做完了之后,再启用CDN可以明显的看到优化效果。(开启CDN后,由于有CDN缓存的原因,观测站点的本身的优化就不是很方便了);

wps_clip_image-15052

 

第四步,采用多台服务器提高并行加载量:

原理:一个浏览器对与同一域名的并行下载的个数默认是2个, HTTP.1.0中规定的是4个。这样,我们可以使用不同的域名来提升下载的速度;

观察上图中的下载数量,第一次并行下载的个数是4个,初始认为是浏览器对于同一个域名来源的下载所限导致;于是考虑将部分静态文件分别放在不同的服务器上;通过把css和js放在不同服务器上;结果并不理想,发现并未提高速度。

想到在哪曾看到过,浏览器必须得把放在页头的css和js下载完成了之后才会开始下载其它的静态组件;

关于并行下载这点上,后续将继续实验是否还有优化的空间。

wps_clip_image-21817

 

第五步,合并脚本和样式表;

    本站首页使用了2个js和3个css。如果采用朴素复制的方式,将js和css都分别整合到一个文件中,不但操作麻烦,而且不方便后期的管理。网络上有不少合并的工具,本站采用了CSS和JS合并优化工具-minify(下载地址:http://code.google.com/p/minify/)。如果使用的YII框架,更有YII整合版(minscript Extension),简单几步的配置,就自动将页面所有的js和css文件合并;

关于minscript Extension的使用,请参考:https://bitbucket.org/TeamTPG/minscript/wiki/Usage

 

第六步,压缩css/js/html/xml;

不同的web服务器设置方式有所差别,本站使用的Linux/apache,

在web根目录下的.htaccess文件中添加以下代码即可:

#set compress

<ifmodule mod_deflate.c>

AddOutputFilter DEFLATE html xml php js css

</ifmodule>

通过firefox工具可看到,压缩前,html文档的大小是25KB;合并后的js大小为138KB;

wps_clip_image-2227

压缩后,html文档大小为6.2KB。js大小为39.8KB;减少2/3的传输时间;

wps_clip_image-10096

 

第六步,最大化的减少HTTP请求;

添加Expires头, 启用静态内容缓存,将jpg、gif等文件缓存;

方法也是在.htaccess中添加:

# Image and Flash content Caching for One Month

<FilesMatch “.(flv|gif|jpg|jpeg|png|ico|swf)$”>

Header set Cache-Control “max-age=2592360″

</FilesMatch>

 

结论

查看最终的测试结果,整体实现了较大 的性能提升,最终页面展现时间为1.62s(测试使用的是一个第三方web测速工具,所有测试结果是在第三方本地无缓存的条件下进行)。仔细观察本站最后 几个加载项:有一个第三方网站的广告(加载广告的时刻,页面已经全部呈现,对用户体验影响不大),以及cnzz的统计数据。这样看来,在第12项加载完 后,整个页面就完整的呈现在用户面前,优化最终结果是1.1s,较优化前加载速度提升2s;由于物理条件(虚拟机、国外站点)所限,本次优化就到此为止 (后续将在并行下载上做做文章,看是否有进一步提升空间)。

wps_clip_image-7016

 

本次优化主要使用的是前端优化,其中大部分规则来自于这本书的指导《高性能网站建设指南》;如果你的web前端部分还没有充分优化,强烈建议读读这本书;

这是一本你只需画上三小时就能看完,但收获价值远远大于付出的一本书。

image

附上本书的目录:

绪言A:前端性能的重要性

第1章:规则1——减少HTTP请求

第2章:规则2——使用内容发布网络

第3章:规则3——添加Expires头

第4章:规则4——压缩组件

第5章:规则5——将样式表放在顶部

第6章:规则6——将脚本放在底部

第7章:规则7——避免CSS表达式

第8章:规则8——使用外部JavaScript和CSS

第9章:规则9——减少DNS查找

第10章:规则10——精简JavaScript

第11章:规则11——避免重定向

第12章:规则12——移除重复脚本

第13章:规则13——配置ETag

第14章:规则14——使AjaX可缓存

第15章:析构十大网站

页面大小、响应时间、YSlow等级

如何进行测试

 

[转载]SQL语句的解析过程 - 独上高楼 - 博客园

mikel阅读(1390)

[转载]SQL语句的解析过程 – 独上高楼 – 博客园.

    由于最近需要做一些SQL query性能提升的研究,因此研究了一下SQL语句的解决过程。在园子里看了下,大家写了很多相关的文章,大家的侧重点各有不同。本文是我在看了各种资 料后手机总结的,会详细的,一步一步的讲述一个sql语句的各个关键字的解析过程,欢迎大家互相学习。


SQL语句的解析顺序

简单的说一个sql语句是按照如下的顺序解析的:

  • 1. FROM FROM后面的表标识了这条语句要查询的数据源。和一些子句如,(1-J1)笛卡尔积,(1-J2)ON过滤,(1-J3)添加外部列,所要应用的对象。FROM过程之后会生成一个虚拟表VT1。
  • (1-J1)笛卡尔积 这个步骤会计算两个相关联表的笛卡尔积(CROSS JOIN) ,生成虚拟表VT1-J1。
  • (1-J2)ON过滤 这个步骤基于虚拟表VT1-J1这一个虚拟表进行过滤,过滤出所有满足ON 谓词条件的列,生成虚拟表VT1-J2。
  • (1-J3)添加外部行  如果使用了外连接,保留表中的不符合ON条件的列也会被加入到VT1-J2中,作为外部行,生成虚拟表VT1-J3。
  • 2. WHERE 对VT1过程中生成的临时表进行过滤,满足where子句的列被插入到VT2表中。
  • 3. GROUP BY 这个子句会把VT2中生成的表按照GROUP BY中的列进行分组。生成VT3表。
  • 4. HAVING 这个子句对VT3表中的不同的组进行过滤,满足HAVING条件的子句被加入到VT4表中。
  • 5. SELECT 这个子句对SELECT子句中的元素进行处理,生成VT5表。
  • (5-1)计算表达式 计算SELECT 子句中的表达式,生成VT5-1
  • (5-2)DISTINCT 寻找VT5-1中的重复列,并删掉,生成VT5-2
  • (5-3)TOP 从ORDER BY子句定义的结果中,筛选出符合条件的列。生成VT5-3表
  • ORDER BY 从VT5-3中的表中,根据ORDER BY 子句的条件对结果进行排序,生成VC6表。

客户,订单的查询例子

首先创建一个Customers表,插入如下数据:

customerid city
FISSA Madrid
FRNDO Madrid
KRLOS Madrid
MRPHS Zion

创建一个Orders表,插入如下数据:

orderid customerid
1 FRNDO
2 FRNDO
3 KRLOS
4 KRLOS
5 KRLOS
6 MRPHS
7 NULL

假如我们想要查询来自Madrid的,订单数小于3的客户,并把他们的订单数显示出来,结果按照订单数从小到大进行排序。

复制代码
SELECT C.customerid, COUNT(O.orderid) AS numorders FROM dbo.Customers AS C LEFT OUTER JOIN dbo.Orders AS O ON C.customerid = O.customerid WHERE C.city = 'Madrid'
GROUP BY C.customerid HAVING COUNT(O.orderid)

<

 3
ORDER BY numorders
复制代码

查询结果为:

customerid numorders
FISSA 0
FRNDO 2

下面我们会详细的讲述sql是怎样计算出这个结果的:

 

FROM子句

FROM子句标识了需要查询的表,如果指定了表操作,会从左到右的处理,每一个基于一个或者两个表的表操作都会返回一个输出表。左边表的输出结果会作为下 一个表操作的输入结果。例如,交表相关的操作有 (1-J1)笛卡尔积,(1-J2)ON过滤器,(1-J3)添加外部列。FROM句子生成虚拟表VT1。

Step 1-J1:执行笛卡尔积(CROSS JOIN)

笛卡尔积会把左右两个表每一行所有可能的组合都列出来生成表VT1-J1,如果左表有m列,右表有n列,那么笛卡尔积之后生成的VT1-J1表将会有m×n列。

Step 1-J1这个步骤等价于执行:

SELECT * from Customers C  CROSS JOIN Orders O

执行结果为:(共有4×7列)

C.customerid C.city O.orderid O.customerid
FISSA Madrid 1 FRNDO
FISSA Madrid 2 FRNDO
FISSA Madrid 3 KRLOS
FISSA Madrid 4 KRLOS
FISSA Madrid 5 KRLOS
FISSA Madrid 6 MRPHS
FISSA Madrid 7 NULL
FRNDO Madrid 1 FRNDO
FRNDO Madrid 2 FRNDO
FRNDO Madrid 3 KRLOS
FRNDO Madrid 4 KRLOS
FRNDO Madrid 5 KRLOS
FRNDO Madrid 6 MRPHS
FRNDO Madrid 7 NULL
KRLOS Madrid 1 FRNDO
KRLOS Madrid 2 FRNDO
KRLOS Madrid 3 KRLOS
KRLOS Madrid 4 KRLOS
KRLOS Madrid 5 KRLOS
KRLOS Madrid 6 MRPHS
KRLOS Madrid 7 NULL
MRPHS Zion 1 FRNDO
MRPHS Zion 2 FRNDO
MRPHS Zion 3 KRLOS
MRPHS Zion 4 KRLOS
MRPHS Zion 5 KRLOS
MRPHS Zion 6 MRPHS
MRPHS Zion 7 NULL

 

Step 1-J2:应用ON过滤,(JOIN 条件)

ON过滤条件是sql的三个过滤条件(ON,WHERE,HAVING)中最先执行的,ON过滤条件应用于前一步生成的虚拟表(VT1-J1),满足ON过滤条件的行会被加入到虚拟表VT1-J2中。在应用了ON 过滤之后,生成的VT1-J2表如下所示:

C.customerid C.city O.orderid O.customerid
FRNDO Madrid 1 FRNDO
FRNDO Madrid 2 FRNDO
KRLOS Madrid 3 KRLOS
KRLOS Madrid 4 KRLOS
KRLOS Madrid 5 KRLOS
MRPHS Zion 6 MRPHS

 

Step 1-J3:添加外部列

这个步骤只会出现在使用了外连接的情况。对于外连接(LEFT,RIGHT, or FULL),你可以标记一个或者两个表作为保留表。作为保留表意味着你希望这个表里面的所有列都被返回,即使它里面的数据不满足ON子句的过滤条件。 LEFT OUTER JOIN 把左边的表标记为保留表,RIGHTOUTER JOIN把右边的表作为保留表,FULL OUTER JOIN把两个表都标记为保留表.Step 1-J3为根据VT1-J2中的虚拟表,添加了保留表中不满足ON 条件的列,在未保留表中没有对应的列,因此标记为NULL。这个过程生成了虚拟表VT1-J3。

C.customerid C.city O.orderid O.customerid
FISSA Madrid NULL NULL
FRNDO Madrid 1 FRNDO
FRNDO Madrid 2 FRNDO
KRLOS Madrid 3 KRLOS
KRLOS Madrid 4 KRLOS
KRLOS Madrid 5 KRLOS
MRPHS Zion 6 MRPHS

如果FROM子句中有多个表操作运算,sql会按照从左到右的顺序处理,左边生成的临时表结果作为右边表的输入表。

Step 2 WHERE 子句

WHERE过滤被应用到前一步生成的临时表中,根据WHERE过滤条件生成临时表VT2。

注意:由于数据现在还没有被分组,因此现在你不能使用聚合运算-例如:你不能使用这样 的句子 WHERE orderdate = MAX(orderdate)。另外你也不能使用SELECT子句中创建的变量别名,因为现在还没有处理SELECT子句-例如你不能写这样的句 子:SELECT YEAR(orderdate) AS orderyear . . . WHERE orderyear > 2008.

应用这个过滤

WHERE C.city = 'Madrid'

这时生成的临时表VT2的内容如下:

C.customerid C.city O.orderid O.customerid
FISSA Madrid NULL NULL
FRNDO Madrid 1 FRNDO
FRNDO Madrid 2 FRNDO
KRLOS Madrid 3 KRLOS
KRLOS Madrid 4 KRLOS
KRLOS Madrid 5 KRLOS

在这个例子中,你需要在ON子句中使用ON C.customerid = O.customerid过滤,没有订单的客户在1-J2这一步中被过滤掉,但是在1-J3这一步中作为外部列又被加回来。但是,由于你只想返回来自 Madrid的客户,因此你需要在WHERE子句中过滤城市(WHERE C.city = ‘Madrid’),如果你放在ON过滤中,不属于Madrid的客户在添加外部列中会被添加回来。

关于ON 和 WHERE 的区别需要在这里说明一下,ON 和WHERE 的主要区别在于 ON 实在添加外部列之前进行过滤,WHERE 是在之后。ON过滤掉的列会在1-J3中添加回来。如果你不需要添加外部列,那么这两个过滤是相同的。

Step 3 GROUP BY子句

这个子句会把前一步中生成的临时表中的数据进行分组,每一行都会分到并且只分到一个组里,生成虚拟表VT3。VT3表中包含了VT2表中所有的数据,和分组标识符。

这是生成的临时表VT3的内容如下:

Groups
C.customerid
C.customerid C.city O.orderid O.customerid
FISSA FISSA Madrid     NULL NULL
FRNDO FRNDO Madrid 1 FRNDO
FRNDO Madrid 2 FRNDO
KRLOS Madrid 3 KRLOS
KRLOS KRLOS Madrid 4 KRLOS
KRLOS Madrid 5 KRLOS

sql最终返回的结果中,每一个分组必须只能返回一行(除非被过滤掉),因此当一个sql语句中使用了GROUP BY时,在GROUP BY后面处理的子句,如SELECT,HAVING子句等,只能使用出现在GROUP BY后面的列,对于没有出现GROUP BY后面的列必须使用聚合函数(如 MAX ,MIN,COUNT,AVG等),保证每一个GROUP只返回一行。

Step 4 HAVING子句

HAVING子句用来过滤前一步生成的临时表,并且只作用于分组后的数据,满足HAVING条件的GROUP被添加到虚拟表VT4中。

当应用了这个过滤:

HAVING COUNT(O.orderid) < 3

之后,生成的VT4表内容如下:

Groups
C.customerid
C.customerid C.city O.orderid O.customerid
FISSA FISSA Madrid     NULL NULL
FRNDO FRNDO Madrid 1 FRNDO
FRNDO Madrid 2 FRNDO

需要注意的一点是,这里面使用的是COUNT(O.orderid),而不是COUNT(*),由于这个查询中添加了外部列,COUNT方法会忽略NULL的列,导致出现了你不想要的结果。

Step 5 SELECT 子句

尽管出现在sql语句的最前面,SELECT在第五步的时候才被处理,SELECT子句返回的表会最终返回给调用者。这个子句包含三个子阶段:(5-1)计算表达式,(5-2) 处理DISTINCT,(5-3)应用TOP过滤。

Step 5-1 计算表达式

SELECT子句中的表达式可以返回或者操作前一步表中返回的基本列。如果这个sql语句是一个聚合查询,在Step 3之后,你只能使用GROUP BY中的列,对不属于GROUP集合中的列必须使用聚合运算。不属于FROM表中基本列的必须为其起一个别名,如YEAR(orderdate) AS orderyear。

注意:在SELECT子句中创建的别名,不能在之 前的Step中使用,即使在SELECT子句中也不能。原因是sql的很多操作是同时操作(all at once operation),至于什么是all-at-once operation这里就不再介绍了。因此,SELECT子句中创建的别名只能在后面的子句中使用,如ORDER BY。例如:SELECT YEAR(orderdate) AS orderyear . . . ORDER BY orderyear。

在这个例子中:

SELECT C.customerid, COUNT(O.orderid) AS numorders

结果会得到一个虚拟表VT5-1:

C.customerid numorders
FIFSSA 0
FRNDO 2

Step 5-2:应用DISTINCT子句

如果sql语句中使用了DISTINCT,sql会把重复列去掉,生成虚拟表VT5-2。

Step 5-3:应用TOP选项

TOP选项是T-SQL提供的一个功能,用来表示显示多少行。基于ORDER BY子句定义的顺序,指定个数的列会被查询出来。这个过程生成虚拟表VT5-3。

正如上文提到的,这一步依赖于ORDER BY定义的顺序来决定哪些列应该显示在前面。如果你没有指定结果的ORDER BY顺序,也没有使用WITH TIES子句 ,每一次的返回结果可能会不一致。

在我们的例子中,Step 5-3被省略了,因为我们没有使用TOP关键字。

Step 6:ORDER BY子句

前一步返回的虚拟表在这一步被排序,根据ORDER BY子句指定的顺序,返回游标VC6。ORDER BY子句也是唯一一个可以使用SELECT子句创建的别名的地方。

注意:这一步和之前不同的地方在于,这一步返回的结果是一个游标,而不是表。sql是基于集合理论的,一个集合 没有对他的行定义顺序,它只是一个成员的逻辑集合,因此成员的顺序并不重要。带有ORDER BY子句的sql返回一个按照特定序列组织每一行的对象。ANSI 把这样的一个对象叫游标。理解这一点对你了解sql很重要。


上面的步骤如图所示:

image

 

本书中主要内容是参照 Inside Microsoft SQL Server 2008:T-SQL Query,中的内容,大家如果想深入了解sql查询相关的知识,可以找这本书看看,我这有英文原版的pdf,需要的可以找我要。