NBearV3 Step by Step教程——ORM篇

原文地址为: NBearV3 Step by Step教程——ORM篇

版本

1.7 [2006-1-16]

简介

教程演示如何基于NBearV3ORM模块开发一个Web应用程序的全过程。本教程演示的实体关系包括:继承、11关联、1对多关联,多对多关联。同时,本教程还演示如何设计实体属性为nullable类型或符合类型。

注:所谓nullable类型主要是针对之类型而言的,.Net2.0位所有的值类型支持nullable,设为nullable的值类型,允许是null的,这样,就可以映射数据库中的null;而符合类型指这个属性是一个复合类型,但是,保存到数据库的时候,整个复合类型序列化后保存为一个数据表的字段的值。

目标

通过本教程,读者应能够掌握使用NBearV3ORM模块进行应用程序设计的基本过程,以及开发过程中,NBearV3提供的相关工具的使用方法。

代码

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

时间

<45分钟。

正文

Step 1 下载NBearV3最新版本

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

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

Step 2 创建应用程序解决方案

2.1 打开VS2005开发环境,新建一个空的解决方案sln

2.2 sln中添加两个新建的C#类库工程,两个类库工程的名称分别为EntityDesignsEntities,删除IDE自动创建的Class1.cs文件。

2.3 sln中新建一个名叫websiteASP.NET Web应用程序,为website添加一个Web.config文件。

Step 3 设计实体及关系

3.1 2.2创建的EntityDesigns工程中,新建一个名为ClassDiagram.cd的类图文件。注:如果您的IDE不支持类图设计,或者您更习惯写代码,您也可以参照下面的步骤直接创建代码。

3.2EntityDesigns工程添加到dist目录下的NBear.Common.Design.dll的引用。因为下面的每一个设计实体接口必须继承自NBear.Common.Design.Entity这个接口。在Entities工程中创建一个名为UserNamestruct包含FirstNameLastName两个string类型的Field。同时在Entities工程中创建一个名为UserStatus的枚举类型,包含两个枚举选项:AvailaleDeleted。注:这两个类型将用于后面的设计实体的设计。之所以这两个类型定义在Entities工程中而不是EntityDesigns工程中是,最终,所有生成的实体将放在Entities工程,且Entities工程最后对EntityDesigns工程是没有依赖关系的。

3.3 双击ClassDiagram.cd打开设计界面,您现在就可以设计实体了。注意,所有的设计实体必须是接口。为了使用3.2创建的类型,需要让EntitDesigns工程引用Entities工程。

3.4 向类图中添加一个User接口,继承自NBear.Common.Design.Entity。添加属性IDNameStatusBirthday。类型分别为GuidUserNameUserStatusDateTime?。注意,这里的NameStatus的类型为3.2创建的自定义符合类型UserName和枚举类型UserStatus。而Birthday属性的类型为一个Nullable类型的DateTime?。注意DateTime后面的问号,表示这个类型实际是一个Nullable<DateTime>,也就是说,Birthday类型如果不赋初始值的话,它的值为null

3.5 向类图中再添加一个LocalUser接口,继承自NBear.Common.Design.Entity。添加属性LoginNamePassword。类型都为string

3.6 从工具栏添加继承线条,让LocalUser继承User

3.7 向类图中添加一个UserProfile接口,继承自NBear.Common.Design.Entity。添加属性IDUserIDProfileContent。类型分别为GuidGuidstring。注:这里的ProfileContent仅仅象征型的代表profile数据,用于演示11关联,实际的项目中可能会有更多属性。

3.8 从工具栏添加关联线条,让User包含一个名叫Profile的UserProfile类型的属性。这样我们就1对1关联了User和UserProfile实体。注:如果操作图形设计界面觉得麻烦,也可以切换到源代码界面,直接编码。

3.9 向类图中添加一个LocalUserPhone接口,继承自NBear.Common.Design.Entity。添加属性IDUserIDDescriptionNumber。类型分别为GuidGuidstringstring

3.10 从工具栏添加关联线条,让LocalUser包含一个名叫Phones的类型为LocalUserPhone[]的数组类型的属性。这样我们就1对多关联了LocalUser和UserPhone。

3.11 向类图添加一个Group接口,继承自NBear.Common.Design.Entity。添加属性IDName。类型分别为Guidstring

3.12 从工具栏添加关联线条,让User包含一个名叫Groups的类型为Group[]的数组类型的属性。注意,这里我们要实现的是多对多关联,所以下面我们还要建一个UserGroup关联实体来连接这个多对多关系。

3.13 向类图添加一个UserGroup接口,继承自NBear.Common.Design.Entity。添加属性UserIDGroupID。类型都是Guid

设计完的实体关系图,应该类似下面这样:

0234cfbdff3cb1556cbc8aa6fb69654c.jpe

Step 4 设置设计实体元数据

4.1 切换到源代码视图。首先,我们要为除了关联实体UserGroup之外(对于关联实体,凡是标记为RelationKey的属性,会被自动认为是复合主键)的所有设计实体的主键设置PrimaryKey这个Attribute,可以为多主键实体的每个主键添加该属性。如果不正确设置主键,代码生成工具将不能正确生成数据库创建脚本。例如,对于User实体的ID属性,设置后的代码象下面这样:

731655954c7be9d8835ece551b5385f8.jpe         [PrimaryKey]
731655954c7be9d8835ece551b5385f8.jpe        Guid ID
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }

注:大家可能有疑问,为什么这里主键ID能不能是int,并且是自增长的只读属性呢?答案是完全可以的,完全可以设置某个ID属性为下面这样,无需额外设置,它将映射到一个自增长只读的int类型的数据库字段:

731655954c7be9d8835ece551b5385f8.jpe         [PrimaryKey]
731655954c7be9d8835ece551b5385f8.jpe        
int  ID
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
f466905a3bcb5dcef110eab799825254.jpe        }

4.2 在后面的步骤生成实体对应的数据库创建脚本时,对于数值类型,nullable类型和枚举类型,NBear能够自动将他们对应到数据库的对应类型,但是,对string类型,一般需要指定其映射到数据库时的具体类型和长度。当然,也可以不指定,如果不指定,则string类型默认被映射为nvarchar(127)。例如,对于UserProfile的ProfileContent属性,我们添加下面的Attribute,设置其映射到数据库的类型为ntext:

731655954c7be9d8835ece551b5385f8.jpe         [SqlType( " ntext " )]
731655954c7be9d8835ece551b5385f8.jpe        
string  ProfileContent
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }

又如,对于LocalUserPhoneNumber属性,我们添加下面的Attribute,设置其映射到数据库的类型为nvarchar(20)

731655954c7be9d8835ece551b5385f8.jpe         [SqlType( " nvarchar(20) " )]
731655954c7be9d8835ece551b5385f8.jpe        
string  Number
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }

4.2 对于User的Name这个UserName类型的复合类型,我们也需要设置其SqlType,一般设为ntext,因为,默认情况下复合类型被序列化为XML,并保存于对应的数据库字段。另外,复合类型还必须使用CompoundUnit这个Attribute标记,所以User的Name属性需要被设置成下面这样:

731655954c7be9d8835ece551b5385f8.jpe         [CompoundUnit]
731655954c7be9d8835ece551b5385f8.jpe        [SqlType(
" ntext " )]
731655954c7be9d8835ece551b5385f8.jpe        UserName Name
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }

注:继承关系不需要特别设置NBear可以识别接口的自然继承关系,但是,注意,不要让一个设计实体接口继承超过一个基类接口,否则,NBear将不能识别这种继承关系。换句话说,NBear不支持多根继承。之所以有这个限制是因为,后面,所有这些设计实体接口会被自动生成为class形式的实体代码,而class是不支持多根继承的。

4.3 对于User和UserProfile的1对1关联,我们需要为User接口的Profile属性设置下面的Attributes(这些Attribues都包含于NBear.Common.Design中,因此,需要注意在代码中using NBear.Common.Design):

731655954c7be9d8835ece551b5385f8.jpe         [FkQuery( " UserID " , Contained  =   true , LazyLoad  =   false )]
731655954c7be9d8835ece551b5385f8.jpe        UserProfile Profile
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }

其中,FkQuery代表这个属性是一个1对1外键关联,参数UserID表示,在UserProfile实体中,UserID为对应的外键。LazyLoad=false容易理解,表示这个属性不是知道访问才载入数据的,而是,在实例化User对象的时候,就自动载入Profile属性的数据。当然,如果需要,也可以将LazyLoad设为true。另外,可以像下面这样设置UserProfile的UserID属性为外键,则生成的数据库脚本将包含外键引用完整性检测:

731655954c7be9d8835ece551b5385f8.jpe         [FriendKey( typeof (User))]
731655954c7be9d8835ece551b5385f8.jpe        Guid UserID
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }

4.4 对于LocalUser和LocalUserPhone的1对多关联,我们需要为LocalUser接口的Phones属性设置下面对的Attributes

731655954c7be9d8835ece551b5385f8.jpe         [FkQuery( " UserID " , Contained = true , LazyLoad = true )]
731655954c7be9d8835ece551b5385f8.jpe        LocalUserPhone[] Phones
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }


这里
LocalUserLocalUserPhones1对多外键关联。Contained=true表示Phones跟随LocalUser级联更新。

