Teddy's Knowledge Base

基于NBear的快速开发解决方案

基于NBear的快速开发解决方案

----
简介
----
NBear是一个.Net 2.0下的快速开发框架。它提供了包括可视化实体设计、代码生成、持久化、SOA、MVP等一系列组件。

NBear的设计目标是尽最大可能减少程序员的重复劳动、提高开发效率、提升代码的可维护性和整体质量。

官方网站:http://nbear.org

中文教程目录索引:http://www.cnblogs.com/teddyma/archive/2006/11/07/553562.html

示例程序:从官方网站下载NBearVXXX_tutorials.zip,解压后见tutorials目录。

--------
核心组件
--------
NBear.Data - 强类型ORM持久化组件
NBear.IoC - IoC及分布式组件
NBear.MVP - MVP模式组件
NBear.Web - Web组件
NBear.Web.Data - 包括NBearDataSource等封装了NBear.Data持久化功能的Web组件
NBear.Tools - 各种Db2EntityDesign、EntityDesign2Entity、VsPlugin等代码生成工具和IDE集成工具

--------------------------------------
使用NBear.Data持久化组件的典型开发流程
--------------------------------------

关于持久化组件实际使用更具体介绍,请参见:tutorials\ORM_Tutorial,ORM_Adv_Tutorial,CaseByCase_Tutorial和StrongTypeQuery_Tutorial等教程。

--------------------------------
NBear.Data.Gateway强类型查询简介
--------------------------------
NBear的持久化组件提供类似Linq的强类型查询语法,支持主外键关联、继承关联、多对多关联、级联更新、联结、分组、分页查询等,
对应90%以上的常用SQL查询语法。并提供对内存数组的强类型查询过滤、查询缓存、对自定义SQL和存储过程的强类型查询封装等功能。

下面是一些典型的强类型查询语法及对应的运行时的SQL:

//带查询条件的简单查询
Product[] products = gateway.From<Product>().Where((Product._.UnitsInStock <= Product._.ReorderLevel && !(Product._.Discontinued == true)) || Product._.UnitPrice < 10m).ToArray<Product>;
SQL:
SELECT [Products].[ProductID],[Products].[ProductName],[Products].[SupplierID],[Products].[CategoryID],[Products].[QuantityPerUnit],[Products].[UnitPrice],[Products].[UnitsInStock],[Products].[UnitsOnOrder],[Products].[ReorderLevel],[Products].[Discontinued] FROM [Products] WHERE ((([Products].[UnitsInStock] <= [Products].[ReorderLevel]) AND NOT (([Products].[Discontinued] = @p3bue3xtylvv4kh))) OR ([Products].[UnitPrice] < @p09bi3366a4l612))
Parameters:
@p3bue3xtylvv4kh[Boolean] = 1
@p09bi3366a4l612[Decimal] = 10

-

//不带条件的分页查询
OrderDetailsExtended[] orders = gateway.From<OrderDetailsExtended>().ToArrayList<OrderDetailsExtended>(10, 10).ToArray();
SQL:
SELECT TOP 10 [Order Details Extended].[OrderID],[Order Details Extended].[ProductID],[Order Details Extended].[ProductName],[Order Details Extended].[UnitPrice],[Order Details Extended].[Quantity],[Order Details Extended].[Discount],[Order Details Extended].[ExtendedPrice] FROM [Order Details Extended] WHERE [Order Details Extended].[OrderID]>(SELECT MAX([__T].[OrderID]) FROM (SELECT TOP 10 [Order Details Extended].[OrderID] AS [OrderID] FROM [Order Details Extended] ORDER BY [Order Details Extended].[OrderID]) [__T]) ORDER BY [Order Details Extended].[OrderID]

-

