快捷搜索:

NBearV3 Step by Step教程——IoC篇

版本

1.2 [2006-11-12]

简介

本教程演示若何基于NBearV3的IoC模块开拓一个Web利用法度榜样的基础历程。本教程同时演示应用NBear.Tools.DbToEntityDesign.exe对象从现有的数据库天生设计实体的历程。

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

目标

经由过程本教程,读者应能够掌握应用NBearV3的IoC模块的基础历程,以及应用NBear.Tools.DbToEntityDesign.exe对象,对已稀有据库布局的项目,应用NBearV3的ORM组件进行数据持久化的历程。

代码

本教程演示创建的所有工程和代码,包孕于可以从sf.net下载的NBearV3最新源码zip包中的tutorialsIoC_Tutorial目录中。是以,在应用本教程的历程中如有任何疑问,可以直接参考这些代码。

光阴

<45分钟。

正文

Step 1 下载NBearV3最新版本

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

1.2 将下载的zip文件解压至C:,您将看到,加压后的NBearV3目录中包括:dist、doc、cases、src等目录。此中,在本教程中将会应用的是dist目录,该目录下包孕所有release编译版本的dll和exe。

Step 2 创建利用法度榜样办理规划

2.1 打开VS2005开拓情况,新建一个空的办理规划sln。

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

2.3 向sln中再添加两个新建的C#类库工程,两个类库工程的名称分手为ServiceInterfaces和ServiceImpls,删除IDE自动创建的Class1.cs文件。

2.4 向sln中新建一个名叫website的ASP.NET Web利用法度榜样,为website添加一个Web.config文件。

Step 3 设计实体、关系及元数据

3.1 运行dist NBear.Tools.DbToEntityDesign.exe,在Connection String文本框中输入下面的连接子串:

Server=(local);Database=Northwind;Uid=sa;Pwd=sa

我们将从SQL Server 2000自带的演示数据库Northwind,为我们必要的某些表和视图天生设计实体。

点击Connect按钮,连接上数据库后,从左边的Tables和Views列表平分手选择下面这些表或视图(由于这里主如果演示,我们只选择和Category和Product相关的几个表和视图):Categories, Products, Products by Category。点击Generate Entities Design按钮,在代码天生文本框内的随意率性位置右键单击鼠标,并选择Copy to ClipBoard,这将能把所有的代码复制到剪贴板。

3.2 为EntityDesigns工程添加到dist目录下的NBear.Common.Design.dll的引用,由于每一个设计实体接口必须承袭自NBear.Common.Design.Entity这个接口。在EntitiyDesigns工程中新建一个代码文件EntityDesigns.cs,添加using System和using NBear.Common.Design设置namespace为EntityDesigns。并将刚才从DbToEntityDesign复制的代码粘贴至该文件中。

此时,EntityDesigns.cs文件中的内容应该象下面这样:

using System;

using NBear.Common.Design;

namespace EntityDesigns

{

public interface Categories : Entity

{

[PrimaryKey]

int CategoryID { get; }

[SqlType("nvarchar(15)")]

string CategoryName { get; set; }

[SqlType("ntext")]

string Description { get; set; }

byte[] Picture { get; set; }

}

//…

}

using System;

using NBear.Common.Design;

namespace EntityDesigns

{

[MappingName("Categories")]

public interface Category : Entity

{

[PrimaryKey]

int CategoryID { get; }

[SqlType("nvarchar(15)")]

string CategoryName { get; set; }

[SqlType("ntext")]

string Description { get; set; }

byte[] Picture { get; set; }

[Query(Where="{CategoryID} = @CategoryID", OrderBy="{ProductName}", LazyLoad=true)]

[Contained]

Product[] Products

{

get;

set;

}

}

[MappingName("Products")]

public interface Product : Entity

{

[PrimaryKey]

int ProductID { get; }

[SqlType("nvarchar(40)")]

string ProductName { get; set; }

int SupplierID { get; set; }

int CategoryID { get; set; }

[SqlType("nvarchar(20)")]

string QuantityPerUnit { get; set; }

decimal UnitPrice { get; set; }

short UnitsInStock { get; set; }

short UnitsOnOrder { get; set; }

short ReorderLevel { get; set; }

bool Discontinued { get; set; }

[Query(Where="{CategoryID} = @CategoryID", LazyLoad=false)]

Category Category

{

get;

set;

}

}

[ReadOnly]

[MappingName("Products by Category")]

public interface ProductsByCategory : Entity

{

[SqlType("nvarchar(15)")]

string CategoryName { get; }

[SqlType("nvarchar(40)")]

string ProductName { get; }

[SqlType("nvarchar(20)")]

string QuantityPerUnit { get; }

short UnitsInStock { get; }

bool Discontinued { get; }

}

}3.4 实体和属性名称我们改造完了,下面还可以给设计实体添加一点关联。我们可以留意到,Category和Product是一个显着的1对多关联。是以,我们可以像下面这样,为Category实体添加一个Products属性,1对多关联到Product表。

[MappingName("Products")]

public interface Product : Entity

{

[PrimaryKey]

int ProductID { get; }

[SqlType("nvarchar(40)")]

string ProductName { get; set; }

int SupplierID { get; set; }

[SqlType("nvarchar(20)")]

string QuantityPerUnit { get; set; }

decimal UnitPrice { get; set; }

short UnitsInStock { get; set; }

short UnitsOnOrder { get; set; }

short ReorderLevel { get; set; }

bool Discontinued { get; set; }

[FkReverseQuery(LazyLoad = true)]

[MappingName("CategoryID")]

Category Category

{

get;

set;

}

}