4.5 对于User和Group的多对多关联,我们为User.Groups属性设置下面的Attributes

731655954c7be9d8835ece551b5385f8.jpe         [ManyToManyQuery( typeof (UserGroup), OrderBy = " {Name} DESC " , LazyLoad = true )]
731655954c7be9d8835ece551b5385f8.jpe        Group[] Groups
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }

我们可以看到,和前面的1对1和1对多关联相比,多对多关联的主要区别是必须设置ManyToManyQuery的构造函数参数,指定关联实体为UserGroup。这里的OrderBy并不是必须的,如果不指定,则载入的Group按默认规则排序。

4.6 另外,还需要设置UserGroup这个关联实体的属性如何与UserGroup的属性进行关联。我们需要对UserGroup这个实体关联接口及它的属性设定下面的Attributes

731655954c7be9d8835ece551b5385f8.jpe     [Relation]
731655954c7be9d8835ece551b5385f8.jpe    
public   interface  UserGroup : NBear.Common.Design.Entity
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe    
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe        [RelationKey(
typeof(User))]
1408c5260b2f05e450dee929db9be5f7.jpe        Guid
 UserID
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe{
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
5bcb1807ee3e00d2b3c225f0b3f5c751.jpe        }

1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        [RelationKey(
typeof(Group))]
1408c5260b2f05e450dee929db9be5f7.jpe        Guid GroupID
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe{
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
5bcb1807ee3e00d2b3c225f0b3f5c751.jpe        }

f466905a3bcb5dcef110eab799825254.jpe    }

 注意,首先,关联实体必须使用Relation这个Attribute修饰。其次,每一个关联属性的用于关联的属性,必须使用RelationKey这个Attribute修饰。RelationKey的唯一参数指定这个属性关联到哪一个实体。例如,这里,UserGroup的UserID属性关联到User实体;而GroupID属性则关联到Group实体。

4.7 对于LocalUserPassword,我们可以添加NotNullSerializationIgnore这两个Attribute,显式地设置其对应字段为非空,并且,保证其不会被包含在默认的XML序列化中。设置到设计实体的SerializationIgnore,会在最终生成的实体中用XmlIngore标识。

731655954c7be9d8835ece551b5385f8.jpe         [SqlType( " nvarchar(50) " )]
731655954c7be9d8835ece551b5385f8.jpe        [NotNull]
731655954c7be9d8835ece551b5385f8.jpe        [SerializationIgnore]
731655954c7be9d8835ece551b5385f8.jpe        
string  Password
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe        
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe            
get;
1408c5260b2f05e450dee929db9be5f7.jpe            
set;
f466905a3bcb5dcef110eab799825254.jpe        }

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

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

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

5.3 点击Generate Entities按钮,将生成的代码保存到Entities工程中的一个名叫Entities.cs的新代码文件。并为Entities工程添加到dist\NBear.Common.dll的引用。

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

5.5 点击Generate DB Script按钮,将生成的代码保存到website工程下的名为db.sql的新文件,可以在某个新建的SQL Server数据库中执行这些脚本,创建对应于所有实体的数据库脚本。

Step 6 使用实体及NBear.Data.Gateway访问数据库

6.1 现在我们就可以使用前面生成的实体了。我们先要让website工程引用Entities工程,以及dist/NBear.Data.dll

6.2 我们还需要设置websiteWeb.config文件,添加一个entityConfig section以包含EntityConfig.xml这个实体配置文件,并设置数据库连接字串。下面是设置完的Web.config,注意,粗体的部分都是我们添加的代码(注意,这里的connectionstring连接到SQL Server数据库的tempdb数据库,我们需要对tempdb数据库执行5.5生成的数据库创建脚本,另外也注意修改数据库登录密码。):