//对查询结果在内存中二次过滤
EntityArrayList<Employee> employeeList2 = gateway.From<Employee>().ToArrayList<Employee>();
SQL:
SELECT [Employees].[EmployeeID],[Employees].[LastName],[Employees].[FirstName],[Employees].[Title],[Employees].[TitleOfCourtesy],[Employees].[BirthDate],[Employees].[HireDate],[Employees].[Address],[Employees].[City],[Employees].[Region],[Employees].[PostalCode],[Employees].[Country],[Employees].[HomePhone],[Employees].[Extension],[Employees].[Photo],[Employees].[Notes],[Employees].[ReportsTo],[Employees].[PhotoPath] FROM [Employees]
//内存中查询过滤
Employee[] filterredEmps = employeeList2.Filter(Employee._.HireDate >= new DateTime(1994, 1, 1), Employee._.City.Asc && Employee._.EmployeeID.Desc);

-

//分组和统计
CustOrderHistResult firstCountProductGroupByNameDesc = gateway.From<Product>().GroupBy(Product._.ProductName.GroupBy).OrderBy(Product._.ProductName.Desc).Select(Product._.ProductName, Product._.ProductID.Count()).ToFirst<CustOrderHistResult>();
SQL:
SELECT [Products].[ProductName],COUNT([Products].[ProductID]) FROM [Products] GROUP BY [Products].[ProductName] ORDER BY [Products].[ProductName] DESC

-

//聚合和查询函数
int maxProductUnit = Convert.ToInt32(gateway.From<Product>().Where(Product._.Discontinued == true).Select(Product._.ProductID.Max()).ToScalar());
SQL:
Text SELECT MAX([Products].[ProductID]) FROM [Products] WHERE ([Products].[Discontinued] = @p2qrwxrrwspri4h)
Parameters:
@p2qrwxrrwspri4h[Boolean] = 1

-

//查询中使用字符串函数
Category[] testStringFunctionsCats = gateway.From<Category>().Where(Category._.CategoryName.Contains("a") && Category._.CategoryName.Length > 2).ToArray<Category>();
SQL:
SELECT [Categories].[CategoryID],[Categories].[CategoryName],[Categories].[Description],[Categories].[Picture] FROM [Categories] WHERE (([Categories].[CategoryName] LIKE @pvvkhm25okrj9g8) AND (LEN([Categories].[CategoryName]) > @p1m9ulgpjn1llb4))
Parameters:
@pvvkhm25okrj9g8[String] = %a%
@p1m9ulgpjn1llb4[Int32] = 2

-

//查询中使用日期函数
DataSet testDateFunctionsDs = gateway.From<Employee>().Where(Employee._.HireDate.GetYear() == 1999 && Employee._.HireDate > PropertyItem.GetCurrentDate() - new TimeSpan(1000, 0, 0, 0)).ToDataSet();
SQL:
SELECT [Employees].[EmployeeID],[Employees].[LastName],[Employees].[FirstName],[Employees].[Title],[Employees].[TitleOfCourtesy],[Employees].[BirthDate],[Employees].[HireDate],[Employees].[Address],[Employees].[City],[Employees].[Region],[Employees].[PostalCode],[Employees].[Country],[Employees].[HomePhone],[Employees].[Extension],[Employees].[Photo],[Employees].[Notes],[Employees].[ReportsTo],[Employees].[PhotoPath] FROM [Employees] WHERE ((DATEPART(Year,[Employees].[HireDate]) = @pqr32n34ruererb) AND ([Employees].[HireDate] > GETDATE() - @p71cpbjv7gwwmqb))
Parameters:
@pqr32n34ruererb[Int32] = 1999
@p71cpbjv7gwwmqb[DateTime] = 1902-9-28 0:00:00

-

//透明的关联条件查询
Product[] testImplicitJoinsOfProducts = gateway.From<Product>().Where(Product._.Category.CategoryName.ToUpper() == "TEST" && Product._.Supplier.Country.ToLower() == "china").ToArray<Product>();
SQL:
SELECT [Products].[ProductID],[Products].[ProductName],[Products].[SupplierID],[Products].[CategoryID],[Products].[QuantityPerUnit],[Products].[UnitPrice],[Products].[UnitsInStock],[Products].[UnitsOnOrder],[Products].[ReorderLevel],[Products].[Discontinued] FROM ([Products] INNER JOIN [Categories] [Products_Category_Categories] ON [Products_Category_Categories].[CategoryID] = [Products].[CategoryID]) INNER JOIN [Suppliers] [Products_Supplier_Suppliers] ON [Products_Supplier_Suppliers].[SupplierID] = [Products].[SupplierID] WHERE ((UPPER([Products_Category_Categories].[CategoryName]) = @p8jv2o2wsphje48) AND (LOWER([Products_Supplier_Suppliers].[Country]) = @pqt37nednnvar7k))
Parameters:
@p8jv2o2wsphje48[String] = TEST
@pqt37nednnvar7k[String] = china

-

//透明的自关联查询
Employee[] testImplicitJoinsOfEmps = gateway.From<Employee>().Where(Employee._.ReportsToEmployee.FirstName == "teddy").ToArray<Employee>();
SQL:
SELECT [Employees].[EmployeeID],[Employees].[LastName],[Employees].[FirstName],[Employees].[Title],[Employees].[TitleOfCourtesy],[Employees].[BirthDate],[Employees].[HireDate],[Employees].[Address],[Employees].[City],[Employees].[Region],[Employees].[PostalCode],[Employees].[Country],[Employees].[HomePhone],[Employees].[Extension],[Employees].[Photo],[Employees].[Notes],[Employees].[ReportsTo],[Employees].[PhotoPath] FROM [Employees] INNER JOIN [Employees] [Employees_ReportsToEmployee_Employees] ON [Employees_ReportsToEmployee_Employees].[EmployeeID] = [Employees].[ReportsTo] WHERE ([Employees_ReportsToEmployee_Employees].[FirstName] = @pa552arjaiqopdc)
Parameters:
@pa552arjaiqopdc[String] = teddy

-

//显式的自定义join查询
Product[] testExplicitJoinsOfProducts = gateway.From<Product>().Join<Category>(Product._.CategoryID == Category._.CategoryID).Where(Category._.CategoryName.ToUpper() == "TEST").ToArray<Product>();
SQL:
SELECT [Products].[ProductID],[Products].[ProductName],[Products].[SupplierID],[Products].[CategoryID],[Products].[QuantityPerUnit],[Products].[UnitPrice],[Products].[UnitsInStock],[Products].[UnitsOnOrder],[Products].[ReorderLevel],[Products].[Discontinued] FROM [Products] INNER JOIN [Categories] ON ([Products].[CategoryID] = [Categories].[CategoryID]) WHERE (UPPER([Categories].[CategoryName]) = @pau7vfnemtpxcwj)
Parameters:
@pau7vfnemtpxcwj[String] = TEST

-

//带参数的自定义SQL查询
Category[] cats = gateway.FromCustomSql("select [CategoryID], [CategoryName], [Description], [Picture] from [Categories] where [CategoryID] > @p1 and [CategoryID] < @p2").AddInputParameter("p1", DbType.Int32, 100).AddInputParameter("p2", DbType.Int32, 2000).ToDataSet();
SQL:
select [CategoryID], [CategoryName], [Description], [Picture] from [Categories] where [CategoryID] > @p1 and [CategoryID] < @p2
Parameters:
@p1[Int32] = 100
@p2[Int32] = 2000

-

//调用存储过程
DataSet dsCustHits = gateway.FromStoredProcedure("CustOrderHist").AddInputParameter("CustomerID", DbType.String, "ALFKI").ToDataSet();
SQL:
CustOrderHist
Parameters:
@CustomerID[String] = ALFKI

-----------------------
NBearDataSource控件简介
-----------------------
NBearDataSource控件位于NBear.Web.Data.dll中,该控件是对NBear.Data的Web控件封装,可以像使用SqlDataSource那样使用它来方便绑定asp.net的数据绑定控件。
具体用法请参见:tutorials\NBearDataSourceSample教程。

------------------------------------
NBear.Data.Gateway强类型查询性能分析
------------------------------------
NBear.Data和ADO.NET及NHibernate的简单查询的性能分析可以参见:http://nbear.org/Modules/Articles/Detail.aspx?i=33