留意,我们没有添加

ContainedAttribute,由于,我们并不盼望一个Category跟随他的一个Product的更新级联更新。同时,我们将Category属性设置为非延迟载入(即实例化Product的同时就载入Category属性的数据)。

这里要分外引起留意的是,当两个实体相互关联,或者,多个实体轮回关联时,切切留意不要同时将相互关联的属性全都设为LazyLoad=fasle,否则将可能导致轮回载入,造成法度榜样逝世轮回。在NBearV3的后续有版本将会引入缓存机制来办理这个问题,然则在这之前,请大年夜家自己留意小心避免。

Step 4 从实体设计代码天生实体代码、实体设置设置设备摆设摆设文件

4.1 至此,实体的设计就完毕了。编译EntityDesigns工程。下面我们将从设计实体天生实际的实体代码和设置设置设备摆设摆设文件。留意,这里和之前的ORM教程不合的是,我们不天生数据库创建脚本,而直接应用一个已经存在的数据库Northwind。

5.3 好了,到今朝为止,实体设置和设置设置设备摆设摆设完毕了。下面我们将开始评论争论IoC模块的应用。

Step 6 定义Service接口和Service实现

6.1 下面我们开始定义一个基于NBear.IoC的Service。我们先要为ServiceInterfaces工程添加到distNBear.Common.dll和distNBear.IoC.dll的引用。一个Service由一个接口定义。我们这个Service的功能很简单,便是我们想得到一些必要的Category和Product。以是,我们还必要为ServiceInterfaces工程添加到Entities工程的引用。在ServiceInterfaces工程中定义接口ICategoryService和IProductService如下:

using System;

using NBear.IoC.Service;

using Entities;

namespace ServiceInterfaces

{

public interface ICategoryService : IService

{

Category[] GetAllCategories();

Category GetCategoryByID(int categoryID);

}

}

using System;

using NBear.IoC.Service;

using Entities;

namespace ServiceInterfaces

{

public interface IProductService

{

Product[] GetAllProducts();

Product GetProductByID(int productID);

}

}

留意,基于NBear.IoC的Service,必须从NBear.IoC.Service.IServiceInterface这个接口承袭。

6.2 定义完Service接口,我们还必要实现它。在ServiceImpls工程中,添加到Entities,ServiceInterfaces和到distNBear.Common.dll,distNBear.Data.dll和distNBear.IoC.dll的引用,分手实现这两个接口如下:

using System;

using NBear.Common;

using NBear.Data;

using Entities;

using ServiceInterfaces;

namespace ServiceImpls

{

public class CategoryService : ICategoryService

{

ICategoryService Members#region ICategoryService Members

public Category[] GetAllCategories()

{

return Gateway.Default.FindArray(WhereClip.All, OrderByClip.Default);

}

public Category GetCategoryByID(int categoryID)

{

return Gateway.Default.Find(categoryID);

}

#endregion

}

}

using System;

using NBear.Common;

using NBear.Data;

using Entities;

using ServiceInterfaces;

namespace ServiceImpls

{

public class ProductService : IProductService

{

IProductService Members#region IProductService Members

public Product[] GetAllProducts()

{

return Gateway.Default.FindArray

(WhereClip.All, OrderByClip.Default);

}

public Product GetProductByID(int productID)

{

return Gateway.Default.Find

(productID);

}

#endregion

}

}

留意加粗的部分,这里我们添加了一个castle的设置设置设备摆设摆设块,并且设置设置设备摆设摆设了两个我们定义的Service和他们对应的实现。

7.3 接着,在Default.aspx.cs文件中的PageLoad中,添加下面的代码,造访Service。

留意,所有的Service只需简单地从ServiceFactory.GetService()获得。然后就能应用了。

protected void Page_Load(object sender, EventArgs e)

{

ServiceFactory factory = ServiceFactory.Create();

IProductService ps = factory.GetService();

Product[] products = ps.GetAllProducts();

WriteLine(string.Format("Got all products, {0} in total.", products.Length));

ICategoryService cs = factory.GetService();

Category[] categories = cs.GetAllCategories();

WriteLine(string.Format("Got all categories, {0} in total.", categories.Length));

WriteLine("In each category:");

foreach (Category item in categories)

{

WriteLine(string.Format("ID={0}, Name={1}, Products in category: {2}.", item.CategoryID, item.CategoryName, item.Products.Length));

}

}

private void WriteLine(string str)

{

Response.Write(Server.HtmlEncode(str) + "

");

}

正文停止。

附录

1 关于ServiceFactory.Create()

在website中,您必然留意到,我们应用NBear.IoC.Service.ServiceFactory.Create()措施得到了ServiceFactory实例,并经由过程他得到Service接口的实现类实例。

在实际的项目中,您也无需在一个统一的地方定义全局的ServiceFactory实例引用,可以在每一个必要ServiceFactory实例的地方直接调用ServiceFactory.Create(),由于ServiceFactory.Create()内部实际上应用了Singleton模式,它老是返回的独一的一个ServiceFactory实例。

同时,除了在website中经由过程ServiceFactory造访service之外,在某一个Service的实今世码中,也可以造访ServiceFactory.Create(),从而造访另一个同样在Web.config的castle块中设置设置设备摆设摆设的service。这样,当不合的Service实现法度榜样集之间相互调用Service时,只必要相互引用Service Interfaces,Service的实今世码相互就能避免任何依附,从而将模块间的耦合度降至最低。

//本文停止

您可能还会对下面的文章感兴趣: