随笔-27  评论-155  文章-0  trackbacks-1
  2008年7月5日

在.NET 3.5 平台上使用LINQ to SQL创建三层/多层Web应用系统 (Part 2)


上一篇文章:在.NET 3.5 平台上使用LINQ to SQL创建三层/多层Web应用系统 (Part 1)

LINQ to SQL
LINQ to SQL 提供了访问数据库的方法,且允许我们做所有数据库相关的操作,如查询、插入、更新和删除。LINQ to SQL消除了写存储过程和从数据访问层调用的过程,它可以在运行的时候自动生成合适的SQL脚本来进行数据库操作。在Visual studio中,你可以通过使用Add New Item 增加LINQ to SQL文件到项目中。下图1.4是Northwind数据库在Object Relational Designer 中的显示(EntLib.com 开源小组注:原文采用SampleDB数据库,这里我们采用Northwind 范例数据库)。当保存该文件时,LINQ to SQL自动创建一个CS文件或VB文件 – 用来访问数据库的DataContext类,还为设计器中的表创建一些必要的实体类。在设计器中的每一个表均有一个对应的实体类。
设计器中的表包含所有的数据库属性,包括表关系。设计器中的箭头标识表示数据库表的主键/外键关系。
EntLib.com 开源小组注:这里我们创建C# 项目,而不是原文采用的VB项目,因此后续的示例代码全部为C#,原文为VB代码。
 
DataContext
Solution 中的每一个LINQ to SQL设计器将自动创建一个DataContext类,用来查询数据库、检索数据记录和更新数据库操作的主要类,它包含了每一个表的属性。
 
实体类
LINQ to SQL为添加到设计器(.dbml文件)中的每一个表创建对应的实体类,这些实体类包含了强类型属性集合,映射到数据库中对应表的字段。LINQ to SQL使用这些实体类来生成数据操作的SQL脚本,同时,我们也可以创建实体类的实例,给实例赋值,然后在不同的层之间作为数据传输对象进行传递。(EntLib.com 开源小组注:这些实体类并不适合在WCF Service与Client 作为DTO传递,因为WCF对传输的实体类有特殊的attribute要求。对WCF Data Contract的要求,请您参加相关的文档。)
 
映射Mapping
DataContext类中的实体类和属性直接映射到对应数据表和字段。缺省情况下,在DataContext类中,LINQ使用继承抽象类MappingSource的AttributedMappingSource类来存放表和字段的映射信息,从数据库中检索记录和提交数据更新到数据库时需要这些映射信息。
 
