YZL的研究室一切都是幻觉吧?

在Asp.Net MVC中使用NVelocity模板引擎(一)-自定义关键字

[.Net] Asp.Net MVC   评论:0   浏览:   Tags: NVelocity  Asp.Net MVC  

大约在很早很早的时候,我们就可以使用MvcContrib为我们的ASP.NET MVC程序引入NVelocity模板引擎的支持了。但是从严格意义上来说,这个支持仅仅是有限支持,因为大部分原本可以在Monorail里面使用的功能都使用不了了,不仅如此,整个程序还有一大堆bug。总的来说,这个程序集堪称“超级杀脑细胞王3000”,让你用得绝望。百般无奈之下,只好自己修改这个程序集,那么这篇文章就权当一个opening吧。

 

如果我们在Preview 5版本的MVC中使用诸如$html.renderaction或者$html.renderpartial这种返回值是void的方法时,我们会发现根本没有效果。不过还好,这个bug已经在beta 1版本中解决了,但是…但是解决的方法并不怎么优雅…

先看看Preview 5的实现代码

 

这里传进Render方法的writer实际上就是一个httpwriter,重点在处理layout那一段,如果有layout的话就把子template,也就是代码中的_viewTemplate,解析之后放到内存流中间去缓存,然后把处理的结果赋给childContent变量,再让父template解析一次,这样就完成了对整个页面的解析。但是如果使用这种方法的话,helper中所有返回值为void的渲染方法都会失效。因为在Helper中所有返回值为void的方法都是调用HttpWriter把结果直接写进response.OutputStream中的。如果向上面那样自己用一个StringWriter来缓存输出流的话,相当于所有返回值为void的helper方法都被剥离出了NVelocity的解析树(这种情况下有2个流,一个是response.OutputStream,一个是StringWriter的Stream),结果当然会不正确啦。

 

所以在Beta 1的MvcContrib中,代码被改成了下面这样

 

这里不再使用StringWriter去缓存流,而是直接使用writer来写入response.OutputStream中,由于在context.Put中送入的是子template的名字(Preview 5是解析后的子template),所以我们在layout.vm中不能再像以前一样直接用$childContent来占位,而是要用#parse($childContent),虽然改变了长期以来的使用习惯,但是好歹还是能够正常使用了,直到……

 

昨天XX强烈要求我把#capturefor给弄出来(这个方法是monorail里面的,在ASP.NET MVC里面用不了),于是我把Monorail的源代码大致看了一下,发现其实#capturefor是monorail自定义的一条directive(指令),也就是说NVelocity引擎是可以支持自定义Directive的。

 

首先定义一个继承自Directive的类

 

然后定义一个继承自DirectiveManager的类

 

并在RegisterCustomDirectives方法中注册,最后在NVelocityViewFactory中注册这个自定义的DirectiveManager类

 

运行一下看看?囧…竟然没有将变量解析出来,不过至少在vm文件中使用#capturefor关键字不会报错了,也就是我们的Directive还是起作用了。经过Debug发现问题其实还是出在最后的渲染步骤上。在template.merge的时候,NVelocity引擎会按照文档的顺序来解析模板并将其输出到response.OutputStream中,而capturefor的参数一般是在父template中定义的,也就是说如果按照顺序解析的话是绝对解析不出来的。但是如果按照Preview 5中那样先解析子template又会有另外的bug.

 

不过好在我们仍有办法解决这个问题。首先建立一个response filter,让它去截获response的输出流,不让这个流输出到客户端,而是存到我们自定义的一个变量中。然后,嘿嘿…看图,应该很明了了

 

还是用HttpWriter来写结果,这样可以保证顺序问题和Void方法问题,但是并不把这个结果输出到客户端,而是放到一个字符变量中,然后我们再调用父template的merge方法来完成解析。这样做不但解决了自定义directive的问题,而且我们现在也可以像以前那样在layout中使用回$childContent方法而不是#parse($childContent)了。一举两得!

寒…

Daily   评论:0   浏览:   Tags:

东西竟然没丢

Intel无线电力传输 驱动60W灯泡

News   评论:0   浏览:   Tags:

IDF第三天,轮到Intel研究实验室的奇思妙想们出场了。电磁感应无线输电技术已经在诸如电动牙刷等小功率产品上获得了应用,但更大功率的传输目前还不现实。Intel日前则在会场上演示了无线公供电驱动一枚60W电灯泡。该项研究是由Intel西雅图实验室的Joshua R. Smith领导的,部分技术基于麻省理工学院物理学家Marin Soljacic的研究。可以在一米距离内无线给60W灯泡提供电力,效率高达75%。Intel首席技术官Justin Rattner表示,未来可以将无线充电装置安装在办公桌内部,只要将笔记本或PDA等电器放在桌上就能够立即供电。

Intel展示无线电力传输 驱动60W灯泡

 

Intel展示无线电力传输 驱动60W灯泡

 

Intel展示无线电力传输 驱动60W灯泡

江城子·乙卯正月二十日记梦

Daily   评论:0   浏览:   Tags:

十年生死两茫茫。
不思量,自难忘。
千里孤坟,无处话凄凉。
纵使相逢应不识,尘满面,鬓如霜。


夜来幽梦忽还乡。
小轩窗,正梳妆。
相顾无言,惟有泪千行。
料得年年肠断处,明月夜,短松冈.

 

看了很伤感,写的太好了,收藏

Entity Framework - 使用SQL Server 2008 中的新数据类型

[.NET] Entity Framework   评论:0   浏览:   Tags: SQL 2008  Entity Framework  HierarchyId  

EF v1仅仅只支持SQL 2008中新的Date类型数据以及部分支持FileStream类型的数据,如果你在数据表中使用了HierarchyId或者Geography等类型的数据,在映射的时候EF会自动把使用了这些数据的列排除的映射之外:

 

<!--Errors Found During Generation:
      warning 6005: The data type 'hierarchyid' is not supported, the column 'Location' in table 'XXX' was excluded. -->

 

我在google上search了一下,没有找到使用EF映射HierarchyId等数据类型的方案,官方的说法是等EF v2,这就有点久了,貌似要到2009年。。。。。

 

本来都快放弃了,但是我无意中发现EF竟然也不支持XML类型的映射(连DLinq都支持哎~~),如果我们的数据表中有XML类型的字段,那么在EF中会自动被映射成String。还好,没有报错!不过这也给我们带来了新的思路,不是么?我依稀记得在ADO.NET可以在SQL 2005上面存储HierarchyId类型的数据,到MSDN上一查,果然如此。请看《在复制拓扑中使用 SQL Server 的多个版本》,在这篇文章中明确说明了SQL 2008中的HierarchyId、Geography、Geometry三种类型的数据可以由SQL 2005中的varbinary(MAX)替代,也就是说如果你在.NET程序中使用了SqlHierarchyId数据类型而又要把这种类型存储到SQL 2005中的话,可以存储到varbinary(MAX)字段中。

 

OK,下面让我们来玩个小小的把戏。

1.在映射的时候把字段改成binary类型(在数据库中仍然是HierarchyId字段)。

<!--SSDL-->
<Property Name="Location" Type="varbinary" Nullable="false" />
<!--CSDL-->
<Property Name="Location" Type="Binary" Nullable="false" />
<!--C-S mapping-->
<ScalarProperty Name="Location" ColumnName="Location" />

 

自动生成属性是这样:

public byte[] Location

2.自己扩展两个方法

public static SqlHierarchyId ToHierarchyId(this byte[] source)
{

var stream = new MemoryStream(source, false);

      var reader = new BinaryReader(stream);
      var hierarchyId = new SqlHierarchyId();
      hierarchyId.Read(reader);
      return hierarchyId;
}
 
public static byte[] ToBytes(this SqlHierarchyId source)
{
      var stream = new MemoryStream();
      var writer = new BinaryWriter(stream);
      source.Write(writer);
      return stream.ToArray();
}

 

3.直接使用吧

Location = SqlHierarchyId.Parse("/0/").ToBytes(),

Trick终究是Trick,如果想用ESQL或者Linq 2 Entities来针对HierarchyId类型进行查询的话(比如IsDescendantOf等等),还是耐心等待EF v2吧!

Visual Studio 2008 SP1 RTM is finally out

Daily   评论:0   浏览:   Tags: Visual Studio  

真是千呼万唤始出来啊。http://msdn.microsoft.com/en-us/vstudio/products/cc533448.aspx

