[JQuery]jQuery UI 1.7 发布下载

mikel阅读(660)

JQuery 1.3.1发布之后,UI包一直没跟上,3月6日,兼容JQuery 1.3.1的UI包终于发布了。大家可以来这里下载jquery-ui-themes-1.7.zip,svn方式:http://jquery-ui.googlecode.com/svn/tags/1.7/themes/

 

这次改动主要如下:

  • jQuery1.3兼容。
  • 修补和优化以前的UI插件。
  • 崭新的CSS框架。
    jQuery UI 1.7建立在一个崭新的强大的css框架上,这个框架不仅仅用于jQuery UI的插件,还可以用于定制插件,任何开发者都能很容易地基于ThemeRoller(jQuery UI 的换肤插件)为插件创建皮肤。更多关于CSS框架
  • 新版的ThemeRoller(V2)。
  • 健全的演示和文档。
  • 完全离线的帮助文档。
  • 重构了download builder,即使JavaScript被禁用,这个插件仍然能运作。
  • 皮肤打包。
    点击这里可以立即下载所有皮肤: jquery-ui-themes-1.7.zip,svn: http://jquery-ui.googlecode.com/svn/tags/1.7/themes/
  • 为jQuery UI新建了一个网站http://www.jqueryui.com/
    这个网站和主站分开,专注于UI研发。

    1