-----------------
NBear.IoC组件简介
-----------------
NBear.IoC组件提供了依赖注入的Service容器和分布式Service工厂等组件,能够实现透明的分布式服务部署。举例来说,只要你的Service以下面的形式定义:
[ServiceContract]
public interface MyService
{
//...
}
则编译后的服务的dll,无须重新编译,只需要修改几行配置文件,就可以轻松部署为单机模式或多服务器负载均衡模式运行。NBear.IoC组件可以直接兼容WCF中的Service。
具体的使用NBear.IoC组件的示例可以参见:tutorials\IoC_Tutorial和IoC_Adv_Tutorial教程。

-----------------
NBear.MVP组件简介
-----------------
NBear.MVP组件基于NBear.IoC组件,提供了对MVP模式的方便支持。结合NBear.IoC组件,使得MVP中的Model也就是Service部分可以透明的分布式部署。
具体的使用示例,请参见:tutorials\MVP_Tutorial教程。

-----------------
NBear.Web组件简介
-----------------
NBear.Web组件提供了一组Page/MasterPage/UserControl扩展基类。您将看到,使用这些基类能大大提高ASP.NET 2.0网页开发速度,轻松获得Ajax和多语言支持等功能。
更具体的使用示例请参见:tutorials\Web_Tutorial教程。

--------
更多资源
--------
更多关于NBear的开发资源请访问项目官方网站:http://nbear.org和博客园:http://www.cnblogs.com

----
致谢
----
感谢博客园和dudu对NBear项目的大力支持,并为NBear项目提供官方网站、FTP、SVN等的服务器支持,并由dudu牵线成立了目前的博客园NB团队,共同开发和维护NBear项目。
感谢所有在NBear的成长过程中参与测试和提出各种建议和意见的朋友。

----
后记
----
NBear还是一个起步时间不长,不断完善中的项目,有任何使用中的问题欢迎及时反馈,我们会尽快解决。希望更多朋友来关注和使用NBear。

 

posted on 2007-05-18 15:30 Teddy's Knowledge Base 阅读(8361) 评论(39)  编辑 收藏 所属分类: Web Dev.Ent. App. Dev.NBear

评论

#1楼  2007-05-18 15:47 菌哥      

感谢teddy!   回复  引用  查看    

#2楼  2007-05-18 15:49 try [未注册用户]

支持   回复  引用  查看    

#3楼  2007-05-18 16:06 xiaosonl      

@xiaosonl
今天真是多谢你的指点了   回复  引用  查看    

#4楼  2007-05-18 16:18 Justin      

好东西,这个周末开始搞搞 :-)   回复  引用  查看    

#5楼  2007-05-18 16:36 guozili [未注册用户]

学习linq为主,觉得nbear过于复杂   回复  引用  查看    

#6楼  2007-05-18 16:36 Vokobo      

绝对好东西。   回复  引用  查看    

#7楼  2007-05-18 16:38 Vokobo      