731655954c7be9d8835ece551b5385f8.jpe <? xml version="1.0" ?>
731655954c7be9d8835ece551b5385f8.jpe
< configuration >
731655954c7be9d8835ece551b5385f8.jpe 
<configSections>
731655954c7be9d8835ece551b5385f8.jpe    
<section name="entityConfig" type="NBear.Common.EntityConfigurationSection, NBear.Common" />
731655954c7be9d8835ece551b5385f8.jpe 
</configSections>
731655954c7be9d8835ece551b5385f8.jpe 
<entityConfig>
731655954c7be9d8835ece551b5385f8.jpe    
<includes>
731655954c7be9d8835ece551b5385f8.jpe      
<add key="Sample Entity Config" value="~/EntityConfig.xml" />
731655954c7be9d8835ece551b5385f8.jpe    
</includes>
731655954c7be9d8835ece551b5385f8.jpe 
</entityConfig>
731655954c7be9d8835ece551b5385f8.jpe 
< appSettings />
731655954c7be9d8835ece551b5385f8.jpe 
<connectionStrings>
731655954c7be9d8835ece551b5385f8.jpe    
<add name="DbName" connectionString="Server=(local);Database=tempdb;Uid=sa;Pwd=sa" providerName="NBear.Data.SqlServer.SqlDbProvider"/>
731655954c7be9d8835ece551b5385f8.jpe 
</connectionStrings>
731655954c7be9d8835ece551b5385f8.jpe 
< system .web >
731655954c7be9d8835ece551b5385f8.jpe        
< compilation  debug ="false"   />
731655954c7be9d8835ece551b5385f8.jpe        
< authentication  mode ="Windows"  /
731655954c7be9d8835ece551b5385f8.jpe    </system.web
>
731655954c7be9d8835ece551b5385f8.jpe
</ configuration >

6.3 好了,现在,我们就可以随心所欲的访问数据库了。将下面的代码添加至website工程的Default.aspx.cs文件(您也可以直接打开tutorials\ ORM_Tutorial\website目录下的Default.aspx.cs,从那里复制代码)。这些代码演示了一个非常典型的创建和级联更新有复杂关系的实体的过程,并伴有详细解说。关于Gateway支持的更多方法的介绍,可以参考doc目录下的SDK类库文档。