重新生成DataContext
当数据库表设计发生变化时,必须更新DataContext类。我们建议在任何修改/更新数据表时,重新生成整个DataContext类。首先,删除DataContext 类文件(C# / VB文件);然后保存该文件,并自动DataContext类。或者你右键点击.dbml文件,找到Run Custom Tool 选项,然后点击重新生成DataContext类文件。
 
创建Data Linq
下图1.2显示Data Linq层,包含了DataContext类和实体类。这些类对应的代码文件由Visual studio自动生成。

1.2Data Linq 详细视图
 
solution中增加一个类库Class Library项目,然后增加LINQ to SQL到项目中。下图是Visual Studio 2008 增加一个新的LINQ to SQL的截屏,并在窗口中选择LINQ to SQL选项。


图1.3: 增加LINQ to SQL类
 
增加LINQ to SQL到项目中,将自动创建一个空白的设计器(.dbml文件),并附有server explorer的链接,同时也创建相关的dbml.layout文件(XML文件)和designer.cs文件(DataContext类文件 – http://www.EntLib.com 开源小组注:原文为VB文件)。打开server explorer,并建立到数据库的链接,然后导航到合适的数据库和表,接着拖放相关的表到设计器表面。最后,保存文件。现在,已经自动生成了包含相关的属性、方法的DataContext类和实体类。
为了演示的需要,我将使用Northwind 范例数据库(http://www.EntLib.com 开源小组注:原文采用自定义的sample数据库)。根据如下表结构,我们可以了解如何创建CURD操作层。如下图1.4显示含有这些表的dbml文件:


图1.4:LINQ to SQL设计器 - .dbml文件
 
下图1.5 是DataContext类和实体类的Class Diagram:


图1.5:Data LINQ – Class Diagram
注:DataContext 类自动负责打开数据库连接,执行数据操作和关闭连接。
 
 
EntLib.com 开源小组注:本文翻译《Building Multi-Tier Web Application in .NET 3.5 Framework Using LINQ to SQL》。后面内容待续。欢迎交流LINQ相关技术。

 
posted @ 2008-07-05 21:37 EntLib 阅读(266) | 评论 (2)编辑
  2008年7月4日
在.NET 3.5 平台上使用LINQ to SQL创建三层/多层Web应用系统 (Part 1)
 
 
在新的.Net Framework 3.5平台上,Microsoft发布了LINQ(C# 3.0, VB.Net 9.0)-集成语言查询(Language-Integrated Query),也就是通过编程语言来查询数据:
  • 数据库 (LINQ to SQL)
  • DataSet 数据集(LINQ to Dataset)
  • XML文档 (LINQ to XML) 
  • 实体对象 (LINK to Entities)
本文将演示如何在ASP.NET 3.0平台上,使用LINQ to SQL构建多层的Web应用程序。在当前的编程领域中,创建N-Tier应用程序成为一般的要求,且.NET Framework 提供了灵活的支持。一般而言,N-Tier应用程序有如下几个层:1. 表示层;2. 业务逻辑层;3. 数据访问层;4. 数据库层。每一层均完成特定的任务。本篇文章中介绍的架构和经典的N-Tier相似,不过数据库层替换新的DataLinq 层,使用LINQ to SQL 完成数据操作。
图1.1:基于LINQ to SQL的N-Tier架构
 
架构思考
如果你有大型ASP.NET项目的经历,你可能会注意到更多的时间花在写组件代码,而不是Web页面代码。有时,组件的设计和管理成为一个费时的过程,你可能正遇到架构方面的问题-寻找最好的方式来设计Web应用程序。
 
我写这篇文章的想法是介绍一个好的设计模式,并不是得到一个结论或者声明这是一个最好的N-Tier应用程序的设计模式。因为对于架构设计,每一个开发人员总是有自己的观点,所以任何合适的架构阐述都是有争议的。然而,如图1.1所示,分离不同的代码到不同的层总是一个好的实践。按这样组织代码,可以更方便地维护和扩展应用程序。
 
在图1.1中,你可以看到业务组件分割到不同的层。组织代码最好的方法是为每一个业务组件创建不同的类库(Class Library)。Visual Studio允许在同一个Solution中创建多个项目。因此,我们可以在同一个Solution中加入ASP.NET 应用程序和类库Class Library项目。当你在编译Solution时,每一个项目都会生成在bin目录下生成一个assembly程序集文件。方法1:我们可以手动复制.DLL文件到应用程序的bin目录。方法2:增加项目引用。当你编译Solution时,第二种方法可以自动更新应用程序bin目录的程序集文件。通过这种方式组织代码,可以更容易修改/更新项目的特定代码,也容易从不同的Server上迁移代码。我不想深入探讨架构,这里我通过截屏来解释如何实现。
 
假定你已经具备经典3层架构应用程序的设计经验,我告诉你如何建立层与层之间的引用关系,接着你可以自己建立项目引用。图1.1上的箭头符号说明了不同层之间的交互。说明如下:
(1) 数据访问层引用Data Linq 层(EntLib.com 开源小组注: 原文说还需要引用业务外观(Business Facade)层,原文有误)。
(2) 业务外观(Business Facade)层引用Data Linq 层和数据访问层,因为业务外观层使用Data Linq层的业务实体来创建表实体(后面进行详细讨论),同时调用数据访问层的方法。
(3) 表现层引用Data Linq层和业务外观层。
 
EntLib.com 开源小组注:本文翻译《Building Multi-Tier Web Application in .NET 3.5 Framework Using LINQ to SQL》。后面内容待续。欢迎交流LINQ相关技术。

posted @ 2008-07-04 23:15 EntLib 阅读(727) | 评论 (8)编辑
  2008年7月2日
LINQ to Objects / LINQ to SQL / LINQ to XML 示例程序下载
 
 
本LINQ示例程序,分别演示了LINQ to Objects / LINQ to SQL / LINQ to XML 的基本用法。
 
运行环境:Visual Studio 2008 + .Net Framework 3.5
数据库环境:SQL Server 2005 / Northwind 数据库



其他相关的LINQ文章:
使用LINQ to SQL和.Net 3.5 构建三层/多层Web Application
用LINQ to SQL 进行数据访问、更新和删除(附Demo示例程序下载)
LINQ – 使用DataLoadOptions 提高LINQ to SQL 查询性能
介绍几篇关于LINQ 的入门文章

示例程序下载!

posted @ 2008-07-02 22:58 EntLib 阅读(1142) | 评论 (4)编辑
LINQ – 使用DataLoadOptions 提高LINQ to SQL 查询性能
 
EntLib.com开源小组发表,http://www.EntLib.com,2008-7-2
LINQ to SQL 提供了 DataLoadOptions用于立即加载对象,避免往返访问数据库,提高查询性能。方法包括:
LoadWith 方法,用于立即加载与主目标相关的数据。
AssociateWith 方法,用于筛选为特定关系检索到的对象。
 
如下LINQ to SQL代码示例:
 
            OrderDataContext orderDC;
            orderDC = new OrderDataContext();
            orderDC.Log = Console.Out;
 
            DataLoadOptions dataLoadOption = new DataLoadOptions();
            dataLoadOption.LoadWith<Order>(r => r.Order_Details);
            orderDC.LoadOptions = dataLoadOption;
 
            var query = from ord in orderDC.Orders
                        select ord;
 
            grdOrder.DataSource = query;
            grdOrderDetail.DataSource = grdOrder.DataSource;
            grdOrderDetail.DataMember = "Order_Details";
 
通过使用LoadWith 方法指定应同时检索与主目标Order相关的Order Detail 数据,这样后续的查询方法仅访问一次数据库,并可同时获取Order、Order Detail 的所有信息。
 
如下是输出的SQL脚本:
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry], [t1].[OrderID] AS [OrderID2], [t1].[ProductID], [t1].[UnitPrice], [t1].[Quantity], [t1].[Discount], (
    SELECT COUNT(*)
    FROM [dbo].[Order Details] AS [t2]
    WHERE [t2].[OrderID] = [t0].[OrderID]
    ) AS [value]
FROM [dbo].[Orders] AS [t0]
LEFT OUTER JOIN [dbo].[Order Details] AS [t1] ON [t1].[OrderID] = [t0].[OrderID]
ORDER BY [t0].[OrderID], [t1].[ProductID]
 
使用 AssociateWith 方法指定子查询以限制检索的数据量。
在下面的示例中,AssociateWith 方法将检索的 Orders 限制为当天尚未装运的那些 Orders。如果没有此方法,则会检索所有 Orders,即使只需要一个子集。
DataLoadOptions dlo = new DataLoadOptions();
dlo.AssociateWith<Customer>(c => c.Orders.Where(p => p.ShippedDate != DateTime.Today));
db.LoadOptions = dlo;
var custOrderQuery =
    from cust in db.Customers
    where cust.City == "London"
select cust;
 
 
posted @ 2008-07-02 10:54 EntLib 阅读(96) | 评论 (0)编辑
  2008年6月29日
用LINQ to SQL 进行数据访问、更新和删除(附Demo示例程序下载)
 
Posted by EntLib.com, http://www.EntLib.com
2008-6-29
本示例主要包括如下内容:
映射LINQ到数据库 – LINQ to SQL定义新的C# 类、properties、attributes,通过在程序中映射数据库表到实体对象,可以与数据库表交互。
DataContext 类 – 该类支持LINQ的ORM功能。
 
本示例程序采用Northwind 数据库中的Customers 表。

  Demo 示例程序下载

代码分析:
映射实体类到数据库表:
    [Table(Name = "Customers")]
    public class Customer
    {
        private string _CustomerID;
        private string _CompanyName;
        private string _ContactName;
        private string _ContactTitle;
 
映射字段和属性到数据表列:
        [Column(Name = "CustomerID", Storage = "_CustomerID", DbType = "nchar NOT NULL",
        IsPrimaryKey = true, IsDbGenerated = false)]
        public string CustomerID
        {
            get { return _CustomerID; }
            set { _CustomerID = value; }
        }
 
        [Column(Name = "CompanyName", Storage = "_CompanyName", DbType = "nvarchar NOT NULL")]
        public string CompanyName
        {
            get { return _CompanyName; }
            set { _CompanyName = value; }
        }
 
创建DataContext 对象:
    public partial class CustomersDataContext : DataContext
    {
        public Table<Customer> Customers;
        public CustomersDataContext(String connString) : base(connString) { }
    }
 
查询数据库表Customers / 新增数据记录:
            CustomersDataContext customersDataContext = new CustomersDataContext(connString);
            // Redirect the log to the console
            customersDataContext.Log = Console.Out;
 
            var query = from cust in customersDataContext.Customers
                        where cust.CustomerID.StartsWith("AN")
                        select new { cust.CustomerID, cust.CompanyName, cust.ContactName, cust.ContactTitle };
 
            foreach (var row in query)
            {
                ObjectDumper.Write(row);
            }
 
            // Console.WriteLine(customers.GetCommand(query).CommandText);
 
            Customer customer = new Customer();
            customer.CustomerID = "Jacky";
            customer.CompanyName = "EntLib.com";
            customer.ContactName = "http://www.EntLib.com";
            customer.ContactTitle = "Developer";
 
            customersDataContext.Customers.InsertOnSubmit(customer);
            // The SubmitChanges Method propagates changes to the database
            customersDataContext.SubmitChanges();
 
示例程序界面如下:


如下是Console数据的SQL脚本,分别为查询、更新和删除操作。
SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle]
FROM [Customers] AS [t0]
WHERE [t0].[CustomerID] LIKE @p0
-- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [AN%]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
 
CustomerID=ANATR        CompanyName=Ana Trujillo Emparedados y helados ContactName=Ana Trujillo        ContactTitle=Owner
CustomerID=ANTON        CompanyName=Antonio Moreno Taquería     ContactName=Antonio Moreno      ContactTitle=Owner
INSERT INTO [Customers]([CustomerID], [CompanyName], [ContactName], [ContactTitle])
VALUES (@p0, @p1, @p2, @p3)
-- @p0: Input NChar (Size = 5; Prec = 0; Scale = 0) [Jacky]
-- @p1: Input NVarChar (Size = 10; Prec = 0; Scale = 0) [EntLib.com]
-- @p2: Input NVarChar (Size = 21; Prec = 0; Scale = 0) [http://www.EntLib.com]
-- @p3: Input NVarChar (Size = 9; Prec = 0; Scale = 0) [Developer]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
 
 
{Inserts: 0, Deletes: 0, Updates: 0}
SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle]
FROM [Customers] AS [t0]
WHERE [t0].[CustomerID] = @p0
-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [Jacky]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
 
UPDATE [Customers]
SET [CompanyName] = @p4, [ContactTitle] = @p5
WHERE ([CustomerID] = @p0) AND ([CompanyName] = @p1) AND ([ContactName] = @p2) AND ([ContactTitle] = @p3)
-- @p0: Input NChar (Size = 5; Prec = 0; Scale = 0) [Jacky]
-- @p1: Input NVarChar (Size = 10; Prec = 0; Scale = 0) [EntLib.com]
-- @p2: Input NVarChar (Size = 21; Prec = 0; Scale = 0) [http://www.EntLib.com]
-- @p3: Input NVarChar (Size = 9; Prec = 0; Scale = 0) [Developer]
-- @p4: Input NVarChar (Size = 19; Prec = 0; Scale = 0) [EntLib.com-专业电子商务系统]
-- @p5: Input NVarChar (Size = 9; Prec = 0; Scale = 0) [高级软件开发工程师]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
 
SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle]
FROM [Customers] AS [t0]
WHERE [t0].[CustomerID] = @p0
-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [Jacky]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
 
DELETE FROM [Customers] WHERE ([CustomerID] = @p0) AND ([CompanyName] = @p1) AND ([ContactName] = @p2) AND ([ContactTitle] = @p3)
-- @p0: Input NChar (Size = 5; Prec = 0; Scale = 0) [Jacky]
-- @p1: Input NVarChar (Size = 19; Prec = 0; Scale = 0) [EntLib.com-专业电子商务系统]
-- @p2: Input NVarChar (Size = 21; Prec = 0; Scale = 0) [http://www.EntLib.com]
-- @p3: Input NVarChar (Size = 9; Prec = 0; Scale = 0) [高级软件开发工程师]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8
posted @ 2008-06-29 07:33 EntLib 阅读(1605) | 评论 (2)编辑
  2008年6月28日

最新中国贫富标准线 你属哪个层次?

超级大富豪:年收入在5000万以上

大富豪:年收入在1000—5000万

富豪:年收入在300—1000万之间

富人:年收入在100—300万之间

高产者:年收入在30—100万之间

中产者:年收入在15—30万之间

低产者:年收入在8—15万之间

穷人:年收入在3—8万之间

很穷的人:年收入在1—3万之间

非常穷的穷人:年收入在5千—1万之间

穷得没衣服穿的人:年收入在1千—5千之间

穷得求生不得求死不能的穷人:年收入在100 —1000元之间

穷得几乎要死的穷人:年收入在30—100元之间

死路一条的穷人:年收入在30元以下

他们究竟有多富超级富豪们无法计算的财富

1.成功并不比失败更难

2.贫穷是一种疾病,但它是可以治愈的

3.钱来自人的内心,它是一种思想状态

4.一切财富的根源是人的下意识

5.思想的“自我编程”是成功的捷径

6.成功者与失败者的唯一区别在于自我暗示不同

7.富人就是为公众提供服务并得到回报的那些人

8.成功是一种习惯,失败也是一种习惯

9.你付出的努力就像存在银行的钱,可以在任何时候提取

10.像百万富翁一样思维,你必定成为百万富翁

找到最简单的成功原则

或许出于某些神秘的原因,富人们总是吸引着大众的目光。尽管我们探索富人的成功奥秘异常艰辛,但是,我们还是决定揭开围绕在富翁们身上的神秘面纱,披露他们积累财富的秘密,回顾他们是如何建立起属于他们的庞大帝国。我们写作本书的初衷实际上非常单纯,我们写作的基本前提是:

成功与命运无关(尽管成功偶尔可能与运气有关)

成功在于将一些具体的原则进行合理的应用

你瞧!出乎所有人的意料,我们的这条原理一次又一次被反复验证。我们研究的这十个亿万富翁都不同程度地应用了某些原则,或者说他们更从容地应用了这些原则。

当然,我们调查的这些伟人在执行这些原则时与我们并不相同,他们要比我们更坚定。同时,他们又都有各自的“特点”,有人强调这条具体原则,有人注重那条具体原则,这些具体的原则最后成为了这些人“标志性”或个性某晒健1热缋?amp;middot;克罗克,世界著名的汉堡包大亨,他是逆境中坚持不懈的典型代表,他在年届五十之后才获得了成功。五十岁对大部分人来说通常是他们考虑退休的年纪了。但在雷·克罗克的眼中,不屈不挠的精神是成功最重要的因素,所以他毫不犹豫地把这一条原则放在了才华和天份之上。

保罗·盖蒂是世界上最富有的人之一,他相信商业上的成功主要取决于如何引导人们的活动。毫无疑问,作为一个石油大王,保罗·盖蒂是一位杰出的领导者,他所透露的影响他整整一生的所有秘密,对世人而言是一笔珍贵的精神遗产,在本书中我们把他的秘诀展现在了读者面前。因为他们每一个人都主张一种主要的成功方法,所以对他们的生活加以研究,对我们寻找成功之路会有所启发。

靠自己奋斗成功的百万富翁

这个世界上的富翁分为两类。第一类是大家众所周知的“财产继承人”,他们出生富贵之家,在他们开始经商的时候,已经有了充足的储备资金。我们大家都清楚,如果腰包里已经有了几百万美元,创业要容易得多,因为只要得到一些良好的建议,这些资金就能带来滚滚财源。

第二类富人通常指那些白手起家,靠自己奋斗的人。与第一类富人不同,他们的成功同他们的出身毫无关系。因此,我们对研究这类富翁的生活更感兴趣,因为这些人同我们一样,创业之初,并没有多少优势,你即将读到的他们的生平故事勿庸置疑地证明了这一点。他们的童年相当普通,首席执行官:ceo.icxo.com时常在贫穷中度过,有时处境悲惨。在学校,他们当中的许多人都是名声不好的“笨学生”。然而,他们中的每一个人在人生的关键时刻,都决定把自己的命运掌握在自己的手中。他们或是受到一本书的启发,或是接受了朋友的建议,或是受到榜样的启迪,或是出于自身强烈的本能,一个接一个地迈向了成功。

古希腊大思想家苏格拉底曾意识到人作为自然生物的脆弱,与此同时,他也发现人是一种不断进化的生物,他们能够朝着某种理想而不断努力,完善和发展自身。同样道理,一个人致富的能力,不管看上去是多么渺小,也都可以培育和提高。而且,在人生的任何阶段都可能迸发出惊人的能量。

实际上,无论你的年龄有多大,无论你的出身如何,每一个人都有改变自身命运的机会,在这种关键时刻,你必须保持警觉,乐于接受和聆听建议。本书中包含的秘密会帮助你到达人生决定性的转折点,书中谈到的这十人正是在抓住人生转折的机遇后飞黄腾达的。

审计长李金华炮轰发改委,指其牵头搞机构改革不合适……我们选择的这十位靠自身努力获得成功的大师来自不同领域,所以大家可以发现在任何领域中都可能成功。当然,十个人不可能覆盖所有行业。然而不管怎样,他们表现出来的品质和坚持的原则对任何公司和个人都是适用的。我们的目的就是帮助读者获得同样的素质,学会应用他们的原则去获取成功。

我们选择的这十位百万富翁,他们的名字早已家喻户晓。他们是:

亨利·福特、康拉德·希尔顿、托马斯·沃森、雷·克罗克、本田宗一郎、沃尔特·迪斯尼、亚里士多德·奥纳希斯、约翰·洛克菲勒、保罗·盖蒂和斯蒂芬·斯皮尔伯格。

他们究竟有多富?

这些人到底有多少钱?保罗·盖蒂曾经说过,如果能计算出一个人的财富,那么他就不能算真正富有。我们研究分析的这些人物拥有的财富是令人难以置信的。他们究竟有多富?我们不可能知道。因为他们拥有各种复杂的股票组合,而这些股票的价值又在不断的变化中。另外,出于经济上的原因,大部分富翁对他们建立的帝国都态度谨慎,他们当中许多人对个人隐私过分看重,总是小心翼翼地避免向外界透露。

最能反映富翁这种心态的是保罗·盖蒂(霍华德·休斯是另一个典型,他还因此患上了恐惧症)。1957年,美国著名杂志《财富》发表了他们对世界上最富有的人的调查结果,保罗·盖蒂名列前茅,甚至到了那个时候,盖蒂还试图隐藏自己的真实姓名,公众对他一无所知。实际上,还有一个关于盖蒂不为人知的小故事,他的一个大学同学碰到保罗·盖蒂时,问盖蒂为谁工作,而盖蒂那时实际上早已是拥有数百万财产的富翁了。

尽管他们中的大多数人都很少谈及他们获得的财富,但他们非常乐意谈论成功背后的思想。他们中许多人都写过回忆录,给后世留下了宝贵的精神遗产。没有写过传记、回忆录的富翁在接受深入的采访时,通常也会敞开心扉,或者允许他们最亲近的同事学习他们的思想,这使我们的工作轻松了许多,当这些人解释他们成功的秘诀时,我们会坐下来聆听,因为他们的建议显然是非常珍贵的。

有一次,一个学生调查约瑟夫·肯尼迪(约翰·F·肯尼迪的父亲),问约瑟夫·肯尼迪为什么那样富有,约瑟夫冷冰冰地回答道:“我富有是因为我有很多钱。”约瑟夫·肯尼迪的资产价值3.6亿美元,但在解释他如何积累了如此巨额的财富时,他缄口不谈。幸运的是,我们所调查的这十位百万富翁并没有保密到如此程度,他们非常乐意向他人解释他们的策略,这样可以让他人从中受益。


文章来源:
http://fashion.ifeng.com/life/culture/200806/0627_52_621456.shtml

posted @ 2008-06-28 19:18 EntLib 阅读(116) | 评论 (2)编辑
Lambda 表达式分析
 
一个Lambda 表达式是这样编写的:首先定义一个参数列表,“=>”标记(针对Lambda运算符的C#标记全部来自Lambda演算)紧随其后,然后就是表达式。
 
The => token is called the lambda operator. It is used in lambda expressions to separate the input variables on the left side from the lambda body on the right side. Lambda expressions are inline expressions similar to anonymous methods but more flexible; they are used extensively in LINQ queries that are expressed in method syntax. The => operator is read as "goes to."--- FROM MSDN
 
LINQ to Object 和 Lambda 表达式示例:
            List<Person> people = new List<Person> {
                new Person { ID = 1,
                IDRole = 1,
                LastName = "Anderson",
                FirstName = "EntLib"},
                new Person { ID = 2,
                IDRole = 2,
                LastName = "Gray",
                FirstName = "Tom"},
                new Person { ID = 3,
                IDRole = 2,
                LastName = "Grant",
                FirstName = "Mary"}
            };
 
            var query = from p in people
                        where p.FirstName == "EntLib"
                        select p;
            ObjectDumper.Write(query);
 
            query = people.Where((p, index) => p.IDRole == index);
 
            ObjectDumper.Write(query);
 
其中(p, index) 就是参数列表,p.IDRole==index 就是表达式。Lambda 表达式的参数既可以是显式类型化的,也可以是隐式类型化的。编译器可以根据整个Lambda 表达式的上下文推断出参数的类型。
 
在C# 3.0 LINQ代码中,可以方便使用Lambda 表达式来建立查询表达式,任何要求delegate参数的方法,都可以传入一个Lambda 表达式。
 
C# 3.0 中也允许使用一系列代码语句来定义Lambda 表达式,当表达式必须使用多行代码处理参数时,可以使用一对大括号确定这些语句的范围。
query = people.Where((p, index) =>{
 Console.WriteLine("Hello, EntLib.com");
 Console.WriteLine("Value of index is :{0}", index);
 return p.IDRole == index;
});
 
EntLib.com 开源论坛开发小组,欢迎交流、分享.Net 技术和源代码。
 
posted @ 2008-06-28 16:50 EntLib 阅读(263) | 评论 (0)编辑
  2008年6月25日

A Look at LINQ
http://www.codeproject.com/KB/dotnet/ALookAtLinq.aspx
对LINQ Framework 进行基本介绍。

LINQ Introduction, Part 1 Of 3
http://www.codeproject.com/KB/vista/LINQ_1.aspx
主要介绍了LINQ to Object,逐个介绍了各个操作符(operator),并提供了可下载的LINQ演示程序。

Lambda Expressions and Expression Trees: An Introduction
http://www.codeproject.com/KB/cs/lambdaexpressions.aspx
以直观、浅显易懂的方式介绍了匿名方法、lambda 表达式、lambda表达式树等等。

LINQ 首部曲 : LINQ To Object Part 1
http://forum.entlib.com/Default.aspx?g=posts&t=74
重点介绍了LINQ框架、LINQ to Object(包括Implicit Local Variable、Extension Method、Lamba Expression、Anonymous Type)等等。

EntLib.com推荐上面的LINQ入门文章,欢迎交流、分享。

posted @ 2008-06-25 22:21 EntLib 阅读(1173) | 评论 (5)编辑
  2008年6月24日
Service Broker实现发布-订阅(Publish-Subscribe)框架(3)


这一主题前面相关的文章如下:
Service Broker实现发布-订阅(Publish-Subscribe)框架(1)
Service Broker实现发布-订阅(Publish-Subscribe)框架(2)


发布信息Publishing Information
这一节演示订阅者通过订阅从PublisherService服务接收信息,已经AuthorService如何发送新的article消息到PublisherService服务进行分发。在订阅者可以从PublisherService接收新的article消息之前,它必须请求一个订阅。可以通过发送一个 [http://ssb.csharp.at/SSB_Book/c10/SubscribeMessage] 消息来实现,代码如下:
 
订阅方请求订阅脚本:
DECLARE @ch UNIQUEIDENTIFIER;
BEGIN DIALOG CONVERSATION @ch
FROM SERVICE [SubscriberService1]
TO SERVICE 'PublisherService'
ON CONTRACT [http://ssb.csharp.at/SSB_Book/c10/SubscribeContract]
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION @ch
MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c10/SubscribeMessage]
(
N'<?xml version="1.0"?>
<Request xmlns="http://ssb.csharp.at/SSB_Book/c10/PublishSubscribe">
<Subject>Subject1</Subject>
</Request>'
);
GO
 
在上述脚本中,你必须在发送的消息中指定消息主题,随后会根据主题从PublisherService 中获取发布数据。在订阅者一设置好订阅,AuthorService就可以发送article消息给PublisherService进行分发。示例代码如下:
 
[AuthorService] 发送PublishMessage消息:
DECLARE @ch UNIQUEIDENTIFIER;
BEGIN DIALOG CONVERSATION @ch
FROM SERVICE [AuthorService]
TO SERVICE 'PublisherService'
ON CONTRACT [http://ssb.csharp.at/SSB_Book/c10/PublishContract]
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION @ch
MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c10/PublishMessage]
(
N'<?xml version="1.0"?>
<Publish xmlns="http://ssb.csharp.at/SSB_Book/c10/PublishSubscribe">
<Subject>Subject1</Subject>
</Publish>'
);
 
AuthorService必须指定随后的article消息属于哪一主题,它通过发送[http://ssb.csharp.at/SSB_Book/c10/PublishMessage] 消息类型,通知PublisherService 记录相应的发布记录。最后,AuthorService 发送属于前面指定主题的、不同的article消息。
 
发送特定主题的article消息:
SEND ON CONVERSATION @ch
MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c10/ArticleMessage]
(
N'This is an article on Subject1'
);
SEND ON CONVERSATION @ch
MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c10/ArticleMessage]
(
N'And this is another article on Subject1'
);
GO
 
在AuthorService 一发送article消息到PublisherService,这些消息将通过sp_PublisherService存储过程自动转发给订阅者。现在,你可以查询订阅者服务对应的队列,⑾址⑺偷腶rticle消息成功转发过来了。
 
备注:因为Service Broker内在的异步处理特性,在你查看SubscriberQueue1和SubscriberQueue2队列之前,你需要等待几秒钟,直到这些消息已经处理完成。
 
EntLib.com译者注:本文翻译Apress出版《Pro SQL Server 2005 Service Broker》的其中一个章节。现已翻译完成,欢迎交流、分享。谢谢!


posted @ 2008-06-24 22:37 EntLib 阅读(1247) | 评论 (0)编辑
  2008年6月23日
Service Broker实现发布-订阅(Publish-Subscribe)框架(2)


关于发布-订阅框架的介绍,请访问前一篇 Service Broker实现发布-订阅(Publish-Subscribe)框架(1) 。

应用发布者逻辑
在存储过程sp_PublisherService 中实现PublisherService服务的入口点(entry point)。当一有新的消息到达PublisherQueue队列是,sp_PublisherService存储过程自动激活,并开始处理消息。这一存储过程能够处理如下消息类型:
[http://ssb.csharp.at/SSB_Book/c10/PublishMessage]: 在存储过程开始发布article消息时,它需要从AuthorService接收该消息类型。这一消息包含有如下article消息相同的主题(Subject)。
[http://ssb.csharp.at/SSB_Book/c10/SubscribeMessage]: 在存储过程准备订阅一个主题时,它需要从订阅者服务方接收该消息类型。这一消息包含有订阅者请求的主题。
[http://ssb.csharp.at/SSB_Book/c10/ArticleMessage]: 在存储过程发布article消息时,它会从AuthorService方接收这一消息类型。
[http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog]: 在存储过程准备关闭PublisherService打开的会话时,存储过程会从AuthorService或订阅方服务接收这一消息类型。
[http://schemas.microsoft.com/SQL/ServiceBroker/Error]: 在请求的主题不存在是,存储过程将从PublisherService接收这一消息类型。
 
下面的script显示sp_PublisherService存储过程如何处理这些消息类型。
sp_PublisherService 服务处理程序:
CREATE PROCEDURE sp_PublisherService
AS
BEGIN
DECLARE @Conversation UNIQUEIDENTIFIER;
DECLARE @Message VARBINARY(MAX);
DECLARE @MessageTypeName SYSNAME;
BEGIN TRANSACTION;
WAITFOR
(
RECEIVE TOP(1)
@Conversation = conversation_handle,
@Message = message_body,
@MessageTypeName = message_type_name
FROM PublisherQueue
), TIMEOUT 1000;
 
WHILE (@Conversation IS NOT NULL)
BEGIN
IF (@MessageTypeName = 'http://ssb.csharp.at/SSB_Book/c10/PublishMessage')
BEGIN
EXEC sp_ProcessPublicationRequest @Conversation, @Message;
END
ELSE IF (@MessageTypeName ='http://ssb.csharp.at/SSB_Book/c10/SubscribeMessage')
BEGIN
EXEC sp_ProcessSubscriptionRequest @Conversation, @Message;
END
ELSE IF (@MessageTypeName ='http://ssb.csharp.at/SSB_Book/c10/ArticleMessage')
BEGIN
EXEC sp_SendOnPublication @Conversation, @Message;
END
ELSE IF (@MessageTypeName IN (
N'http://schemas.microsoft.com/SQL/ServiceBroker/Error',
N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'))
BEGIN
END CONVERSATION @Conversation;
IF (EXISTS (SELECT * FROM Publications WHERE Publication = @Conversation))
BEGIN
EXEC sp_RemovePublication @Conversation;
END
IF (EXISTS (SELECT * FROM Subscribers))
BEGIN
EXEC sp_RemoveSubscriber @Conversation;
END
END
ELSE
BEGIN
-- Unexpected message
RAISERROR (N'Received unexpected message type: %s', 16, 1,
@MessageTypeName);
ROLLBACK;
RETURN;
END
COMMIT;
SELECT @Conversation = NULL;
BEGIN TRANSACTION;
WAITFOR
(
RECEIVE TOP(1)
@Conversation = conversation_handle,
@Message = message_body,
@MessageTypeName = message_type_name
FROM PublisherQueue
), TIMEOUT 1000;
END
COMMIT;
END
GO
 
在上面的存储过程中,先从PublisherQueue队列中接收一个新的消息。如下消息类型为[http://ssb.csharp.at/SSB_Book/c10/PublishMessage],就调用sp_ProcessPublicationRequest 存储过程,将接收到的发布数据记录到Publications表中。如果为[http://ssb.csharp.at/SSB_Book/c10/SubscribeMessage] 消息类型,则调用sp_ProcessSubscriptionRequest 存储过程,负责将接收到的订阅数据记录到Subscriptions表中。最后,如果为 [http://ssb.csharp.at/SSB_Book/c10/ArticleMessage]消息类型,则sp_PublisherService存储过程负责调用sp_SendOnPublication 分发该消息给所有匹配的订阅者。
 
通过sp_ProcessPublicationRequest 和sp_ProcessSubscriptionRequest 存储过程来管理发布和订阅记录。这2个存储过程分别调用其他的存储过程,将接收到的消息插入到Publications 或 Subscriptions 表中。如下显示 the sp_ProcessPublicationRequest 存储过程。因为sp_ProcessSubscriptionRequest 存储过程比较相似,这里忽略该存储过程。
 
sp_ProcessPublicationRequest 存储过程脚本:
CREATE PROCEDURE sp_ProcessPublicationRequest
@Conversation UNIQUEIDENTIFIER,
@Message VARBINARY(MAX)
AS
BEGIN
DECLARE @Request XML;
DECLARE @Subject NVARCHAR(MAX);
SELECT @Request = CAST(@Message AS XML);
WITH XMLNAMESPACES (DEFAULT 'http://ssb.csharp.at/SSB_Book/c10/PublishSubscribe')
SELECT @Subject = @Request.value(N'(//Publish/Subject)[1]', N'NVARCHAR(MAX)');
IF (@Subject IS NOT NULL)
BEGIN
EXEC sp_PublishPublication @Conversation, @Subject, @Message;
END
ELSE
BEGIN
END CONVERSATION @Conversation
WITH ERROR = 1
DESCRIPTION = N'The publication is missing a subject';
EXEC sp_RemovePublication @Conversation;
END
END
GO
 
sp_ProcessPublicationRequest存储过程调用sp_PublishPublication,并传入@Conversation, @Subject, @Message 三个参数。如下是sp_PublishPublication 存储过程。
sp_PublishPublication 存储过程脚本:
CREATE PROCEDURE sp_PublishPublication
@Publication UNIQUEIDENTIFIER,
@Subject NVARCHAR(MAX),
@OriginalXml XML
AS
BEGIN
INSERT INTO Publications (Publication, Subject, OriginalXml)
VALUES
(
@Publication,
@Subject,
@OriginalXml
)
END
GO
 
Publications 表中的Publication列和Subscriptions表中的Subscription 列都存放会话ID,你需要这些会话ID来发送article消息到订阅方。最后一个存储过程是sp_SendOnPublication,在有[http://ssb.csharp.at/SSB_Book/c10/ArticleMessage] 消息从 AuthorService接收到后,调用才存储过程。
sp_SendOnPublication 存储过程脚本:
CREATE PROCEDURE sp_SendOnPublication
@Publication UNIQUEIDENTIFIER,
@Article VARBINARY(MAX)
AS
BEGIN
DECLARE @Subscription UNIQUEIDENTIFIER;
DECLARE @cursorSubscriptions CURSOR;
SET @cursorSubscriptions = CURSOR LOCAL SCROLL FOR
SELECT Subscriber
FROM Subscriptions s
JOIN Publications p ON s.Subject = p.Subject
WHERE p.Publication = @Publication;
BEGIN TRANSACTION;
OPEN @cursorSubscriptions;
FETCH NEXT FROM @cursorSubscriptions
INTO @Subscription;
WHILE (@@fetch_status = 0)
BEGIN
 
IF (@Article IS NOT NULL)
BEGIN
SEND ON CONVERSATION @Subscription
MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c10/ArticleMessage] (@Article);
END
ELSE
BEGIN
SEND ON CONVERSATION @Subscription
MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c10/ArticleMessage];
END
FETCH NEXT FROM @cursorSubscriptions INTO @Subscription;
END
CLOSE @cursorSubscriptions;
DEALLOCATE @cursorSubscriptions;
COMMIT;
END
GO
 
sp_SendOnPublication 存储过程使用一个cusor,发送从AuthorService接收到的article消息,给匹配的订阅者。
SEND ON CONVERSATION @Subscription
MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c10/ArticleMessage] (@Article);
 
通过对Publications 和 Subscriptions 表的Subject 字段进行连接,进行匹配:
SELECT Subscriber
FROM Subscriptions s
JOIN Publications p ON s.Subject = p.Subject
WHERE p.Publication = @Publication;
 
当接收到的是[http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog] 消息类型时(从AuthorService或从订阅者服务方),相应的发布或订阅数据则需要从Publications或Subscriptions表中删除。分别通过sp_RemovePublication 或 sp_RemoveSubscriptions 存储过程来实现。
sp_RemovePublication 存储过程脚本:
CREATE PROCEDURE sp_RemovePublication
@Publication UNIQUEIDENTIFIER
AS
BEGIN
DELETE FROM Publications
WHERE Publication = @Publication
END
GO

 
EntLib.com译者注:本文翻译Apress出版《Pro SQL Server 2005 Service Broker》的其中一个章节。后面的内容会尽快发布,欢迎交流、分享。谢谢!
posted @ 2008-06-23 20:23 EntLib 阅读(1146) | 评论 (2)编辑