还有,
DUDU,
对于下面的行为,
学习一下,看看对我的eform快速开发平台(在线运行地址: http://demo.fcsoft.com.cn/eform )有没有帮助.

能不能在评论里过滤一下,只要含有demo.fcsoft.com.cn就不让写到数据库去。   回复  引用  查看    

#8楼  2007-05-18 17:03 五年      

这东西中国人做的吗??   回复  引用  查看    

#9楼  2007-05-18 17:28 stoneZhu [未注册用户]

正在试用中,力顶   回复  引用  查看    

#10楼  2007-05-18 18:08 大石头      

楼主似乎一直忽略了一个问题,NBear的确可以减轻程序员的工作,非常多人都想用NBear,但是,学习NBear的成本,实在是太高昂了,几乎与其优势相抵消。

你作为设计者,对这套系统非常熟悉,自然觉得很容易了。但是,对于绝大多数用户来说,……   回复  引用  查看    

#11楼  2007-05-18 20:35 WinKen      

太复杂了... 看了会头晕....   回复  引用  查看    

#12楼  2007-05-18 22:53 coolbo [未注册用户]

我一开始也觉得挺麻烦的,但是实际用过做点东西就觉得挺方便的了,建议实际用用看   回复  引用  查看    

#13楼  2007-05-18 23:30 袁永福      

将SQL转换为多级函数调用,不错的样子。   回复  引用  查看    

#14楼  2007-05-19 00:09 IcE      

不错啊,又有新的。下载看看   回复  引用  查看    

#15楼  2007-05-19 10:09 nt [未注册用户]

EntityArrayList不可以做数据源么?如下
EntityArrayList<DB_Color> colorlist= Gateway.Default.From<DB_Color>().ToArrayList<DB_Color>();
this.dataGridView1.DataSource = colorlist.;
gridview没有反映但是
this.dataGridView1.DataSource = colorlist.ToArray();
可以,怎么能让EntityArrayList直接做数据源   回复  引用  查看    

#16楼  2007-05-19 13:46 bugSharp      

teddy ,辛苦了!   回复  引用  查看    

#17楼  2007-05-19 20:21 Ivan Chin      

NBear 有没有实现 Left Join 和 Right Join查 询啊?   回复  引用  查看    

#18楼  2007-05-19 20:32 Ivan Chin      

NB从最初到现在我一直在关注,也在很多项目中用到了NB,
这篇文章虽然简单,但解决了我非常多关于NB的问题。非常感谢Teddy,感谢CCTV,感谢MTV。   回复  引用  查看    

#19楼  2007-05-20 08:03 命运有自己的梦!      

一直在用ActiveRecord,不过现在有点不打算再写代码了......   回复  引用  查看    

#20楼  2007-05-20 09:11 Apple [未注册用户]

mark   回复  引用  查看    

#21楼  2007-05-21 08:02 我不是神      

的确是好东西,我的项目中已经使用了,建议大家使用   回复  引用  查看    

#22楼  2007-05-21 11:58 JerryChou      

准备使用中,感谢开发者   回复  引用  查看    

#23楼  2007-05-21 20:00 Ellipse      

谢谢 teddy   回复  引用  查看    

#24楼  2007-05-21 22:21 wma [未注册用户]

今天真是多谢你的指点了   回复  引用  查看    

#25楼  2007-05-27 11:22 而且      

看了两三天,感觉好复杂.而且教程里感觉全是文字不容易理解,能否做一个从一开始到最后应用的一个操作流程的动画教程?比如第一步是不是通过数据库用工具建立接口,第二步设计实体类,第三步编译,第四步引用到实际项目中.现在看了教程完全是一头雾水.感觉没有象nhibernate那样简洁,它只需要建立实体关系xml文件,建立实体类,然后就可以应用了.   回复  引用  查看    

#26楼  2007-06-10 19:28 蛙蛙池塘      

快急死人了,ActiveEntity和EntityFactory弄哪儿了给,简直没法用了。   回复  引用  查看    

#27楼  2007-06-15 08:01 条码,条形码,条码打印机,条码解决方案 [未注册用户]

多谢你的指点了   回复  引用  查看    

#28楼  2007-06-15 12:30 @源 [未注册用户]

这几天我一直在看Near,感觉非常不错,不过有几个问题想给大家讨论一下:
1、本框架对事务是怎样处理的,在所有的例子中,都没有涉及到关于事务处理的内容
2、本框架支持缓存方式,但对缓存数据的并发访问是怎样控制的,是否考虑锁定之类的问题,若不考虑锁定,肯定会存在问题的

  回复  引用  查看    

#29楼  2007-07-01 09:21 heguo [未注册用户]

bug1:
parentEntity.ArrayList.Add(entity)操作,如果该entity在deletedList中,则会把对象从删除列表中移出,
虽然category.GetToDeleteRelatedPropertyObjects()["EntityArrayList"].count 为 0,
但category.GetToDeleteRelatedPropertyObjects().count > 0,parentEntity.IsModified是true,应为false;

bug2:
Category rootCategory = target.GetRootCategory();
Assert.IsTrue(rootCategory.SubCategoryList.Count == 2);
//Save语句,啥也没干,不应生成两条SQL:update Category set ParentID = "0000000...." where ID = "11111111111...";
target.Save(rootCategory);

测试数据,Category表其中一条记录为:
insert into Category(ID,Name,ParentID,RowIndex)
values('{00000000-0000-0000-0000-000000000001}','__root','{00000000-0000-0000-0000-000000000000}',0);
  回复  引用  查看    

#30楼  2007-07-11 14:16 天纯蓝 [未注册用户]

NBear否支持Oracle   回复  引用  查看    

#31楼  2007-07-27 14:58 @源 [未注册用户]

BUG!
我用了一个实体测试,此实体增加[BatchUpdate(10)]的属性,与其它实体无任何关系,数据库为Oracle XE,运行时出错:ORA-01036,(当不增加[BatchUpdate]属性时运行正常),跟踪了一下源程序,其参数是用@P方式表示的,我查了一下,据说,Oracle不支持@这种参数方式。我用的是V3.7.2.6的版本,请Teddy给解决一下,谢谢!   回复  引用  查看    

#32楼 [楼主] 2007-07-27 15:03 Teddy's Knowledge Base      

oracle不支持BatchUpdate。   回复  引用  查看    

#33楼  2007-07-29 21:11 @源 [未注册用户]

BUG!
以下语句:
Order[] ds = gateway.FromCustomSql("Select * From [Order]").ToArray<Order>();
当使用Select *时,若数据库在[Order]的字段顺序与Order实体的顺序不一致时,有错,错误发生在Entities.cs中的SetPropertyValues方法,原因是框架没有判断读出的数据字段是否与实体的属性一致,建议Teddy解决!谢谢   回复  引用  查看    

#34楼  2007-10-19 11:16 gateway [未注册用户]

想问一个问题,就是对于不想或者不喜欢采用数据库约束的情况(就是一般使用多表联合查询或者单表查询,直接写sql语句)下,NBear 是否也可以应用在web数据库开发中?

另外help manual别字太多,容易误导   回复  引用  查看    

#35楼  2007-10-20 00:01 Attr [未注册用户]

你的NBear为什么非要搞一堆Attribute呢?用这么多的Attribute去控制实体关联,是不是太不容易维护了?我不是排斥attribute,只是不同意采用接口的方式去限制实体的关系。
而且实体数据语句越来越LINQ了,准备放弃NBear了   回复  引用  查看    

#36楼  2008-02-23 11:44 lixin      

我试了一下Nbear的分布式IoC功能.发现还是很不完善的.
比如: 一个接口在Remoting的Host程序上注册有多个Component的实现时(使用不同的id,比如(
接口
IBiz
实现
BizOne:IBiz
BizTwo:IBiz
配置id分别为"One"和"Two" )
在远程进行如下调用:
IBiz biz = ServiceFactory.Create().GetService("One");
IBiz biz = ServiceFactory.Create().GetService("Two");
的返回居然是同一个对象(总是在Host上注册的第一个Component). 而如果使用Local工厂创建出来的对象可以正确的处理GetService的key参数. 也许我自己通过修改source可以修正这个bug,但是时间上不允许了... 所以因为这一点, 还是不能在项目中应用这个分布式的IoC啊. 现在正在考查Spring.net的分布式IoC. 还是感谢NBear小组的工作,非常棒. 希望能尽快修正bug.   回复  引用  查看    

#37楼  2008-03-13 15:54 无法平抑的忧伤 [未注册用户]

花了几天看了nbear3.7.2 关于ORM、Query的代码,我认为这个设计是失败的。功能是实现了,但是里面有了好多无关的东西,但是我想外部控制它,又没有什么办法,太难扩展了。还是用NHibernate,至少它没有那么多内部东西暴露出来而又不让我动这样的情形。   回复  引用  查看    

#38楼  2008-05-16 12:02 零缺陷生活      

想要问一下这种情况该如何处理:
两个自定义类:USER和DEPT,USER中包含一个DEPT_ID的属性,
那在显示USER信息的时候,需要显示DEPT_NAME.
如果在查询的过程中,参数和返回值都是以实体传递,那这种查询的结果该如何处理才能更加方便呢?
  回复  引用  查看    

#39楼  2008-05-16 12:04 零缺陷生活      

@零缺陷生活
我当前的处理方式是先查询指定条件的USER实体,再根据DEPT_ID逐个查询DEPT实体.   回复  引用  查看