在上一篇介紹完了搜索功能的概念和思路之後,在這一篇開始要看實作的部份。
通常寫Mvc都是從Model開始,因此這一篇將來看一下搜索功能所會使用到的ViewModel
ViewModel的內容
首先,搜索的ViewModel必然會有兩個Property:
- 搜索條件
- 搜索結果
因此,我們會先從這兩個部份的Property來看起。
搜索條件的ViewModel
搜索條件會有一定有的欄位和各個domain所需要的欄位,因此會先定義一個Base,好方便之後domain來繼承並且提供其他相關欄位。
一定會有的欄位像是:
- 每頁筆數
- 目前頁數
- 排序欄位
- 排序順序
Domain相關的欄位就依照各自的需求,例如假設是一篇文章,可能會有以“標題”做搜索或者以“內文”做搜索。
因此,程式碼會如下:
/// <summary>
/// 搜索 Form 的 ViewModel base。定義搜索必須要有的相關欄位。
/// </summary>
public abstract class SearchFormViewModelBase : ISearchFormViewModelBase
{
/// <summary>
/// 目前頁數的值
/// </summary>
private int page;
/// <summary>
/// 取得或設定目前頁數。最小值是1。
/// </summary>
/// <value>
/// 目前頁數
/// </value>
public virtual int Page
{
get
{
if (this.page < 1)
{
this.page = 1;
}
return this.page;
}
set { this.page = value; }
}
/// <summary>
/// 每頁筆數的值
/// </summary>
private int pageSize;
/// <summary>
/// 取得或設定每頁筆數。最小值是15。
/// </summary>
/// <value>
/// 每頁筆數
/// </value>
public virtual int PageSize
{
get
{
if (this.pageSize < 1)
{
this.pageSize = 15;
}
return this.pageSize;
}
set { this.pageSize = value; }
}
/// <summary>
/// 欄位排序的值
/// </summary>
protected string orderByColumnName;
/// <summary>
/// 取得或設定要依照那個欄位做排序。
/// </summary>
/// <value>
/// 依照那個欄位做排序.
/// </value>
public abstract string OrderByColumnName { get; set; }
/// <summary>
/// 取得或設定排序的方向。
/// </summary>
/// <value>
/// <c>true</c> 表示用 ascending排序; otherwise, <c>false</c>.
/// </value>
public bool IsAscending { get; set; }
}
這個ViewModel實作的Interface就不看了,基本上就是這些Property的定義。
這邊有個地方可以注意到就是排序的欄位。因為我們這個SearchFormViewModelBase
沒有形態的概念,而通常來說搜索條件會和某一個DB的Table對應。因此,為了方便之後框架幫忙做搜索,這邊又定義一個有強型別的SearchFormViewModelBase
:
/// <summary>
/// 搜索 Form 的 ViewModel base。有帶上形態,以第一個欄位做排序
/// </summary>
/// <typeparam name="T">Entity Framework裡面Table Entity</typeparam>
public abstract class SearchFormViewModelBase<T> : SearchFormViewModelBase
{
/// <summary>
/// 取得或設定要依照那個欄位做排序。
/// </summary>
/// <value>
/// 依照那個欄位做排序.
/// </value>
public override string OrderByColumnName
{
get
{
if (string.IsNullOrEmpty(this.orderByColumnName))
{
this.orderByColumnName = typeof(T).GetProperties().First().Name;
}
return this.orderByColumnName;
}
set
{
this.orderByColumnName = value;
}
}
}
可以注意到這個Class的定義是
Abstract
,表示之後的class應該要依照自己的Domain去做繼承,例如如果今天是Post的搜索ViewModel,希望有一個 “標題”的搜索欄位,和排序要以“建立時間”欄位,那麼ViewModel就會是: public class SearchFormViewModel : SearchFormViewModelBase<Post>
{
[DisplayName("標題")]
public string Title { get; set; }
public override string OrderByColumnName
{
get
{
return "CreateDateTime";
}
}
}
搜索結果
這個部份就比較簡單,就是某一個和Detail頁面一樣ViewModel不過是被一個IPagedList
包住。因此他不會像搜索ViewModel一樣有個base而是直接看定義的 ViewModel然後以泛型的方式傳入。
PagedList.Mvc - 好用的分頁套件
- Nuget安裝指令:Install-Package PagedList.Mvc
- 套件Github首頁:https://github.com/TroyGoode/PagedList
- 如果完全沒有用過,可以參考:
搜索ViewModel的主檔
有了這兩個Property的ViewModel之後,就可以建立搜索的ViewModel的Base:
/// <summary>
/// 搜索頁面的ViewModel需要繼承這一個Base。
/// 方便處理Paging和搜索條件相關。
/// 這個方法就兩個Property,用作於表示搜索的form和搜索結果的result。
/// </summary>
/// <typeparam name="TSearchForm">搜索的form ViewModel type。
/// 必須是繼承<see cref="MvcInfrastructure.Common.Base.SearchFormViewModelBase"/>
/// </typeparam>
/// <typeparam name="TPageResult">搜索的結果ViewModel type</typeparam>
public class SearchViewModelBase<TSearchForm, TPageResult> :
ISearchViewModelBase<TSearchForm, TPageResult>
where TSearchForm : Core.Common.Base.ISearchFormViewModelBase, new()
{
private TSearchForm searchForm;
/// <summary>
/// 取得或設定搜索的Form。如果是null,會實例一個。
/// </summary>
/// <value>
/// 搜索的Form
/// </value>
public TSearchForm SearchForm
{
get
{
if (this.searchForm == null)
{
this.searchForm = new TSearchForm();
}
return this.searchForm;
}
set { this.searchForm = value; }
}
/// <summary>
/// 取得或設定搜索結果的ViewModel。
/// </summary>
/// <value>
/// 搜索結果的ViewModel。用<see cref="PagedList.IPagedList"/>包住,方便做分頁
/// </value>
public IPagedList<TPageResult> Result { get; set; }
}
Post的搜索ViewModel
定義好了搜索的BaseViewModel之後,假設今天是Post
頁面要做搜索的ViewModel,就可能會像是:
public class Index : SearchViewModelBase<SearchFormViewModel, SearchResult>
{
}
public class SearchResult : IMapFrom<Post>
{
public int Id { get; set; }
[DisplayName("標題")]
public string Title { get; set; }
[DisplayName("內文")]
public string PostContent { get; set; }
}
public class SearchFormViewModel : SearchFormViewModelBase<Post>
{
[DisplayName("標題")]
public string Title { get; set; }
public override string OrderByColumnName
{
get
{
return "CreateDateTime";
}
}
}
結語
有了搜索的ViewModel之後,在下一篇將會介紹框架的Service怎麼能夠做修改並且讓搜索處理邏輯變的簡單。