Entity Framework - 查询单条记录

[.NET] Entity Framework   评论:0   浏览:   Tags: Entity Framework  

在DLINQ中我们可以使用Single()或者SingleOrDefault()方法查询单条纪录,但是在EF中,如果我们试图这样做,将得到一个异常,告诉我们Linq To Entities不支持Single()方法,可以用First()方法代替。

虽然First()确实可以替代Single(),但它们还是有少许差别的。原语句如下:

 

Select Value U.ID From UserInfos AS U Where U.Email=@email

 

First()翻译后的语句是

 

SELECT 
[Limit1].[ID] AS [ID]
FROM ( SELECT TOP (1) 
    [Extent1].[ID] AS [ID]
    FROM [dbo].[Users] AS [Extent1]
    WHERE [Extent1].[Email] = 'yzlhccdec@1631.com'
)  AS [Limit1];

 

而我期望的语句是

 

SELECT [Extent1].[ID] AS [ID]
FROM [dbo].[Users] AS [Extent1]
WHERE [Extent1].[Email] = 'yzlhccdec@1631.com'

 

那么上面这两个语句究竟有区别么?让我们在SQL Server中看一下:

无标题     

从查询计划上面看两种方法是差不多的,但是从统计信息来看,前者不论是从客户端发送的字节还是服务端收到的字节都比后者多一些(我不大明白为什么接收字节会有区别)。然后我们来看看在.NET下的性能测试:

 

.NET测试结果 

其中NT表示使用了MergeOption.NoTracking。从图中可以看出如果先用ToList()然后再调用Linq方法会比直接使用Linq方法快得多。而ToList()方法对应的TSQL语句也正是我期望的语句。也就是说选取单个纪录的话,最好是先用ToList()转换成内存对象再选取性能会高一些。另外,我们还可以看出在只选取部分Entity属性时,MergeOption.NoTracking这个选项是没效果的(这句话貌似是废话?Tracking系统只针对继承了EntityObject的类)。

Entity Framework(4)-优化查询(续)

[.NET] Entity Framework   评论:0   浏览:   Tags: Entity Framework  

上篇Post中,我们提到了几种优化Entity Framework查询的方法。另外从最后的测试结果中我们可以注意到第一次创建ObjectContext并查询数据时耗费了大量的时间,原因是什么?有没有什么优化的方法?本文将给出一个合理的解释。

 

下面这个饼状图给出了第一次创建ObjectContext并用其访问数据库时各种操作所占的时间比

PerfBlogImage2

从中可以看出仅仅View Generation一个操作就占用了56%的时间,不过令人欣慰的是,这个操作只出现在第一次查询的时候,之后生成好的View会被缓存起来供以后使用。一个View.cs文件的样本如下:

无标题

我们可以使用EDMGen2.exe来自己生成View.cs,然后把它加入到工程中编译,这样会大大缩减View Generation操作所占的时间比。根据ADO.NET TEAM 的测试,自己编译View大概会节省28%的时间。不过我在自己电脑上测试的结果没有那么理想,大概是8%左右。

Entity Framework(3)-优化查询

[.Net] Entity Framework   评论:2   浏览:   Tags: Entity Framework  Ado.net EF  

在开始之前首先了解一下Entity Framework存取Entity的三种方式。

 

LINQ to Entities 直接通过LINQ存取,可完全将程序与数据库分离,由LINQ在内部自动使用Object Service进行数据库操作
Object Service 可以透过Entity SQL来存取Entity,并且直接以物件的方式来存取结果集(因为结果集本身就是物件的集合)。
EntityClient 透过类似ADO.NET 的方法,以及 Entity SQL 存取 Entity。

 

不论是Linq To SQL或是EF,他们都作为一个容器管理着里面所有附着在其上的对象。它们通过一种叫Object Tracking的机制来跟踪对象的变化,以便于在用户需要的时候把这些变化持久化到数据库中去。有时候,我们可能并不需要改动数据(比如我们只是简单地取出一个Entity然后把它绑定到UI上面去),那么在这个时候,Tracking机制就比较多余了。在DLINQ中,我们可以通过OjectTrackingEnabled=false来关闭它,而在EF中,我们可以以MergeOption.NoTracking=false来取得同样的效果。

 

