最近在做一個數據檢索的工作,對一個數據庫中的寬表進行多個條件的檢索。爲了簡單方便快捷的完成這個功能,我使用LINQ to SQL+ReportView的方式來完成。
首先需要做的是一個查詢界面和寫一個數據庫查詢方法。用戶在輸入框中輸入多個指標,將根據指標的格式生成LINQ的Where語句。這個很容易實現,比如輸入“2003 北京 人口”,那麼就根據空格將這個字符串分成3個字符串,第一個字符串格式是年份,所以用表中的Year字段進行匹配,第二個字段是地區,所以再用表中的Location進行匹配,第三個是指標,那麼就用指標進行匹配,具體的C#代碼就是:
public static List<Data2010> SearchData(string itemName)
{
using (DataClassesDataContext dc = new DataClassesDataContext())
{
var data = from d in dc.Data2010s
select d;
string[] items = itemName.Split(' ');
foreach (string item in items)
{
if (IsYear(item))
{
int year = Convert.ToInt32(item);
data = data.Where(d => d.Year ==year);
}
else if (IsLocation(item))
{
string location=item;
data = data.Where(d => d.Location == location);
}
else
{
string keyword=item;
data = data.Where(d => d.Indicator.Contains(keyword));
}
}
return data.ToList();
}
}
這個功能還簡單,畢竟多個指標之間都是與的關係,但是接下來如果要實現或的關係,那麼又該怎麼辦呢?這個讓我傷了幾天的腦筋。比如說如果要搜索北京、上海、重慶的2000年和2010年的人口,那麼該怎麼查呢,我定義了一個簡單的語法,如果是或關係的指標,那麼就在小括號中用空格隔開。那麼查詢字符串就變成了:
(北京 上海 重慶)(2000 2010) 人口
這樣括號之間是與的關係,括號內的內容是或的關係。
但是真正的難點是如何用LINQ來實現動態的或查詢。我第一想到的是Dynamic LINQ(具體參見:這裏),這個在之前的項目中用過,特別強大,但是在這裏用起來不是很方便,所以又想自己實現一套動態OR查詢的方法,結果由於時間和能力有限,也沒有做出來,最後終於找到一個很好的類庫LinqKit,這個類庫中有一個
PredicateBuilder類,可以非常簡單的實現動態的邏輯或查詢。到網站中下載該類庫並添加到項目中,然後引用命名空間,將我們的搜索方法改爲如下內容:
public static List<Data2010> SearchData(string itemName)
{
using (DataClassesDataContext dc = new DataClassesDataContext())
{
var data = from d in dc.Data2010s
select d;
Regex r = new Regex(@"\([^\)]*\)");
var ms = r.Matches(itemName);//匹配括號及其中的內容
if (ms.Count > 0)
{
foreach (Match m in ms)
{
string name = m.Value.Substring(1, m.Value.Length - 2);//去掉括號,只剩下之間的內容
string[] items = name.Split(' '); //各個Item之間是or的關係 空格區分
var predicate = PredicateBuilder.False<Data2010>();
foreach (string item in items)
{
predicate = predicate.Or(WhereCondition(item));//這裏就是要用的動態邏輯或查詢
//WhereCondition的定義是:Expression<Func<Data2010, bool>> WhereCondition(string item),就是根據item的格式判斷該用哪個字段進行匹配
}
data = data.Where(predicate);//將最後的predicate傳入Where函數,相當於是對括號之間進行邏輯與查詢
}
itemName = r.Replace(itemName, " ");//把括號給替換掉,再對括號外的內容進行邏輯與查詢
}
string[] items2 = itemName.Split(' ');
foreach (string item in items2)
{
data = data.Where(WhereCondition(item));
}
return data.ToList();
}
}
數據庫查詢函數已經完成,接下來就是要用ReportViewer來展現查詢出來的結果綁定到報表中,具體代碼如下:
private void BindData(string q)
{
var datas = DbOperation.SearchData(q);
this.ReportViewer1.LocalReport.DataSources.Clear();
this.ReportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource(
"DataSet1", datas));
this.ReportViewer1.DataBind();
}
這裏的DataSet1就是對於rdlc報表的數據源,不能寫錯。