731655954c7be9d8835ece551b5385f8.jpe using  System;
731655954c7be9d8835ece551b5385f8.jpe
using  System.Data;
731655954c7be9d8835ece551b5385f8.jpe
using  System.Configuration;
731655954c7be9d8835ece551b5385f8.jpe
using  System.Web;
731655954c7be9d8835ece551b5385f8.jpe
using  System.Web.Security;
731655954c7be9d8835ece551b5385f8.jpe
using  System.Web.UI;
731655954c7be9d8835ece551b5385f8.jpe
using  System.Web.UI.WebControls;
731655954c7be9d8835ece551b5385f8.jpe
using  System.Web.UI.WebControls.WebParts;
731655954c7be9d8835ece551b5385f8.jpe
using  System.Web.UI.HtmlControls;
731655954c7be9d8835ece551b5385f8.jpe
731655954c7be9d8835ece551b5385f8.jpe
using  Entities;
731655954c7be9d8835ece551b5385f8.jpe
using  NBear.Common;
731655954c7be9d8835ece551b5385f8.jpe
using  NBear.Data;
731655954c7be9d8835ece551b5385f8.jpe
731655954c7be9d8835ece551b5385f8.jpe
public  partial  class  _Default : System.Web.UI.Page 
24a924a57ba6b3f2b51fc9edb7ea4186.jpe9310e85a14af99de4811ff4c77f1f911.jpe
222530190136c9c4cfd237cc0d5cff99.jpe {
1408c5260b2f05e450dee929db9be5f7.jpe    
protected void Page_Load(object sender, EventArgs e)
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe    
222530190136c9c4cfd237cc0d5cff99.jpe{
1408c5260b2f05e450dee929db9be5f7.jpe        
//init a Gateway, the param "tempdb" is the connectionstring name set in Web.config
1408c5260b2f05e450dee929db9be5f7.jpe
        Gateway gateway = new Gateway("tempdb");    //youcan also use gateway = Gateway.Default, which maps to the last connectionstring in Web.config
1408c5260b2f05e450dee929db9be5f7.jpe

e083dfde5a91f50979fe8979b4012b9d.jpe715f2d05503b99d41f3b6ba2cdccc84d.jpe        
create & save a LocalUser#region create & save a LocalUser
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Create a new local user and set property values.");
1408c5260b2f05e450dee929db9be5f7.jpe        LocalUser newLocalUser 
= new LocalUser();
1408c5260b2f05e450dee929db9be5f7.jpe        newLocalUser.ID 
= Guid.NewGuid();
1408c5260b2f05e450dee929db9be5f7.jpe        newLocalUser.Password 
= "12345";
1408c5260b2f05e450dee929db9be5f7.jpe        
//by default, newUser.Birthday equals null, because it is DateTime? type, which means when saved in database, its value is dbnull.
1408c5260b2f05e450dee929db9be5f7.jpe        
//newUser.Birthday = null
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//if you want to set a compoundunit property like User.Name, you must create the compoundunit type first, and then assign it to the property
1408c5260b2f05e450dee929db9be5f7.jpe        
//you should not assign value directly to the compoundunit property's property like "newUser.Name.FirstName = XXX", 
1408c5260b2f05e450dee929db9be5f7.jpe        
//or, a compile-time warning will be thrown
1408c5260b2f05e450dee929db9be5f7.jpe
        WriteLine("Create & set the user name.");
1408c5260b2f05e450dee929db9be5f7.jpe        UserName newUserName 
= new UserName();
1408c5260b2f05e450dee929db9be5f7.jpe        newUserName.FirstName 
= "teddy";
1408c5260b2f05e450dee929db9be5f7.jpe        newUserName.LastName 
= "ma";
1408c5260b2f05e450dee929db9be5f7.jpe        newLocalUser.Name 
= newUserName; //must create the compoundunit type first, and then assign it to the property
1408c5260b2f05e450dee929db9be5f7.jpe

1408c5260b2f05e450dee929db9be5f7.jpe        newLocalUser.Status 
= UserStatus.Available;
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//create and assign the 1 to 1 related Profile property
1408c5260b2f05e450dee929db9be5f7.jpe
        UserProfile newUserProfile = new UserProfile();
1408c5260b2f05e450dee929db9be5f7.jpe        newUserProfile.ID 
= Guid.NewGuid(); //create it first
1408c5260b2f05e450dee929db9be5f7.jpe
        newUserProfile.UserID = newLocalUser.ID;
1408c5260b2f05e450dee929db9be5f7.jpe        newUserProfile.ProfileContent 
= "some sample content";
1408c5260b2f05e450dee929db9be5f7.jpe        newLocalUser.Profile 
= newUserProfile;   //assign it to the property
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//create two phones and assign the 1 to many related Phones property
1408c5260b2f05e450dee929db9be5f7.jpe
        WriteLine("Create & set the local user phones");
1408c5260b2f05e450dee929db9be5f7.jpe        LocalUserPhone[] newPhones 
= new LocalUserPhone[2];
1408c5260b2f05e450dee929db9be5f7.jpe        newPhones[
0= new LocalUserPhone();    //create first phone
1408c5260b2f05e450dee929db9be5f7.jpe
        newPhones[0].Description = "home";
1408c5260b2f05e450dee929db9be5f7.jpe        newPhones[
0].ID = Guid.NewGuid();
1408c5260b2f05e450dee929db9be5f7.jpe        newPhones[
0].UserID = newLocalUser.ID;
1408c5260b2f05e450dee929db9be5f7.jpe        newPhones[
0].Number = "111";
1408c5260b2f05e450dee929db9be5f7.jpe        newPhones[
1= new LocalUserPhone();    //create second phone
1408c5260b2f05e450dee929db9be5f7.jpe
        newPhones[1].Description = "work";
1408c5260b2f05e450dee929db9be5f7.jpe        newPhones[
1].ID = Guid.NewGuid();
1408c5260b2f05e450dee929db9be5f7.jpe        newPhones[
1].UserID = newLocalUser.ID;
1408c5260b2f05e450dee929db9be5f7.jpe        newPhones[
1].Number = "222";
1408c5260b2f05e450dee929db9be5f7.jpe        LocalUserPhoneArrayList newPhoneList 
= new LocalUserPhoneArrayList();
1408c5260b2f05e450dee929db9be5f7.jpe        newPhoneList.AddRange(newPhones);
1408c5260b2f05e450dee929db9be5f7.jpe        newLocalUser.Phones 
= newPhoneList;    //assign it to the property
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//create a group and assign it to the Groups property
1408c5260b2f05e450dee929db9be5f7.jpe
        WriteLine("Create & set the user groups.");
1408c5260b2f05e450dee929db9be5f7.jpe        Group newGroup 
= new Group();
1408c5260b2f05e450dee929db9be5f7.jpe        newGroup.ID 
= Guid.NewGuid();
1408c5260b2f05e450dee929db9be5f7.jpe        newGroup.Name 
= "new group";
1408c5260b2f05e450dee929db9be5f7.jpe        GroupArrayList groupList 
= new GroupArrayList();
1408c5260b2f05e450dee929db9be5f7.jpe        groupList.Add(newGroup);
1408c5260b2f05e450dee929db9be5f7.jpe        newLocalUser.Groups 
= groupList; //another way to add a item to array property
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//save newLocalUser
1408c5260b2f05e450dee929db9be5f7.jpe
        WriteLine("Save the new local user.");
1408c5260b2f05e450dee929db9be5f7.jpe        gateway.Save
<LocalUser>(newLocalUser);  //do you know what is happening when saving the new local user?
1408c5260b2f05e450dee929db9be5f7.jpe

5bcb1807ee3e00d2b3c225f0b3f5c751.jpe        
#endregion

1408c5260b2f05e450dee929db9be5f7.jpe
e083dfde5a91f50979fe8979b4012b9d.jpe715f2d05503b99d41f3b6ba2cdccc84d.jpe        
Check saving result#region Check saving result
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"After we saved the local user.");
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//let find the saved local user by id first
1408c5260b2f05e450dee929db9be5f7.jpe
        LocalUser theSavedLocalUser = gateway.Find<LocalUser>(newLocalUser.ID);
1408c5260b2f05e450dee929db9be5f7.jpe        
if (theSavedLocalUser != null) WriteLine("We found the saved local user itself.");
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//a local user is also a user, right? then could we find the saved local user as a user?
1408c5260b2f05e450dee929db9be5f7.jpe
        User theSavedLocalUserAsUser = gateway.Find<User>(newLocalUser.ID);
1408c5260b2f05e450dee929db9be5f7.jpe        
if (theSavedLocalUser != null) WriteLine("We found the saved local user itself as a user.");
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//was the 1 to 1 related user profile saved on the new local user's saving?
1408c5260b2f05e450dee929db9be5f7.jpe
        if (theSavedLocalUser.Profile != null && theSavedLocalUser.Profile.ID == newLocalUser.Profile.ID) WriteLine("We found the 1 to 1 related user profile of the saved local user was also saved.");
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//were the 1 to many related local user phones saved on the new local user's saving?
1408c5260b2f05e450dee929db9be5f7.jpe
        if (theSavedLocalUser.Phones != null && theSavedLocalUser.Phones[0].ID == newLocalUser.Phones[0].ID && theSavedLocalUser.Phones[1].ID == newLocalUser.Phones[1].ID)
1408c5260b2f05e450dee929db9be5f7.jpe            WriteLine(
"We found the 1 to many related local user phones of the saved local user were also saved.");
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//were the many to many related user group and the usergroup relation entity saved on the new local user's saving?
1408c5260b2f05e450dee929db9be5f7.jpe
        if (theSavedLocalUser.Groups != null && theSavedLocalUser.Groups.Count > 0 && theSavedLocalUser.Groups[0].ID == newLocalUser.Groups[0].ID)
1408c5260b2f05e450dee929db9be5f7.jpe            WriteLine(
"We found the many to many related local user group of the saved local user was also saved.");    //is the line really executed?? it should not.
1408c5260b2f05e450dee929db9be5f7.jpe
        else
1408c5260b2f05e450dee929db9be5f7.jpe            WriteLine(
"Oh! many to many related local user group of the saved local user was NOT saved!! Do you know why? - It is NOT because it is many to many related while profile and phones are 1 to 1 or 1 to many. It is not because you are not Teddy, either. :) It IS because in the entity design of User, the Groups property is NOT marked with the [Contained] attribute.");
1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe        
//save an uncontained property's value
1408c5260b2f05e450dee929db9be5f7.jpe
        WriteLine("To save an uncontained property value, such as user's Groups, you have to manually do this.");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Firstly, you should save the group it self.");
1408c5260b2f05e450dee929db9be5f7.jpe        gateway.Save
<Group>(newGroup);
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Furthermore, you have to create & save a usergroup relation entity manually. Let's do it.");
1408c5260b2f05e450dee929db9be5f7.jpe        UserGroup newUserGroup 
= new UserGroup();   //create the new usergroup relation entity instance
1408c5260b2f05e450dee929db9be5f7.jpe
        newUserGroup.UserID = theSavedLocalUser.ID;
1408c5260b2f05e450dee929db9be5f7.jpe        newUserGroup.GroupID 
= newGroup.ID;
1408c5260b2f05e450dee929db9be5f7.jpe        gateway.Save
<UserGroup>(newUserGroup);  //do the saving
1408c5260b2f05e450dee929db9be5f7.jpe
        WriteLine("Let's find the saved local user again. Was the group saved this time?");
1408c5260b2f05e450dee929db9be5f7.jpe        theSavedLocalUser 
= gateway.Find<LocalUser>(newLocalUser.ID);
1408c5260b2f05e450dee929db9be5f7.jpe        
if (theSavedLocalUser.Groups != null && theSavedLocalUser.Groups.Count > 0 && theSavedLocalUser.Groups[0].ID == newLocalUser.Groups[0].ID)
1408c5260b2f05e450dee929db9be5f7.jpe            WriteLine(
"Yes, conguratulation! This time, we found the many to many related local user group of the saved local user was finally saved.");
1408c5260b2f05e450dee929db9be5f7.jpe        
1408c5260b2f05e450dee929db9be5f7.jpe        
//to see the saved user name details
1408c5260b2f05e450dee929db9be5f7.jpe
        WriteLine("Do you want to know the saved user name's details, which is a compoundunit property? Ok, show you what you want, in fact, it is serialized as xml by the NBear.Common.SerializationManager class, looks like:");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(SerializationManager.Serialize(theSavedLocalUser.Name));
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Ok, I heard you considering whether you can save it into some other format because you do not want it to be XML? You do have chance to control this!!");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"What youshould do is easily register a custom serialize/deserialize delegate method pair.");
1408c5260b2f05e450dee929db9be5f7.jpe        SerializationManager.RegisterSerializeHandler(
typeof(UserName), new SerializationManager.TypeSerializeHandler(CustomSerializeUserName), new SerializationManager.TypeDeserializeHandler(CustomDeserializeUserName));
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Let's save the user name again.");
1408c5260b2f05e450dee929db9be5f7.jpe        theSavedLocalUser.Name 
= newUserName;
1408c5260b2f05e450dee929db9be5f7.jpe        gateway.Save
<LocalUser>(theSavedLocalUser);
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"What does the details of the user name now become? It becomes:");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(SerializationManager.Serialize(theSavedLocalUser.Name));
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Cool!~~ Right? But remember, in real project, you must register the custom serialize/deserialize delegate method pair at application started up. For example, in Application_Start().");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Thank you so much for having completed this tutorial. You can look up the appendixes, for more information about the usage of the Gateway.");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"See you later!");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Warm regards,");
1408c5260b2f05e450dee929db9be5f7.jpe        WriteLine(
"Teddy " + DateTime.Now.ToShortDateString());
1408c5260b2f05e450dee929db9be5f7.jpe        SerializationManager.UnregisterSerializeHandler(
typeof(UserName));
1408c5260b2f05e450dee929db9be5f7.jpe
5bcb1807ee3e00d2b3c225f0b3f5c751.jpe        
#endregion