在EF中,有个Query Plan Caching的功能,它可以Cache编译后的ESQL。如果使用Objective Service,可以用System.Data.EntityClient.EntityCommand.EnablePlanCaching将它设置为打开。如果使用EntityClient,可以用System.Data.Objects.ObjectQuery.EnablePlanCaching将它设置为打开。默认情况下,这两个设置都是为True的,不需要我们过多操心。不过要注意的是只有要执行的语句与已缓存的语句完全精确匹配的时候才能使用缓存(但是查询参数可变,其实这个原理跟SQL Server的执行计划缓存原理差不多)。另外,缓存的ESQL是基于App-Domain的,而且即使是ObjectQuery<T>的实例被销毁了,其余的ObjectQuery<T>实例照样可以使用缓存计划。

 

最后,当然是CompiledQuery,这个功能基本上和DLINQ差不多,这里就不多说了。因为CompiledQuery会在第一次运行时进行编译,所以在第一次运行时,它比正常的LINQ语句还要慢。如果某些语句只需要执行一次,那还是不用CompiledQuery为妙!不过似乎不会出现这种情况?CompiledQuery的一般用法是声明一个static的变量来存储它。

 

下面是一个小小的测试:

 

var entities = new Entities();
 
var GetComments =
CompiledQuery.Compile((Entities entities1, int id) => entities1.Comments.Where(p => p.Id == id));
 
//第一次编译,这个肯定会慢些,不算!
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < 1000; i++)
{
    var query = new ObjectQuery<Comments>("Select value c From Comments as c Where c.Id = @Id", entities,
      MergeOption.NoTracking);
    query.Parameters.Add(new ObjectParameter("Id", i));
    query.EnablePlanCaching = false;
    var list = query.ToList();
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
watch.Reset();
 
//关闭ESQL Caching
watch.Start();
for (int i = 0; i < 1000; i++)
{
    var query = new ObjectQuery<Comments>("Select value c From Comments as c Where c.Id = @Id", entities,
      MergeOption.NoTracking);
    query.Parameters.Add(new ObjectParameter("Id", i));
    query.EnablePlanCaching = false;
    var list = query.ToList();
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
watch.Reset();
 
//打开ESQL Caching,默认就是打开的
watch.Start();
for (int i = 0; i < 1000; i++)
{
    var query = new ObjectQuery<Comments>("Select value c From Comments as c Where c.Id = @Id", entities,
      MergeOption.NoTracking);
    query.Parameters.Add(new ObjectParameter("Id", i));
 
    var list = query.ToList();
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
watch.Reset();
 
//使用CompiledQuery
watch.Start();
for (int i = 0; i < 1000; i++)
{
    var result = GetComments(entities, i).ToList();
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
watch.Reset();
 
//不使用CompiledQuery
watch.Start();
for (int i = 0; i < 1000; i++)
{
    var result = entities.Comments.Where(p => p.Id == i).ToList();
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
watch.Reset();

 

结果如下

无标题

校内,我真替你囧

Daily   评论:1   浏览:   Tags:

今天无聊打开校内主页,发现首页正中间有一副巨大的广告-“全新校内网横空出世”。我霎时间就被雷焦了,我记得前不久Facebook才改过版,难不成校内这次又迅速跟进了?于是乎我怀着无比激动的心情点开了校内的新版主页,果不其然,又是明显地把Facebook抄袭了一遍。我无语了。。。

 

回顾一下校内的发展史,几乎所有的功能,甚至包括界面都是在抄袭Facebook,所有的所有都比Facebook慢了一拍。。校内简直就是互联网行业的超级大山寨!!抄一次两次,我都不会觉得有什么大问题,毕竟我们的底子薄一点,多学习一下国外的先进经验是好的。但是校内已经发展了2年多,用户也达几千万,这种时候还一直跟在Facebook后面抄。。。我真不知道该说什么了,囧一个吧。。。

 

我不想把这个话题扯到民族问题上面去,不过,我们真应该好好想想,我们是不是应该好好考虑一下其它问题了?为什么我们不能有一些自己的创新呢?校内,一路走好,不送!!!

Copyright Aaron.Yi's Blog. All Rights Reserved. Powered By Z-Blog 1.8 Spirit Build 80722 & Theme Dmno by Stephen