[C#]并行编程的基础

mikel阅读(794)

并行编程在近些时候特别火爆,因为ILP得潜力已经被发掘得差不多了,TLP必然成为未来提高微处理器性能的最重要方向,最重要的体现形式就是多核并行处理器,看看做GPUNV前些日子的嚣张就知道多核并行运算的炙热程度。现在我们就来看看ILPTLP的转换中,我们程序员面临哪些可能的挑战。以下内容很多自己推测,肯定存在错误,仅仅作参考。

对于程序员来说,并行运算最重要的地方就是共享资源正确和高效的使用,而程序员所能最大限度掌控的便是存储系统。我们来看看INTEL多核CPU的构成原理图:
Core0 Excution > RFs > L1 Cache > L2 Cache > Memory > (Buffer) External Storage(HD)
Core1 Excution > RFs > L1 Cache >
其中红色部分为共享资源,下面我来详细讨论以下几个问题。

1.  Memory的使用策略
INTEL CPU对内存的使用策略多种多样,分别用来满足不同的应用需求

A. 强不可缓冲模式(strong uncacheable

B. 不可缓冲模式(uncacheable)

C. 写透模式(write through

D.写回模式(write back

E. 写组合(write combining

F. 写保护(write protection

我们常见的的两样就是DE,普通应用程序执行的内存模式都是WB的,AGP内存是WC的,而内存使用模式的定义可以通过PATMTTRs等进行配置,详细情况请参考相关手册。INTEL CPU按访问模式将数据分为3类:临时的,表示在不久马上就会用到的;连续的,表示数据会被序列访问的;非临时的,表示接下来一段时间不会被再次用到。WB内存模式最主要针对第一种使用模式的数据设计,经常被反复读写,所以WB模式会完整利用Cache来加速这样的访问。而WC模式主要是针对写的非常多,而基本不怎么读的数据,比如AGP MEMORY,这样数据就不必经过Cache缓冲,经过Cache反而会影响效率,因为同时要写Cache和内存,造成不必要的cache污染和cache波动。

对于WB模式内存区域具备如下特性:

1、  读取内存数据是投机执行的,不要指望内存读命令按程序顺序执行

2、  读可以提前到写之前执行,比如因为总线忙,写被BUFFERSTORE BUFFER中,而后续的读已经被CACHE,则读可以先进行。

3、  写内存通常都是遵循程序顺序的,但CLFLUSHNON-TEMPORAL指令除外,因为这些指令是WC语义的,WEAKING orDERNT写被BUFFERWC BUFFER中(通常为64BYTE)。

4、  写可被缓冲起来(CACHE中或者STORE BUFFER中)。

5、  WB内存绝对不会实行投机写。

6、  可执行存储转发(STORE FORWARDING

7、  读和写内存都不会被提前到I/O指令、LOCK指令和序列化指令之前。

8、  读不能提前到LFENCEMFENCE之前。

9、  写不能提前到SFENCEMFENCE之前。

2.  Cache的原理

INTEL CORE2实现了L1L2两级CACHEL2双核共用,CORE22CACHE都是64B/LINE,共1024行。分别是8路和16路组相连,CACHE在与主存之间传输数据采用8-Transfer Burst transcation,(CACHE LINE不支持partial write transaction)这个是总线技术术语,什么意思呢?就是一次传输64字节,分8组突发传送,为原子操作(毕竟我不是专业做硬件的,解释可能有误,详细请参看总线技术相关文档),即便只需要小于64字节的数据,总线依然传送64字节填充整个CACHE LINE。根据CPU的档次,L2 CACHE大小不一,但L1都是64KB的,32的指令,32的数据。两个CoreL1d Cache之间可以互相传输数据(可能与MESI协议实现有关),L1 Cache拥有几个数据和指令硬件预取器,L2 Cache的预取器是基于L1 Cache预取器的访问模式和密集程度来工作的,使用了一个改进的Round-Robin算法动态的在两个处理器之间分配带宽。前端总线接口也采用了类似的方式以确保平衡。L1 CacheL2 Cache采用了独立访问设计,也就是说Core可以直接从L2 L1Main Memory中直接取数据,无须逐级上升。intel cache使用了mainly inclusive设计。

现在我来详细讨论CACHE LINE的构造,如下图:

Data blocks

Tag

Index

Displacement

Valid bit

DATA BLOCKS包含实际从主存中攫取的数据64BTAG\INDEX\DISPLACEMENT均为内存地址,valid bit 好像是2bit用来表示此LINE的状态,后面我会详细叙述。可能朋友们看到这里对组相联这个概念还有些许模糊,其实这是对于CACHE的使用策略,我们知道CACHE远小于内存,如何合理高效的使用CACHE是个大问题,常用的算法有如下3中:

全相联:内存中的任何64对齐字节可以放在任何一CACHE LINE

直接映射:内存的任何一个64对齐字节只能放在特定的一CACHE LINE

N路组相联:内存的任何一个64对齐字节只能放在某些(NCACHE LINE

L18路组相联,表示每8CACHE LINE对应128个组值中的一个。7BIT的组值,6BITINDEX值,19BITTAG。很显然如果L1D32KB并且为8路组联,则每12864组组织重复一次。

 

我们详细理一下INTEL CORE2 L1 CACHE的参数:64KB64B/LINE8路组相联。所以我们可以知道CACHE LINE数目为1024行,每8行编为一组,共128组。CACHETAG SRAMDATA SRAM,每行都有一个TAG值,假设为所存数据物理地址的高19位,如下图TAG SRAM的组织:

Set Index

Way0

Way1

Way2

Way3

Way4

Way5

Way6

Way7

0

Tag

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

127

 

 

 

 

 

 

 

 

CORE2可以一直读取8TAG同时比较。INDEX索引很显然是物理地址低位6BIT064),再取128的模,所以应该是[12:6]位为组索引,然后用要操作的地址的高19位与TAG SRAM中的128组中的每个值比较,一旦比较成功则CACHE HIT,这样我们便知道数据在哪组哪路。接下来便是数据的实际操作,L1 CACHE DATA SRAM好像是8BYTE 数据读宽度,一次可以READ 8路,还记得系统总线的8 TRANSFER BURST TRANSCATION吗?估计跟这也有关系.

上图可能有点问题(其实细节跟SRAM实现细节有关),但我们简单考虑,我们知道了HITSET数,以及SET中的路数,所以我们知道CACHE LINESET×8way+ Set_Offset,结合Data offset可以读取正确的数据出来。CORE2 使用CACHE的方式,我不知道具体情况,只知道INTEL CORE2 CACHE替换策略为PSEUDO-LRU算法,并且高端处理器CACHE HIT都使用虚拟地址完成,而不是物理地址,减少地址翻译负载。

3.  存储一致性维护

在此必须首先对CORE2双芯架构有个了解,为什么称其为双芯而不是双核,主要是因为CORE2 DUO的两个核是通过前端总线连接在一起的,导致不光CPU与外部设备访问要使用FSB,甚至CORE之间信息交流(MESI协议的实施)也要占用带宽,这是CORE2架构中最鸡肋的部分,当然在David Kanter以前的文章中提到L1 CACHE之间可以直接通信,可能是INTEL做了相关优化,但具体不得而知,暂时我们就当CORE只能通过FSB互相交互。每个CACHE LINE有一种状态,可以分别为MODIFIEDEXCLUSIVESHAREINVALIDMODIFIED默认就是EXCLUSIVE的,一般MESI协议会定义若干种同步消息来交流信息,而CORE都会在总线上监听SNOOPING这些消息,然后对自身的特定CACHE LINE的状态做修改。必须重点提醒的是所谓存储一致性主要是针对CACHEABLE MEMORY提出的,比如WTWB,而WC模式是无须硬件保证存储一致性的。以下是MESI协议中CACHE LINE根据自身状态和读写情况,进行自我状态改变,总线同步消息发送以及内存操作的图例,对理解MESI协议的实现非常重要。(贴不上图,随后补上).

4.程序编写中需要注意些什么

如何保证我们对存储器的访问是原子的?

很显然并行程序设计少不了进行同步操作,对临界区、时间、信号等同步资源的访问就必须是原子的。CPU提供了 3大类硬件功能供操作系统开发人员和应用程序开发人员来保证最基本的原子操作:1、硬件上真正不会被打断的指令。2、系统总线锁。3、CACHE一致性管 理。接下来我详细解释下以上3个功能。CORE2提供了一些保证不会被中断的指令,比如读或写位于对其位置的1/2/4/8字节长内存,如果内存没有被 CACHE,一次总线2字节的数据传输的访问也是原子的,CACHE LINE内数据访问都是原子的。因为CORE2的数据总线是4字节的,而访问指令只支持1、2、4字节访问,假设要访问的内存并没有对齐,就很可能需要2 次或2次以上总线数据传输才能完成反问,这样就又可能被打断了,比如访问位于地址3上的2个字节,这就需要2次总线操作,但如果访问的2个字节位于地址1 上就只需要一次,你可能会问,这明明没有对齐,怎么能一次传输搞定呢?因为这是CPU会利用总线宽度冗余,一次传输从0~3地址的4个字节,这样其中需要 的1、2字节也包含在里面了,但位于3上就不行了,因为不论总线是2字节还是4字节传送,都无法一次传输完毕,这与系统总线数据传输特性有关,只能对齐传 送数据!新人可能还会问个问题?操作寄存器的指令是否能被打断呢?我认为是不可以的,因为CISC指令的CPU将一条指令当作完整功能,能打断的只是外部 操作,比如数据LOAD和STORE,CPU内部一条指令解码后的所有微指令执行之间应该是无法被打断的,因为只有当一条指令的所有微指令都 retirement后,CPU的状态才算更新完毕。除非掉电,当然这个只是我的猜测,没有看到官方文档上有说明,知道的朋友可以告诉我。但这个问题对于 并行运算无关紧要,因为寄存器是CPU内部私有的,不是共享资源。总线锁,CPU有一个LOCK针脚,会触发LOCK信号,用来锁定系统总线(主要就是前 端总线)资源不被其他总线主控逻辑(如另外的核和BUS AGENT)占用,当一个核LOCK住系统总线后,其他核或总线代理都必须等待释放,这时外部中断什么的都无法传送到CPU中来。LOCK可以将外部储存 器访问原子化(因为其他主控逻辑都无法使用总线反问内存了),但细心的朋友可能会意识到一个问题LOCK只是用来锁定外部的系统总线,应该不能用来保证跨 CACHE LINE的内存访问吧,是的你想对了,我们无法保证这种操作的原子性,因为很显然CACHE是在CPU内部,不受LOCK信号影响,CORE2中如果访问 CACHE LINE的指令前加了LOCK前缀,是不会触发LOCK信号锁定系统总线的,而是会使用MESI协议保证CACHE一致性。任何需要1次以上存储访问的操 作都不是原子的,很可能被打断和中间安插其他访问指令,比如add [mem], eax,其实至少有2次存储访问,一次读,一次写,在SMP系统中就很可能在这2次存储访问之间加入其他存储指令,为了安全需要加LOCK前缀来保证一条 指令存储访问的原子性,这又涉及2种情况,CACHE内语义和总线语义,如果访问数据已经CACHE在高速缓冲中,则CORE2不会在总线触发LOCK信 号锁定总线。非对齐数据的存储访问也是非原子的,因为需要1次以上的存储访问,这就是为什么SMP系统中内存访问指令需要加LOCK的原因,如XADD和 CMPXCHG指令都需要多次存储访问,访问其他CORE同时访问数据,必须LOCK。而单处理器上我觉得XADD,CMPXCHG之流应该无需加 LOCK,注意这里的非原子有两种情况,一种是但处理器一种是多处理器,在单处理器上一条指令的执行是原子的,不论他需要访问几次存储 器,RETIREMENT标志着一条指令的执行完毕,指令的RETIREMENT是指令顺序的,但执行不一定是。所以单处理器不存在同时指令多条指令的问 题

_BEGIN:

PAUSE

Cmp [sem], 0 //测试锁

JNE _ BEGIN

Mov [sem], 1 //得到锁

DO SOMETHING

Mov [sem], 0 //释放锁

很显然以上程序是错误的,因为

Cmp [sem], 0 //测试锁

JNE _ BEGIN

Mov [sem], 1 //得到锁

中间是可以被打断的,多个线程轻松的可以同时得到锁。我们需要一条原子操作既完成比较又完成赋值,让我们看看cmpxchg,

Mov eax, 0

_BEGIN:

PAUSE

Cmpxchg [sem], 1

JNE _BEGIN

DO SOMETHING

Mov [sem], 0

很显然没问题,只要有其中一个线程进入,其他的线程都会碌碌无为在前面循环,但这只是在单核CPU上有效,对 于多核可就没这么幸运了,因为多核上可能同时执行Cmpxchg [sem], 1这条指令,这条指令至少有2次存储访问(不对齐可能就会有4次访问),一次是读sem,一次是写sem,不论sem在内存还是在cache中,2个核中 的4次访问可能互相交叉,A READ SEM,B READ SEM, A WRITE SEM, B WRITE SEM,很显然错了。如何避免这种情况呢,便是加前缀LOCK,触发总线锁定信号,这样其他核必须等待总线释放后才能访问特点内存地址,对齐数据访问都是 原子的,跨DATA BUS宽度、CACHE LINE和页边界的都很可能不是原子的。显然不是原子的情况都是需要1次以上存储访问的,不管是CACHE还是总线。

在TEMPORAL语意的MEMORY区域上执行NON-TEMPORAL STORE是否需要程序保证数据一致性?

回答是肯定的,单独提出这个问题的主要原因是存在大量的NON-TEMPORAL STORE优化,主要是MOVNTQ等指令,这些指令是NON-TEMPORAL语意的,跟WC BUFFER一样,使用write combining buffer进行写缓冲,并且写是WEAK orDERING的,顺序和结果都会在此BUFFER中合并,如果FSB是64BIT的,一般WC BUFFER也是64字节,分8个CHUNK,通过FSB的8-Transfer Burst transcation一次(原子的)将数据传输到内存控制器,如果WC BUFFER并没用写满,则需要通过多次(非原子的)partial write transaction完成。对WB内存进行NON-TOMPORAL STORE需要注意的问题,对于已经处于CACHE之中的内存,则遵循WB语义,如果不在则遵循WC语义。SFENCE不见得能把NT STORE的数据FLUSH到内存中,SFENCE貌似只对WC BUFFER和STORE BUFFER中的有用,这就是所谓的全局可见性,在CACHE和内存中都具备全局可见性,而CORE内部的REGISTER FILE都不是,这三条指令具备执行屏障和使前面存储访问指令全局可见的效果。

Core2中到底有哪些缓冲?

1、L1(I/D) L2  L3 CACHE

2、TLBs(I/D)translation lookaside buffer

3、Loop Buffer

4、Store Buffer

5、Write Combining Buffer

注意Trace Cache只有NetBurst架构的微处理器才具备,CORE2没有。

5.未来发展趋势

离我们最近的就是Nehalem架构的CPU CORE I7,应该说相当的先进,SHARE BUS 的FSB从此消失,迎来的是QPI互联的原生4核,集成内存控制器,PCI-E控制器和IOMMU单元,北桥即将消失,甚至连GPU集成也已经可在 INTEL技术线路图中出现,对于底层程序员还是会有一定影响。详细请参看 《Inside Nehalem: Intel's Future Processor and System》。

[C#]浅谈MVP与Model-View-ViewModel(MVVM)设计模式

mikel阅读(1549)

转载:http://www.cnblogs.com/xiaoyin_net/archive/2009/03/09/1407258.html    
  微软的WPF带来了新的技术体验,如Sliverlight、音频、视频、3D、动画……,这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了

诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架

的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性揉合进去

,以应对客户日益复杂的需求变化。

      WPF的数据绑定与Presentation Model相集合是非常好的做法,使得开发人员可以将View和逻辑分离出来,但这种数据绑定技术非常简单实用,也是WPF所特有

的,所以我们又称之为Model-View-ViewModel (MVVM)。这种模式跟经典的MVP(Model-View-Presenter)模式很相似,除了你需要一个为View量身定制的

model,这个model就是ViewModel。ViewModel包含所有由UI特定的接口和属性,并由一个 ViewModel 的视图的绑定属性,并可获得二者之间的松散耦合,所以

需要在ViewModel 直接更新视图中编写相应代码。数据绑定系统还支持提供了标准化的方式传输到视图的验证错误的输入的验证。

如下图MVP设计模式架构所示。

                               

        在视图(View)部分,通常也就是一个Aspx页面。在以前设计模式中由于没有清晰的职责划分,UI 层经常成为逻辑层的全能代理,而后者实际上属于应用

程序的其他层。MVP 里的M 其实和MVC里的M是一个,都是封装了核心数据、逻辑和功能的计算关系的模型,而V是视图(窗体),P就是封装了窗体中的所有操

作、响应用户的输入输出、事件等,与MVC里的C差不多,区别是MVC是系统级架构的,而MVP是用在某个特定页面上的,也就是说MVP的灵活性要远远大于MVC

,实现起来也极为简单。

      我们再从IView这个interface层来解析,它可以帮助我们把各类UI与逻辑层解耦,同时可以从UI层进入自动化测试自动化测试(Unit/Automatic Test)并提

供了入口,在以前可以由WinForm/Web Form/MFC等编写的UI是通过事件Windows消息与IView层沟通的。WPF与IView层的沟通,最佳的手段是使用Binding

,当然,也可以使用事件;Presenter层要实现IView,多态机制可以保证运行时UI层显示恰当的数据。比如Binding,在程序中,你可能看到Binding的Source是

某个interface类型的变量,实际上,这个interface变量引用着的对象才是真正的数据源。

      MVC模式大家都已经非常熟悉了,在这里我就不赘述,这些模式也是依次进化而形成MVC—>MVP—>MVVM。有一句话说的好:当物体受到接力的时候,凡是有

界面的地方就是最容易被撕下来的地方。因此,IView作为公共视图接口约束(契约)的一层意思;View则能传达解耦的一层意思。

下面介绍一下MVVM设计模式。因为WPF技术出现,从而使MVP设计模式有所改进,MVVM 模式便是使用的是数据绑定基础架构。它们可以轻松构建UI的必要元素。

如,下图所示MVVM架构图。

                                

      可以参考The Composite Application Guidance for WPF(prism),prism V2下载源码

      View绑定到ViewModel,然后执行一些命令在向它请求一个动作。而反过来,ViewModel跟Model通讯,告诉它更新来响应UI。这样便使得为应用构建UI非常

的容易。往一个应用程序上贴一个界面越容易,外观设计师就越容易使用Blend来创建一个漂亮的界面。同时,当UI和功能越来越松耦合的时候,功能的可测试性就

越来越强。

      在MVP模式中,为了让UI层能够从逻辑层上分离下来,设计师们在UI层与逻辑层之间加了一层interface。无论是UI开发人员还是数据开发人员,都要尊重这个

契约、按照它进行设计和开发。这样,理想状态下无论是Web UI还是Window UI就都可以使用同一套数据逻辑了。借鉴MVP的IView层,养成习惯。View Model听

起来比Presenter要贴切得多;会把一些跟事件、命令相关的东西放在Controler里。

      参考示例:PersonViewModel层

public FamilyTreeViewModel(Person rootPerson)
{
    _rootPerson 
= new PersonViewModel(rootPerson);
    _firstGeneration 
= new ReadOnlyCollection<PersonViewModel>(
        
new PersonViewModel[] 
        { 
            _rootPerson 
        });
    _searchCommand 
= new SearchFamilyTreeCommand(this);
}

 在这里我不在赘述,详细应用实例参考:

Simplifying the WPF TreeView by Using the ViewModel Pattern

源码下载

[C#]Grove——.NET中的ORM实现

mikel阅读(1156)

作者:林学鹏

ORM的全称是Object Relational Mapping,即对象关系映射。它的实质就是将关系数据(库)中的业务数据用对象的形式表示出来,并通过面向对象(Object-Oriented)的 方式将这些对象组织起来,实现系统业务逻辑的过程。在ORM过程中最重要的概念是映射(Mapping),通过这种映射可以使业务对象与数据库分离。从面 向对象来说,数据库不应该和业务逻辑绑定到一起,ORM则起到这样的分离作用,使数据库层透明,开发人员真正的面向对象。图 1简单说明了ORM在多层系统架构中的这个作用。

art\grove_001.jpg

图1:ORM在多层系统架构中的作用

目 前大多数项目或产品都使用关系型数据库实现业务数据的存储,这样在开发过程中,常常有一些业务逻辑需要直接用写SQL语句实现,但这样开发的结果是:遍地 布满SQL语句。这些高藕合的SQL语句给系统的改造和升级带来很多无法预计的障碍。为了提高项目的灵活性,特别是快速开发,ORM是一个不错的选择。举 个简单的例子:在使用ORM的系统中,当数据库模型改变时,不再需要理会逻辑代码和SQL语句中涉及到该模型的所有改动,只需要将该模型映射的对象稍作改 动,甚至不做改动就可以满足要求。

*

本页内容
一、ORM的工具实现:Grove 一、ORM的工具实现:Grove
二、Grove在开发中的实际应用 二、Grove在开发中的实际应用
三、总结 三、总结

一、ORM的工具实现:Grove

优秀的ORM工具不仅可以帮助我们很好的理解对象及对象的关系,而且工具本身会帮助我们维护这些关系。基于这个理念,我设计了基于.NET的ORM工具——Grove orM Development Toolkit。

Grove orM Development Toolkit包含Grove和Toolkit两部分内容。Grove为ORM提供对象持久、关系对象查询、简单事务处理、简单异常管理等功能。数据持久 包括一些对象的Insert、Delete、Update、Retrieve等功能,关系对象查询则提供一些基于对象的复杂关系查询,包括对应到数据库功 能的子查询、关联查询(JOIN)、函数支持(count、avg、max、min)、聚合等。Toolkit是基于VS.NET 2002/2003的VSIP开发的外接程序,职责是帮助开发人员快速映射关系数据库中的业务模型到符合Grove要求的映射实体类,以及映射数据库中复 杂关系查询到Grove要求的关系映射实体,暂时只提供C#支持。图 2是Grove内部类实现关系图。

art\grove_002.jpg

图 2: Grove内部类实现关系图

在ORM实现的前期工作中,为了实现屏蔽各种数据库之间的操作差异,我们需要定义数据操作公有接口,封装基本的数据库Insert,Update,Delete,Query等操作。

public interface IDbOperator
{
int ExecNonQuery(string cmdText);
int ExecDataSet(string cmdText,DataSet entity);
object ExecScalar(string cmdText);
…
}

再定义一个数据库操作工厂类,实现各种不同类型数据的适配。

public abstract class DbOperatorFactory:IDbOperator

然后实现各种数据库的操作类,以SQLServer为例。

internal class SqlDbOperator:DbOperatorFactory

完成后,就是ORM主角——实体(Entity)的实现。ORM中实体的定义可以通过实体类自身包含数据模型元数据的方式实现,也可以通过定义XML的元描述实现。下面讲述了通过实体类自身映射的实现。

实 体(Entity)是实际业务数据的载体,包含业务数据模型的元描述,可以直接由数据库中的某张表或视图生成,也可以根据需要手工创建。.NET中提供了 System.Attribute,该类包含访问和测试自定义属性的简便方法。.NET Framework预定义了一些属性类型并使用它们控制运行时行为。我们可以通过继承System.Attribute基类自定义用于描述实体对象映射时 所需要的数据模型元数据,包括表名,字段名,字段长度,字段类型等一些常用的数据。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class DataTableAttribute : Attribute

AttributeUsage用来表示该自定义属性可以被绑定在什么样的对象上,这里表示应用在Class或者Struct之上。

抽象一些具有相同特征的属性,使之成为自定义属性的基类。

[AttributeUsage(AttributeTargets.Property)]
public class BaseFieldAttribute:Attribute

定义一般字段所需要的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]
public class DataFieldAttribute : BaseFieldAttribute

定义关键字字段所需的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]
public class KeyFieldAttribute : BaseFieldAttribute

定义外键字段所需要的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]
public class ForeignKeyFieldAttribute : BaseFieldAttribute

在以上自定义属性类完成后,我们需要一个用于访问实体在运行期绑定的自定义属性及属性数据的一个Help类。

internal class TypeHelper

实体定义完成后,我们需要根据实体类中绑定的自定义属性构造出运行期需要的SQL语句,为了收集实体类定义中的数据结构描述,我们需要定义一个类来说明实体在运行期所引用到的所有关于数据持久的信息,包括关键字字段,外键字段,一般字段等。

internal class TypeInfo

同时需要一个字段元数据描述类,描述字段在数据库中的名称,大小,是否可为空,列类型等信息。

internal class ColumnInfo

以上条件具备后,我们需要定义一个解析类,负责转换数据的程序类型到数据库字段类型,并且构造出Insert,Update,Delete,Query等操作所需要的SQL语句。

internal class SqlEntityParser

将上面的操作组合起来就是实体类对象操作员。

public class ObjectOperator

实现新增一个记录到数据库中,就是创建了一个新的实体对象,并交由对象操作员进行持久化。

public void Insert(object o)
{
TypeInfo info1=new TypeInfo(o.GetType());//根据实例或者实体描述信息
SQLCommand sc=info1.BuildInsertCommand(o);//构造SQL命令对象
DbOperator.Parameters=sc.Parameters;//赋值SQL命令所需的参数
DbOperator.ExecNonQuery(sc.CommandText);//执行SQL命令
}

这里的SQLCommand对象封装了SQL命令处理时所需要的一些值,包含SQL语句,命令参数(Parameter)等。

二、Grove在开发中的实际应用

安装Grove Kit要求Visual Studio 2003 及.NET Framework 1.1支持。从Grove网站下载安装包之后,解压缩GroveKit.zip,执行安装。

在GroveKit安装结束后,打开VS.NET,在VS.NET的启动画面上,您会看到Grove Develop Kit的标志,表示GroveKit已被正确安装。

2.1生成映射实体类

本文将以C# 项目为例解释Grove在开发中的具体应用。项目名WebApp1,操作系统 Windows 2000,数据库SQL Server 2000,数据库实例名:WebApp1,表结构定义如下:

表名 字段

Customers

CustomerID int(4) PK

CustomerName varchar(50)

CustomerDesc varchar(200)

Status tinyint

Addresses

AddressID int(4) PK

CustomerID int(4) FK

Address varchar(200)

1.

在 VS.NET中,打开“文件->新建->项目”,在Visual C#项目选择ASP.NET WEB应用程序,确定后生成WebApp1项目,在项目中添加对Grove.dll的引用,Grove.dll位于GroveKit的安装路径下,您也可 以通过.NET Configuration将Grove添加到程序集缓存中。

2.

在VS.NET中,打开“工具->Grove Tool Kit”,在GroveToolKit中设置数据库连接属性,并保存。

art\grove_003.jpg

图3 设置数据库连接串

3.

配置当前Web项目的web.config(在</configuration>之前加入以下配置)

<appSettings>
<add key="DBConnString" value="Server=localhost;Uid=sa;Pwd=sa;Database=WebApp1" />
</appSettings>

4.

4)在VS.NET解决方案资源管理器中选中Entities,并在GroveToolKit中选择表名,点击GroveToolKit的toolbar中的Preview Entity Class按钮,出现该表的实体映射类预览窗口。

art\grove_004.jpg

图4 预览实体映射类

5.

检查当前预览的实体类,点击生成文件按钮,该实体类将被生成到解决方案资源管理器当前选中的路径下。

6.

重复4,5步骤就可以生成其他表的映射实体类。

Customer.cs
using System;
using Grove.ORM;
[DataTable("Customers")]
public class Customer
{
int _CustomerID;
string _CustomerName;
string _CustomerDesc;
int _Status;
[KeyField("CustomerID")]
public int CustomerID
{
get{return this._CustomerID;}
set{this._CustomerID=value;}
}
[DataField("CustomerName")]
public string CustomerName
{
get{return this._CustomerName;}
set{this._CustomerName=value;}
}
[DataField("CustomerDesc")]
public string CustomerDesc
{
get{return this._CustomerDesc;}
set{this._CustomerDesc=value;}
}
[DataField("Status")]
public int Status
{
get{return this._ Status;}
set{this._ Status=value;}
}
}
Address.cs
using System;
using Grove.ORM;
[DataTable("Addresses")]
public class Address
{
int _AddressID;
int _CustomerID;
string _Address;
[KeyField("AddressID")]
public int AddressID
{
get{return this._AddressID;}
set{this._AddressID=value;}
}
[ForeignKeyField("CustomerID")]
public int CustomerID
{
get{return this._CustomerID;}
set{this._CustomerID=value;}
}
[DataField("Address")]
public string CustomerAddress
{
get{return this._Address;}
set{this._Address=value;}
}
}

代码1.实体映射类

2.2对象持久化

Grove提供ObjectOperator实现对映射实体对象的数据库持久工作,并通过IObjectQuery接口实现对复杂数据库关系映射实体的查询,主要接口如下:

方法 说明

Insert

新增一个对象

Update

根据条件更新一个对象

Remove

根据条件删除一个对象

RemoveChilds

删除所有关系对象

Retrieve

返回一个对象

RetrieveChilds

返回所有关系对象

GetDataReader

返回IDataReader

GetObjectSet

返回对象集合

GetObjectSource

根据对象定义返回DataSet

GetCount

从数据源返回记录条数

BeginTranscation

在数据库支持事务的基础上,开始事务处理

Commit

完成当前事务

Rollback

回退当前事务

2.3数据查询

如 一般的关系型数据库所具有的查询功能一样,Grove也有着非常丰富的查询功能,如对象查询、函数查询、子查询、排序查询等。这里对对象查询做简单介绍, 其它查询读者可以自行参考Grove的开发文档。Grove提供ObjectQuery 帮助ObjectOperator从数据源查询数据, ObjectOperator 需要通过ObjectQuery解析实体对象中的属性(System.Arrtibute)定义,并构造查询语句。ObjectQuery在运行时往往需 要定义筛选语句(请参考筛选语句的语法定义)。例如,检索Customer对象,当State 属性等于WA的情况:

ObjectQuery query=new ObjectQuery(typeof(Customer),"this.State='WA'");

当检索需要返回所有对象时,则不需要定义筛选语句

ObjectQuery query=new ObjectQuery(typeof(Customer),"");

2.4筛选语句的语法定义

在ObjectQuery中使用的筛选允许你在定义的时候,根据使用面向对象语法规则进行定义筛选语句。

操作 描述

!, not

用于比较布尔型,例如:

!Order.CustomerID.Contains(Customer.CustomerID)

<, >, <= , >=

用于值比较,例如:

Order.Quantity >= 12

=, !=, <>, = =

用于值判断,例如:

Customer.Country = 'USA' and Customer.Region != 'WA'

and, &&

用于逻辑判断,例如:

Customer.Country = 'USA' and Customer.Region = 'WA'

or, ||

用于逻辑判断,例如:

Customer.LastName = 'Smith' or Customer.LastName = 'Jones'

三、总结

以 上就是ORM的简单实现,复杂的关系对象映射及关系映射实体的查询也是ORM中尤为重要的一块处理,为了屏蔽各数据库之间的SQL差异,很多好的ORM框 架都提供一种符合面向对象语言本身语法规则的Query Language支持,例如实现对数据库函数的支持时,会通过定义一些公开的,与编程语言接近的语言来实现,比如说定义 Object.Size(),Object.Sum()等类方法式操作语法,在逻辑判断的时候提供一些语言本身的逻辑运算符支持,比如c#中 的&&表示and,||表示or等等这些一系列的面向对象编程风格的支持,都很好地为基于关系型数据库支持的系统开发向“面向对象”提供 了有力的支持。Grove目前对关系对象查询有很好的支持,感兴趣可以到Grove的网站了解详细信息。

[Javascript]等比例缩放图片内容

mikel阅读(802)

window.onload=fiximage;
function fiximage() {
    var max=580;
    imgs = document.getElementsByTagName('img');
    for(i=0;i<imgs.length;i++) {
    w=imgs[i].width;h=imgs[i].height;
    if(w>max) { imgs[i].width=max;imgs[i].height=h/(w/max);}
    }
}

[JQuery]TextArea的取值问题

mikel阅读(901)

JQuery中读取TextArea的值,以前一直用
$("#textarea").text();
读取,最近测试时候发现在firefox中读取不出textArea的值,IE正常
于是修改为:
$("#textarea").val();
问题解决,不过搜索时,发现有人提另一个问题:
当在一个textarea标签中键入一个回车时,实际上会插入2个符号:\n\r \n 回车符 \r 换行符 如果用text()获取textarea中的值,那么存入数据库的数据就只会有\r 如果用var()获取textarea中的值,那么存入数据库的数据就只会有\n 这样的区别就是,在IE下,你如果是读取用text()存入的数据在展示在textarea中,那么数据的换行是正常的。而读取用var()存入的数据在展示在textarea中,那么数据的就不会换行。
没有具体测试过看来用val()也不妥当

[项目管理]项目管理实践系列文章

mikel阅读(693)

项目管理实践【一】工欲善其事,必先利其器【Basic Tools】

项目管理实践【二】版本控制【Version Control Using VisualSVN Server and TortoiseSVN】

项目管理实践【三】每日构建【Daily Build Using CCNET and MSBuild】

项目管理实践【四】Bug跟踪管理【Bug Trace and Management】

项目管理实践【五】自动编译和发布Using Visual Studio with Source Control System to build and publish website automatically

项目管理实践【六】自动同步数据库【Using Visual Studio with Source Control System to synchronize database automatically】

[SEO]SEO专题之三:SEO与网站开发

mikel阅读(829)

  继续来发第三篇文章.在发文之前.回应一下前面几位朋友的留言,关于怎么提高PR 值,我在后面的系列中会具体讲解.PR值google的更新时间是无法确定的.一般二到四个月更新一次,SEO是一门技术.不是投机取巧.也不是钻空子, 虽然也有很多站点也确实钻了SEO的空子(但这样做的代价危险性可想而知).步入正题:
    这篇我从程序开发的角度来讲解在网站开发的过程中从SEO的角度需要注意一些什么方面,我只会C#下的ASP.NET,所以本章也是从ASP.NET开发的角度来说.但从事asp/php的程序员也可以基本可以照搬.
    我们先把google的设计指南中的话先copy过来,然后再一步一步讲解
     设计与内容指南

* 网站应具有清晰的层次结构和文本链接。 每个网页应至少可以通过一个静态文本链接打开。
* 为用户提供网站地图,列出指向网站重要部分的链接。 如果网站地图上的链接超过或大约为 100 个,则需要将网站地图拆分为多个网页。
* 网站应实用且信息丰富,网页文字应清晰、准确地表述要传达的内容。
* 要考虑到用户会使用哪些字词来查找您的网页,确保网站上确实包含了这些文字。
* 尽量使用文字而不是图片来显示重要的名称、内容或链接。 Google 抓取工具无法识别图片中所含的文字。
* 确保 <标题> 元素和 ALT 属性具有描述性且准确无误。
* 检查链接是否损坏,并确保 HTML 格式正确。
* 如果要使用动态网页(即网址中包含"?" 字符),请注意并非每一个搜索引擎抓取工具都能抓取动态和静态网页。缩短参数长度和减少参数数目都会对这种情况有帮助。
* 将特定网页上的链接限制在合理的数量内(少于 100 个)
质量指南 – 具体指南
* 请不要使用隐藏文本或隐藏链接。
* 请不要使用隐藏真实内容或欺骗性的重定向手段。

* 请不要向 Google 发送自动查询。
* 请不要加载使用无关关键字的网页。
* 请不要创建包含大量重复内容的多个网页、子域或域。
* 请不要制作欺诈性或安装有病毒、特洛伊木马或其他有害软件的网页。
* 请不要专门针对搜索引擎创建"桥页",或使用其他如联属计划这类原创内容很少或几乎没有原创内容的俗套 (cookie cutter) 方法。
* 如果您的网站参与联属计划,请确保您的网站可为其增添价值。 请提供独特且相关的内容,使用户有理由首先访问您的网站。
这篇文章的出处:http://www.google.com/support/webmasters/bin/answer.py?answer=35769,
我在原有的基础上补充几点:

1.文件命名不宜过长.网站设计中不能出现死页面.死链接.错误链接.空链接.文件名应该富有意义(这点的出发点似乎是为了更容易理解文件的大概内容)
2.除非呈现数据.否则布局不要用table

3.URL地址,通过搜索得知.静态页面以及伪静态页面和动态页面google是一样可以收录的.但google建议参动态页面参数不宜过长.我的建议一般不要超过三个,但哪种页面google最亲睐,我们得先来了解一下google收录的基本原理和规律.

    google会根据你的网站首页(或其它页)来遍历该页面的其它链接.例如:你的首页有100个超链接.那么google会遍历你的这100个链接页面. 再根据其它的页面的链接一个一个遍历直至整站遍历完成.如果中途出现很多死链接,错误链接或死页的话.google就会认为你这个网站错误百出.可能中止 遍历,从而影响你页面的收录效果.那么带参数的动态页面或伪静态页是否会影响收录呢?答安是肯定的.再举个例子:如有一个显示产品详细内容的页 面:www.a.com/products.aspx?id=x的网页.那么有100种产品是存在数据库里面的.根据不同的ID值来通过 products.aspx?id={1-100}中的<%#Eval("数据库字段")%>来显示相应的产品内容.那么看似有100个页 面.而实际上只有products.aspx这一个页面.而google会遍历你的数据库记录吗?不会.所以你有100个产品介绍.可能只能收录一个页 面!(这种形式是很多cms或企业站所采用的方式),那么有办法能收录这100个页面吗?答安是:可以.折中的选择方案是做一个产品列表页如 productlist.html(aspx)(这个页面应该是手工静态页或后台生成静态页.,只要不从数据库里面读数据就可以),该页面内容如下:

<a href="products.aspx?id=1">球阀</a>
<a href="products.aspx?id=2">闸阀</a>
…….
上面的内容应该静态生成.那么google在遍历productlist.aspx(html)页面的时候.就会遍历这些产品相应的地址了.遍历地址时会根据这个地址是否返回404错误而缓存相应的页面内容..(原理很简单..说了一大堆.不知道大家能否理解)
4.不要轻易网站内页面文件名
   google一旦收录了这个页面.而不久你又将这个页面删除或改名.那么GOOGLE再次收录的时候发现这个页面不见了.肯定对你的PR值是有影响的
5.图片的alt属性不要为空.而且内容与你的关键字有关(后面详解)
6.一定要在web.config里面定义404错误转向.这个转向页面里面最好还要定义转向各个重要页面的链接
再加一点:
 7.无论在站点内的哪个页面.你必须保证你可以在当前页通过页面与页面之间的链接能跳转到任何一个页面(好像有点别扭.就是说你的页面必须不可缺少正确的导航)

 

   

非淡泊无以明志,非宁静以致无以致远

[SEO]seo专题之二:网站pr值

mikel阅读(901)

    什么是Pr值?pr是英文PageRank的缩写,中文翻译过来中网页级别.网页排名.wiki的解释:是一种由搜索引擎根据网页之间相互的超链接计算的 网页排名技术,以Google公司创办人拉里·佩奇(Larry Page)之姓来命名。此技术通常和搜索引擎优化有关,Google用它来体现网页的相关性和重要性。Google的创始人拉里·佩奇和谢尔盖·布林于 1998年在斯坦福大学发明了这项技术.
  我们来通俗的解释一下这段话:pr值是google特有的网页评级标准,它仅对google有效.baidu,yahoo等其它是没有这个评级标准的.这 个评级的范围是0-10,那么这个值对网站和网页能够起到什么决定性的作用呢?通常来讲.网站PR值越高google就认为该网站对浏览者来说越有价值, 资料越具有权威性,则搜索引擎对该站点的抓取和收录频率越高,页面PR值越高则排名越靠前.那么该怎么样查看站点和页面的PR值呢?下面我们隆重请上 serachstatus(一款firefox下的插件,没有装firefox的要先装上了),官方下载地址:http://www.quirk.biz /searchstatus/,安装之后在浏览器状态栏右下角就可以看到如下图标, 现在大家看到的绿色条就是cnblogs.com的PR值哦 .该值为6,蓝色条为alexa的排名(暂且不表),一般网站PR值能大于或等于6就已经相当不错了(作弊的除外),当我们访问cnblogs里面的不同 页面时.pagerank都会准确的显示出来 ,大家在浏览的时候发现不同页面的PR值是不一样的.那么站点PR值与页面PR值到底有什么区别和联系呢.下面我们来举例说明:
   假设:www.a.com站点PR值为6,www.a.com/xx.html的页面PR值为5,该页面的关键字为"阀门"
        www.b.com站点PR值为5,www.b.com/xx.html的页面PR值为6,该页面的关键字同样也为"阀门".
     那么当用户在搜索"阀门"关键词时哪个站点的xx.html页面的排名会靠前呢?一般来说(90%的可能),www.b.com/xx.html 的页面排名会靠前,因为它的PR值比较a站点的高.google会认为这个页面比b站点的xx.html页面更具有参考价值和权威性.那么还有10%的不 确定性在哪里?那就是google会分析你这个页面的关键词密度,创建时间,页面相似性等因素.来判断你是否有作弊嫌疑,如果认为有则有可能PR值高的页 面可会排在后面(这点我们在后面文章将进一步分析).

    我们都知道.网站PR值一般就是指首页的PR值了.因为打开网址自动加载首页.我们可以看到博客园首页是看不到地址的.但根据PR值大概也可以分析出来: 博客园首页的默认转向文件名应该是index.html或index.htm(大家可以尝试不同的默认首页文件名来判断),那么网站PR值高有什么好处 呢?还是以上面两个网址来举例:
   a站点和b站点在同一时间同时更新了网站内容,添加了不少新的页面,那么PR值高的站点的新的页面google会先收录.当然两个站点的PR值差距越大.收录时间的差距一般来说也就越大(不能绝对),同时页面PR值差距越大.页面在搜索中的排名也就差距越大.
   综上所述:页面PR值是影响当前页面排名的.网站PR值(一般指首页PR值)是影响站内所有页面收录频率的.当然它也影响页面排名了.它不也是指首页嘛!!
   下一篇:SEO与网站开发,敬请期待!!

[SEO]SEO专题之四:如何合理有效选定关键字

mikel阅读(811)

   上一篇我们讲到了SEO网站开发的中的注意事项,这篇文章继续结合上一篇内容继续讲解,如何合理有效的选定关键字.
    我们都知道.搜索引擎的工作是按你在文本框内输入的关键字来查找内容相匹配的网页.如果查找到则在搜索列表中显示出来,那么是不是你只要指定了相应的关键 字浏览者就一定能看到你的网页呢.非也!!如果你的页面排到十几页之后.那么有谁能翻到十几页之后再查找符合要求的信息网页呢.按照我们一般的搜索习惯. 一般最多看前两页,或许大部分浏览者只是看第一页,所以我们要想方设法将自己的页面排到第一页.或第一页前几位(这对于一个新站来说做通用关键字非常难).还是通过例子来说明这件事情
   先来了解HTML页面结构
   <html>

   <head>

   <title>xx</title>
   <meta name="keywords" content=""/>
   <meta name="descritpion" content="">

   </head>
   <body>
       xx
   </body>

   </html>
   搜索引擎在区配关键词同时会按HTML页面结构来区配关键字内容(有点像遍历二叉树,不知道这种说法对不对.本人数据结构没学好.),按此理解.它的搜索 顺序为html-head-title-meta-body-div..由此看来title是指定关键字最重要的部分(这点我们在下一章再重点讲解),关 键字如何选?同样我们也要结合一个工具来做分析,,下载地址:http://ff.SEOquake.com/,安装过程就不多说了.运行成功之后在 google搜索时界面截图如下:
   
    在每个页面下都有相应的PR值.外链接.和收录页面提示.通过这个页面我们就可以分析到各个关键字的强度及排名情况,以及重点竞争对手的排名情况.分析关键字应该从哪几方面着手呢?
   1.关键字收录页面数,相比较之下.收录页面数越多.关键字越难做
   2.搜索列表首页网站的PR值,一页只有10个名额.如果这10个网站的PR值普遍越高.关键字越难做
   3.搜索列表首页网站的外链数,外链数越多,超过它越难.
   4.google收录的该站点页面数.收录数越多,超过它越难.|
  这是几个基本的分析点.但我们可以看到.有些PR值低的页面也排到了PR值高的网站前面.这是因为google排名不仅仅依据上面所列举的这四点,我们还 应该分析排在前面的页面的关键字放置的位置.以及页面关键字的密度.这个我们可以通过seoquake的pageinfo可以分析到(见图):
 

   所以.要想排名靠前.要考虑的因素很多.而google的排名算法一直是没有公开的.这点我们就需要平时经验的不断积累了.我们不能够太相信PR值对网站排名的绝对影响.但也不能忽视,所以选一个好的关键词比做1000个外链来的效果要好得多.
下一节将重点关键词在title,keywords,description中的应用..

非淡泊无以明志,非宁静以致无以致远