5bcb1807ee3e00d2b3c225f0b3f5c751.jpe    }

1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe    
private void WriteLine(string str)
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe    
222530190136c9c4cfd237cc0d5cff99.jpe{
1408c5260b2f05e450dee929db9be5f7.jpe        Response.Write(Server.HtmlEncode(str) 
+ "<br /><br />");
5bcb1807ee3e00d2b3c225f0b3f5c751.jpe    }

1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe    
private string CustomSerializeUserName(object name)
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe    
222530190136c9c4cfd237cc0d5cff99.jpe{
1408c5260b2f05e450dee929db9be5f7.jpe        UserName userName 
= (UserName)name;
1408c5260b2f05e450dee929db9be5f7.jpe        
return userName.FirstName + "," + userName.LastName;
5bcb1807ee3e00d2b3c225f0b3f5c751.jpe    }

1408c5260b2f05e450dee929db9be5f7.jpe
1408c5260b2f05e450dee929db9be5f7.jpe    
private object CustomDeserializeUserName(string data)
715f2d05503b99d41f3b6ba2cdccc84d.jpee083dfde5a91f50979fe8979b4012b9d.jpe    
222530190136c9c4cfd237cc0d5cff99.jpe{
1408c5260b2f05e450dee929db9be5f7.jpe        
string[] splittedData = data.Split(',');
1408c5260b2f05e450dee929db9be5f7.jpe        UserName userName 
= new UserName();
1408c5260b2f05e450dee929db9be5f7.jpe        userName.FirstName 
= splittedData[0];
1408c5260b2f05e450dee929db9be5f7.jpe        userName.LastName 
= splittedData[1];
1408c5260b2f05e450dee929db9be5f7.jpe        
return userName;
5bcb1807ee3e00d2b3c225f0b3f5c751.jpe    }

