2014年10月24日 星期五

[iThome 第七屆鐵人賽 25] 搜索頁面 - Service層的工作 - 搜索在進化

在上一篇介紹完了如何顯示搜索表單之後,一個基本的通用搜索功能就完成了。

不過,其實有些部份還可以在加強,舉例來說,目前搜索是一定要完全符合才搜索的到,但是這樣就失去了很多好處,畢竟如果完全符合才搜索的到,那基本上等於搜索不到。

還有,假設今天我們搜索結果是要給使用者看的,通常都會有所謂的上下架起訖時間和是否啟用,當符合條件才可以看,這一部份其實自動搜索也可以幫到我們。

因此這一篇將會介紹未來如何在擴充自動搜索功能和在搜索做一些客制處理,符合只搜索出前臺使用者看的條件。

以Like的方式搜索

第一個要處理的是針對string類型的用like方式做搜索。要用Like方式做搜索,就要用到Linq裡面的Contain()語法:

/// <summary>
/// 依照Search Form ViewModel的值來設定Where的內容。
/// </summary>
/// <typeparam name="T">通常是EF的Entity</typeparam>
/// <param name="data">要被處理的資料</param>
/// <param name="searchForm">Search Form Viewmodel的值</param>
/// <returns>有增加OrderBy的IQueryable</returns>
public static IQueryable<T> DynamicWhere<T>(this IQueryable<T> data, ISearchFormViewModelBase searchForm)
{
var properties = searchForm.GetType().GetProperties
(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
.Where(x => (x.GetGetMethod().GetBaseDefinition() == x.GetGetMethod())).ToArray(); // where 條件是用來避免override的property (例如:OrderByColumnName)也被算進去。

string whereCalus = string.Empty;
string andOperator = string.Empty;
List<object> propertiesValue = new List<object>();

for (int i = 0; i < properties.Length; i++)
{
var value = properties[i].GetValue(searchForm);

if (string.IsNullOrEmpty(value.NonNullString()) == false)
{
whereCalus = string.Format("{0}{1} {2}.Contains(@{3})", whereCalus, andOperator,
properties[i].Name, propertiesValue.Count);

andOperator = " and";

propertiesValue.Add(value);
}
}

if (string.IsNullOrEmpty(whereCalus) == false)
{
data = data.Where(whereCalus, propertiesValue.ToArray());
}

return data;
}

被高亮的行數就是和之前不一樣的地方。


Like搜索帶來的問題


上面修改完成之後,假設去執行,搜索都正常,但是如果有欄位是數值形態(int)會出錯,因為int是不能夠做Like的。因此,修改成:

...

for (int i = 0; i < properties.Length; i++)
{
var value = properties[i].GetValue(searchForm);

if (string.IsNullOrEmpty(value.NonNullString()) == false)
{
// 如果形態是string,就用Like方式查詢
if (properties[i].PropertyType == typeof(string))
{
whereCalus = string.Format("{0}{1} {2}.Contains(@{3})",
whereCalus, andOperator,
properties[i].Name, propertiesValue.Count);
}

// 如果形態是int,就用等於查詢
if (properties[i].PropertyType == typeof(int))
{
whereCalus = string.Format("{0}{1} {2} = @{3}",
whereCalus, andOperator,
properties[i].Name, propertiesValue.Count);
}

andOperator = " and";

propertiesValue.Add(value);
}
}
...

這個基本上就是多了一個判斷,如果是string,就用like方式搜索,如果是int,就用符合的方式搜索。


未來這個其實可以在被擴充,可以透過Attribute的方式,告知要用什麼方式做搜索。或許有些欄位是要做某個範圍之內的值,或者大於小於等。

結語


這一篇主要介紹的是在未來如何擴充自動搜索的部分。其實,自動搜索可以千變萬化,除了基本的一些大小於搜索,有時候我們可能會依照一個欄位的flag去決定是否要顯示,或者上下架時間。這些都可以透過自動搜索來做處理,而前面呼叫Service的不用記得需要加入這些預設的搜索條件,因為Service層已經做好了。


沒有留言 :

張貼留言