NBearV3 Step by Step教程——ORM进阶篇

版本

1.2 [2006-11-12]

简介

本教程在前一篇《NBearV3 Step by Step教程——ORM》的基础上,演示前文中没有涉及的实体自关联关系;及和性能相关的Attribute的设置:IndexPropertyBatchUpdate;并将详细比较和讨论NBear.Data.Gateway类中的强类型查询方法的使用和注意事项,特别是在不同的Attribute设置选项下的性能差异分析。

注:在阅读本文之前,建议读者先阅读《NBearV3 Step by Step教程——ORM》以掌握NBearV3中有关ORM的基本知识。

目标

通过本教程,读者应能够更全面地掌握使用NBearV3ORM模块进行应用程序设计的过程,了解实体设计中与性能相关的重要选项,并能全面掌握NBear.Data.Gateway中各种强类型查询方法的使用。

代码

本教程演示创建的所有工程和代码,包含于可以从sf.net下载的NBearV3最新源码zip包中的tutorials\ORM_Adv_Tutorial目录中。因此,在使用本教程的过程中如有任何疑问,可以直接参考这些代码。

时间

<30分钟。

正文

Step 1 下载NBearV3最新版本及准备

1.1访问http://sf.net/projects/nbear,下载NBearV3的最新版本到本地目录。

1.2 将下载的zip文件解压至C:\,您将看到,加压后的NBearV3目录中包括:distdoccasessrctutorials等目录。其中,在本教程中将会使用的是dist目录中的所有release编译版本的dllexetutorials目录中之前的ORM基础教程。

1.3 tutorials目录中的整个ORM_Tutorial目录复制到任意其它位置,并命名为ORM_Adv_Tutorial,我们将以ORM_Tutorial为基础,演示NBearV3中的ORM的进阶知识。

Step 2 扩展设计实体及元数据

2.1 ORM_Adv_Tutorial中的ORM_Tutorial.sln重命名为ORM_Adv_Tutorial.sln,并在VS2005开发环境中打开。

2.2 EntityDesigns工程的Group.cs文件中,添加ParentID属性,并为ParentID属性添加IndexPropertyAttribute设置如下:

        [IndexProperty]
        Guid ParentID
        
{
            
get;
            
set;
        }

将属性标记为IndexProperty,表示在NBear.Tools.EntityDesignToEntity.exe生成的数据库创建脚本中,将自动为该属性创建一个单列索引。我们都理解数据库索引的作用——这将有助于改善以该属性为条件的查询性能。

2.3 还是在Group.cs文件中,我们为Group新增一个SubGroups属性如下:

        [FkQuery("ParentID", Contained=true, LazyLoad=true)]
        Group[] SubGroups
        
{
            
get;
            
set;
        }

我们可以看到,SubGroups属性的设置方式和普通的1对多关联的属性设置方式没什么两样,但是,可以注意到,它其实是Group实体1对多关联到Group实体自己,也就是说,它是一个1对多的自关联。

注:对于1对1自关联,也可以以类似的方式设置。但是,NBearV3还不支持多对多的自关联,也不支持一个继承体系中的类的多对多关联,例如,不支持User和LocalUser的多对多关联。

2.4 User.cs文件和LocalUser.cs中,为UserLocalUser实体添加一个BatchUpdateAttribute如下:

    [BatchUpdate(10)]
    
public interface User : Entity
    
{
      \\
    }


    [BatchUpdate(
10)]
    
public interface LocalUser : User
    
{
      \\
    }

BatchUpdate这个Attribute对于该实体的查询性能将有重要影响。当使用BatchUpdate标记一个实体时,实体的Save和Delete级联操作,将在内部自动使用一个BatchGateway,以批更新方式执行。BatchUpdate的构造参数代表每多少个作为一个batch,连接数据库,并执行。举例来说,假如原来,User实体的一个实例Delete的时候,由于User实体自己,及所有User中以Contained这个Attribute标记的属性对象的数量一共有20个应该被自动Delete掉,那么,要连接20次数据库,执行20次Delete;而在设置了BatchUpdate(10)的情况下,因为每十个查询才连接一次数据库,所以,实际上,只需要连接两次数据库,每次分别发送并执行10个Delete操作。很显然,BatchUpdate对性能的改善是惊人的

Step 3 从实体设计代码生成实体代码、实体配置文件和数据库生成脚本

