315技术社区's Archiver

购买请咨询客服QQ:604164

wolaile 发表于 2008-5-11 10:28

C#3.0之LINQ数据库应用

[b]1.C#3.0简述[/b]
C#3.0 已经推出有一段时间了,相信大家也和我一样对其中的技术亮点激动不已吧,Automatic Properties, Object/Collection Initializers, LINQ Language, Extension Method等无数的新技术大大加快了我们的开发进程,下面我将以一个网络书店的实例向大家展示LINQ语言在数据检索方面的巨大优势。

LINQ全名叫做Language-Integrated Query,字面意思就是集成到语言中的查询语言,目前在C#3.0,VB9中你都可以使用这种语法用来在数据集合,XML文件和数据库中检索数据。举个例子来说,比如我们数据库表users中的所有用户取出来,以前的做法可能是使用一个SqlCommand来初始化查询,然后取回数据结果集,最后再对结果集进行分析,而现在使用LINQ只需要写一行语句即可:
[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]var allUsers =
from user in users
select user;


[align=left]是不是很简单呢:)

下面给大家介绍一下网络书店项目需要用到4张表。
[/align][font=Tahoma][size=3][size=10.5pt]Tbl_books[/size][/size][/font]                                                                                                                                             
[align=left][img=450,204]http://image.it168.com/cms/2007-8-20/Image/2007820103148.jpg[/img][/align][font=Calibri][size=3]   
[/size][size=3]Tbl_Users
[img=450,207]http://image.it168.com/cms/2007-8-20/Image/2007820103735.jpg[/img]
[/size][size=3]
Tbl_Bills
[img=450,121]http://image.it168.com/cms/2007-8-20/Image/2007820104246.jpg[/img]

[font=Tahoma][size=10.5pt][size=1]Tbl_type[/size][/size]
[size=10.5pt][img=450,67]http://image.it168.com/cms/2007-8-20/Image/2007820104547.jpg[/img][/size][/font][/size][/font]
1

wolaile 发表于 2008-5-11 10:28

[b]2[font=宋体].[/font][font=Calibri]SqlMetal[/font]工具的使用[/b][size=3]
OK,言归正传,在正式使用LINQ进行数据库操作之前,我先介绍一个叫做SqlMetal的工具,这个工具是包含在DLinq的安装包内的,不过我相信很多人已经将VS Orcas这个大块头下载下来了:)。在你安装完Orcas之后您也可以在安装目录下找到这个工具(默认的路径是C:\Program Files\Microsoft Visual Studio 9.0\SDK\v3.5\Bin)。

下面我给大家介绍一下这个工具的用途。

有经验的ASP.NET开发人员都知道,我们在对数据库进行操作的时候往往是先把它实体化,然后在程序中再对这些实体对象进行操作,这样代码逻辑显得很清晰,便于以后的业务拓展和维护。一般的做法是,每一张表生成一个实体类,比如在我们这个项目中,生成BookProvider, UserProvider, BillProvider, TypeProvider几个类,这样也会带来两个问题,第一类文件繁多不好管理,第二类是我们处理数据库得到的是表结构,除非我们定义更多的数据结构类型,才能构造出返回结果的具体型别。

SqlMetal这个工具就是用来解决上面所说到的问题的,指定一个数据库实例,它可以以一种优雅的方式生成该数据库的实体类。使用也相当简单,读者可以通过在命令行输入:

SqlMetal /?


来查看SqlMetal的命令行参数。在这里我们输入下面的命令生成网络书店数据库的实体类:


Sqlmetal /pluralize /code:Books.cs d:\TestSecBooks\Books.mdf

这里限于篇幅,不能将Books.cs的详细内容打印出来,有兴趣的朋友可以自己研究一下SqlMetal生成的代码,我在后面会详细介绍它的使用方法,大家会发现它大大简化了我们对数据库的操作。
[/size]

wolaile 发表于 2008-5-11 10:29

[b]3.用户搜索模块的实现[/b]
现在回到我们的网站,作为一个网络书店,最重要的一点是,让用户迅速找到自己想要的书,另一方面,书店也要不断的通过更新数据来留住顾客用户,比如设立排行榜,每天都放置一些特价图书等等,下面我将详细介绍LINQ是如何实现这两方面内容的。

用户搜索模块
一般来说,网站会提供一个搜索框,然后用户输入关键字用于对作者、标题或者简介的搜索,在这里为了说明简便,我把多项搜索和到了一起,即只要关键字出现在三者之一,程序就把它们搜索出来。
[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]public IQueryable<Tbl_book> GetSearchBooks(string keyWord)
        {
            Books books = new Books(ConnectionString);
            var searchBooks =
                from book in books.Tbl_books
                where
                (   book.Title.Contains(keyWord)||
                    book.Author.Contains(keyWord)||
                    book.Description.Contains(keyWord)
                )
                select book;
            return searchBooks;
        }