f466905a3bcb5dcef110eab799825254.jpe}

6.4 运行以上代码,您将得到类似到下面的结果:

Create a new local user and set property values.
Create & set the user name.
Create & set the local user phones
Create & set the user groups.
Save the new local user.

After we saved the local user.
We found the saved local user itself.
We found the saved local user itself as a user.
We found the 1 to 1 related user profile of the saved local user was also saved.
Oh! many to many related local user group of the saved local user was NOT saved!! Do you know why? - It is NOT because it is many to many related while profile and phones are 1 to 1 or 1 to many. It is not because your are not Teddy, either. :) It IS because in the entity design of User, the Groups property is NOT marked with the [Contained] attribute.
To save an uncontained property value, such as user's Groups, you have to manually do this.
Firstly, you should save the group it self.
Furthermore, you have to create & save a usergroup relation entity manually. Let's do it.
Let's find the saved local user again. Was the group saved this time?
Yes, conguratulation! This time, we found the many to many related local user group of the saved local user was finally saved.
Do you want to know the saved user name's details, which is a compoundunit property? Ok, show you what you want, in fact, it is serialized as xml by the NBear.Common.SerializationManager class, looks like:
<?xml version="1.0" encoding="utf-16"?> <UserName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <FirstName>teddy</FirstName> <LastName>ma</LastName> </UserName>
Ok, I heard you considering whether you can save it into some other format because you do not want it to be XML? You do have chance to control this!!
What youshould do is easily register a custom serialize/deserialize delegate method pair.
Let's save the user name again.
What does the details of the user name now become? It becomes:
teddy,ma
Cool!~~ Right? But remember, in real project, you must register the custom serialize/deserialize delegate method pair at application started up. For example, in Application_Start().
Thank you so much for having completed this tutorial. You can look up the appendixes, for more information about the usage of the Gateway.
See you later!
Warm regards,
Teddy 2006-11-3