3.1 至此,所有的实体的设计就扩展完毕了。编译EntityDesigns工程。

3.2 运行dist目录中的NBear.Tools.EntityDesignToEntity.exe工具,载入EntityDesigns工程编译生成的EntityDesigns.dll

3.3 点击Generate Entities按钮,将生成的代码保存到Entities工程中的一个名叫Entities.cs的新代码文件。

3.4 点击Generate Configuration按钮,将生成的代码保存到website工程下的名为EntityConfig.xml的文件中。

3.5 点击Generate DB Script按钮,将生成的代码保存到website工程下的名为db.sql的文件,可以在某个新建的SQL Server数据库中执行这些脚本,创建对应于所有实体的数据库脚本。对于本教程而言,建议使用SQL Server 2000的查询分析器,在tempdb数据库中执行db.sql中的脚本。

Step 4 使用Gateway进行查询

4.1删除website工程中的Default.aspx.cs文件中原来的代码,参考tutorials\ ORM_Adv_Tutorial\website目录下的Default.aspxDefault.aspx.cs,创建Default.aspx。这些代码演示了Gateway类的大多数强类型查询方法的使用。关于Gateway支持的更多方法的介绍,可以参考doc目录下的SDK类库文档。

4.2 运行以上代码,在输出文本框内,您将得到详细的SQL调试信息及相关说明。

在运行结果中,大家可以注意比较以“TEXT 内容”格式出现的SQL日志,这些日志显示了何时,NBearV3的强类型查询在内部执行了什么样的SQL查询。

有两个地方需要特别留意比较的,一个是BatchUpdate后非BatchUpdate方式下的Save和Delete时,实际执行的SQL语句;另一个是,注意LazyLoad=true和LazyLoad=false的属性,载入的时机的不同

正文结束。

附录

1 关于Entity.Attach()/Detach()/IsAttached()方法的使用

细心的读者会发现,NBearV3中,保存实体只有Save方法,而不区分Insert还是Update。那么,是如何区分一个实体什么时候该Insert,什么时候该Update的呢?

NBear判断的是Entity.IsAttached()方法。一个刚刚new出来的实体实例,总是IsAttached() == false的,因此,当Save它时,实际会执行Insert,而一个通过Find返回的实体实例,则总是IsAttached() = true的,当保存这样的实体时,只有修改过的属性会被Update

理解以上这一点有什么作用呢?在需要的情况下,我们可以灵活地直接调用Entity.Attach()/Detach()来修改IsAttached()的值,从而实现一些特殊需求的查询

例如:

假如我们想更新User对象的Status,而我们的输入参数只有Userid。如果不了解Attach()/Detach()方法,那么,只有先通过Gateway.Find方法找到ID=idUser实例,修改Status,再Save它。这至少需要两次数据库查询,一次Select,一次Update。更有效的做法是,我们可以new一个User的实例user,手动设置这个user.Attach(),修改userStatus,再Save它。这样,这个user被保存时,也只会Update IDidUserStatus属性,但是,此时,只需要一次数据库查询,就是Update

相反的,Detach()方法,可以设置一个Attached的实体实例的IsAttached() = =false。这有什么用呢?

例如:

我们已经通过某些渠道得到了一个User的实例user,在某个算法中,我们可能要频繁的写User的属性,最后,才会保存这个user。如果不设置Detach(),则实体属性的每次修改都会触发Entity.OnPropertyChanged事件,这不仅意味着性能损失,也意味着,Entity.OnPropertyChanged的订阅者可能要响应很多不必要的事件变更事件。此时,理想的方法是,在频繁的写User的属性的算法执行之前,我们先Detach(),算法完成后,我们再Attach()

2 Gateway.RegisterSqlLogger()/UnregisterSqlLogger()

您应该已经注意到,Default.aspx.cs文件中的Page_LoadGateway.RegisterSqlLogger()的使用:

        gateway.RegisterSqlLogger(new LogHandler(WriteLine));

对应于注册一个SqlLogger,我们也可以调用UnregisterSqlLogger()来注销一个SqlLogger

这两个方法对于调试应用程序的运行和程序性能的优化非常重要,建议大家在开发中一定要注意使用,从而有效监视NBear提供的强类型外衣下的,真正的程序和数据库的交互细节。

//本文结束

posted @ 2006-11-05 15:42  Teddy's Knowledge Base  Views(7672)  Comments(14Edit  收藏  举报