大家注意,我们在这里返回了一个IQueryable<Tbl_book>的接口,其中Tbl_book就是我们之前用SqlMetal工具生成的一个实体类,我们可以轻松地在数据显示层调用这个方法:

[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]foreach (var tbl_book in BooksProvider.GetSearchBooks(keyWord))
{
//...
}


大家可以对比一下传统做法,就会发现代码简单了很多。


public IList GetSearchBooks(string keyWord)
{
SqlConnection conn = new SqlConnection(ConnectionString);
conn.Open();
SqlCommand command = new SqlCommand("select * from tbl_books where title = @keyWord or author = @keyWord or description = @keyWord");
command.Parameters.Add("@keyWord", SqlDbType.VarChar).Value = "%" + keyWord + "%";
SqlDataReader reader = command.ExecuteReader();

//这里的Book是另外定义的tbl_Book的实体类
List<Book> retList = new List<Book>();
while (reader.Read())
{
Book book;

book.id = reader.GetInt32(0);
book.title = reader.GetString(1);
book.type_id = reader.GetInt32(2);
book.price = reader.GetDouble(3);
book.author = reader.GetString(4);
book.description = reader.GetString(5);
book.add_time = reader.GetDateTime(6);
book.user_id = reader.GetInt32(7);
book.image = reader.GetString(8);
book.clicks = reader.GetInt32(9);
book.isspecial = reader.GetInt32(10);

retList.Add(book);
}

return retList;
}
[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]


在这里,大家可能会发现这样一个问题,上面的代码都是返回了整个tbl_book表格的结构类型,但有时候我们并不需要tbl_book所有的整个字段,这些不需要的字段就造成了存储空间的浪费。举个例子,用户在修改密码时我们只要用户名和密码是否一致就可以,如果此时把整个tbl_user都返回,那么其他的字段空间都被浪费掉了,对于这种情况,我们将代码修改如下:

Books books = new Books(ConnectionString);

var usersChangePwd =
from user in books.Tbl_users
where (
(name == user.User_name) &&
(pwd == user.User_pwd)
)
select new { user.User_name, user.User_pwd };
[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]

大家可以看到,这里返回了一个匿名类型,其中只有User_name,User_pwd这两项属性值,但这对于用户修改密码这个逻辑来说已经足够了。如果用传统方法来实现我们需要再定义一个数据类型,显得不够灵活。
同样,我们可以在数据显示层用foreach语句把数据取出来:

[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]foreach (var user in usersChangePwd)
            {
                string user_name = user.User_name;
                string user_pwd = user.User_pwd;
        }

wolaile 发表于 2008-5-11 10:29

[b]4.排行榜、特价书等逻辑的实现

[/b]首先看排行榜的实现:

public static IQueryable<Tbl_book> GetClicksTopBooks(int topNum)
        {
            Books books = new Books(ConnectionString);
            var topBooks =
                (from book in books.Tbl_books
                orderby book.Clicks descending
                select book).Take(10);
            return topBooks;
    }



这里使用了LINQ的Take语句,首先按价格从高到低排列,然后取出排在前面的10个数据。下面我们看一下特价书的实现:

[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]public IQueryable<Tbl_book> GetSpecialBooks()
        {
            Books books = new Books(ConnectionString);
            Books booksSpecial =
                from book in books.Tbl_books
                where (book.Isspecial == true)
                select book;
            return booksSpecial;
     }



下面再介绍一个例子,使大家对LINQ有更深一层的理解。

例如:我们现在需要统计出各个类别的图书分别有多少本,以及各类图书的点击总量

[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]var groupBooksNumAndClicks =
from book in books.Tbl_books
group book by book.Type_id into g
select new { type = g.Key, booksSum = g.Count(), clicksSum = g.Sum(p => p.Clicks) };



这里使用了Group by语句和扩展方法Sum轻松的实现了这一逻辑,这里的匿名类型中type显示的是type id,可能读者朋友们觉得不够直观,没关系,我们稍作修改如下:

[img]http://129.0.0.116/Images/OutliningIndicators/None.gif[/img]var groupBooksNumAndClicks =
from book in books.Tbl_books
from type in books.Tbl_types
where book.Type_id == type.Id
group book by type.Name into g
select new { type = g.Key, booksSum = g.Count(), clicksSum = g.Sum(p => p.Clicks) };


OK!这里我们把tbl_type表也添加进来,并把group的Key值设为type.Name,这样我们取出的type就是真实的类型名称了。

5.总结
从上面几个例子可以看出,LINQ语句将SQL的部分语法整合进C#语句中,使得程序在检索数据方面显得相当灵活,增强了编程语言在数据检索方面的能力,使我们能够更加专注于数据逻辑的设计而非实现。上面的介绍只是对LINQ应用的一个简单介绍,更多的内容还等着朋友们自己去发掘哦:)

页: [1]

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.