正文结束。

附录

1 关于ConnectionStrings的设置

这里定义了五个ConnectionString,分别对应MS AccessMS SQL ServerSQL Server 2005MySqlOracle数据库。

731655954c7be9d8835ece551b5385f8.jpe < connectionStrings >
731655954c7be9d8835ece551b5385f8.jpe   
< add  name ="TestAccessDb"  connectionString ="Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Teddy\NBear\skeleton\Simple\website\App_Data\TestAccessDb.mdb"  providerName ="NBear.Data.MsAccess.AccessDbProvider" />
731655954c7be9d8835ece551b5385f8.jpe   
< add  name ="Northwind"  connectionString ="Server=(local);Database=Northwind;Uid=sa;Pwd=sa"  providerName ="NBear.Data.SqlServer.SqlDbProvider" />
731655954c7be9d8835ece551b5385f8.jpe   
< add  name ="Northwind2"  connectionString ="Server=(local);Database=Northwind;Uid=sa;Pwd=sa"  providerName ="NBear.Data.SqlServer9.SqlDbProvider9" />
731655954c7be9d8835ece551b5385f8.jpe   
< add  name ="MySql"  connectionString ="Dsn=mysqltest;database=test;option=3;server=localhost;uid=root;password=sa"  providerName ="NBear.Data.MySql.MySqlDbProvider" />
731655954c7be9d8835ece551b5385f8.jpe   
< add  name ="Oracle"  connectionString ="Data Source=localhost;User ID=system;Password=sa;Unicode=True"  providerName ="NBear.Data.Oracle.OracleDbProvider" />
731655954c7be9d8835ece551b5385f8.jpe
</ connectionStrings >

2 关于Gateway的初始化和连接多数据库

除了使用Gateway.Default之外,还可以下面两种方式实例化Gateway

1)使用配置文件中的ConnectionStringname属性对应的名称来初始化Gateway。例如,

731655954c7be9d8835ece551b5385f8.jpe public   static  Gateway Northwind  =   new  Gateway( " Northwind " );
731655954c7be9d8835ece551b5385f8.jpe
public   static  Gateway TestAccessDb  =   new  Gateway( " TestAccessDb " );

我们可以像这样实例化多个Gateway对应不同的ConnectionString

2)如果您不将ConnectionString定义于应用程序的配置文件中,那么,就需要直接提供ConnectionString来初始化了。下面是几个典型的初始化示例:

731655954c7be9d8835ece551b5385f8.jpe Gateway TestDbAccess  =   new  Gateway(DatabaseType.MsAccess,  @" C:\Teddy\NBear\skeleton\Simple\website\App_Data\TestAccessDb.mdb " );
731655954c7be9d8835ece551b5385f8.jpeGateway Northwind 
=   new  Gateway(DatabaseType.SqlServer,  @" Server=(local);Database=Northwind;Uid=sa;Pwd=sa " );
731655954c7be9d8835ece551b5385f8.jpeGateway Northwind2 
=   new  Gateway(DatabaseType.SqlServer9,  @" Server=(local)\SQLEXPRESS;Database=Northwind;Uid=sa;Pwd=sa " );
731655954c7be9d8835ece551b5385f8.jpeGateway.Default 
=   new  Gateway(DatabaseType.MySql,  " Dsn=mysqltest;database=test;option=3;server=localhost;uid=root;password=sa " );
731655954c7be9d8835ece551b5385f8.jpeGateway.Default 
=   new  Gateway(DatabaseType.Oracle,  " Data Source=localhost;User ID=system;Password=sa;Unicode=True " );

注意以上的代码使用了Gateway构造函数的另一个重载版本,接受一个DatabaseType参数和一个ConnectionString。这五行示例分别实例化了对应于MSAccessMS SQL Server 2000MS SQL Server 2005MySqlOracle的数据库的Gateway

//本文结束。


转载请注明本文地址: NBearV3 Step by Step教程——ORM篇

猜你喜欢

转载自blog.csdn.net/wangchaoqi1985/article/details/82794043