技术开发 频道

整合Java 6脚本、Groovy实现动态 MVC模式(二)


【IT168技术文档】
1.C#3.0简述

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只需要写一行语句即可:

var allUsers =
from user in users
select user;

是不是很简单呢:)

下面给大家介绍一下网络书店项目需要用到4张表。 

Tbl_books                                                                                                                                             

   
Tbl_Users


Tbl_Bills


Tbl_type


2
SqlMetal工具的使用

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生成的代码,我在后面会详细介绍它的使用方法,大家会发现它大大简化了我们对数据库的操作。

 

 

 

 

 

 

 


3.用户搜索模块的实现

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

用户搜索模块
一般来说,网站会提供一个搜索框,然后用户输入关键字用于对作者、标题或者简介的搜索,在这里为了说明简便,我把多项搜索和到了一起,即只要关键字出现在三者之一,程序就把它们搜索出来。

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工具生成的一个实体类,我们可以轻松地在数据显示层调用这个方法:

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;
}


在这里,大家可能会发现这样一个问题,上面的代码都是返回了整个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 };

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

foreach (var user in usersChangePwd)
            {
                string user_name = user.User_name;
                string user_pwd = user.User_pwd;
        }

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

首先看排行榜的实现: 

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个数据。下面我们看一下特价书的实现:

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有更深一层的理解。

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

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,可能读者朋友们觉得不够直观,没关系,我们稍作修改如下:

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应用的一个简单介绍,更多的内容还等着朋友们自己去发掘哦:)
0
相关文章