我正在开发一个CRM类型的应用程序,我正在实现的一个功能是能够查看数据网格,然后使用单个文本框来过滤任何列中的值。我想出了一个非常难看的解决方案(请注意,此方法也使用Dynamic Linq对数据进行排序),但是我希望它更“通用”,可能使用反射,所以我可以调用WithFiltering扩展方法和提供扩展方法的过滤条件。这就是我到目前为止所做的:
public List<PersonModel> GetPeople(int owningOrganisationID, int skip, int records, out int totalCount, Ordering orderByDirection, string filter, string orderBy = "")
{
if (string.IsNullOrEmpty(orderBy))
orderBy = "PersonID";
if (!string.IsNullOrEmpty(filter))
{
filter = filter.ToLower();
totalCount = Context.PeopleView.Where(p => p.OwningOrganisationID == owningOrganisationID &&
p.City.ToLower().Contains(filter)
|| p.CountryName.ToLower().Contains(filter)
|| p.Forename.ToLower().Contains(filter)
|| p.PersonTypeName.ToLower().Contains(filter)
|| p.Postcode.ToLower().Contains(filter)
|| p.Surname.ToLower().Contains(filter)).Count();
return Context.PeopleView.Where(p => p.OwningOrganisationID == owningOrganisationID &&
p.City.ToLower().Contains(filter)
|| p.CountryName.ToLower().Contains(filter)
|| p.Forename.ToLower().Contains(filter)
|| p.PersonTypeName.ToLower().Contains(filter)
|| p.Postcode.ToLower().Contains(filter)
|| p.Surname.ToLower().Contains(filter))
.OrderBy(orderBy + " " + orderByDirection.ToString())
.Skip(skip)
.Take(records)
.ToList();
}
else
{
totalCount = Context.PeopleView.Where(p => p.OwningOrganisationID == owningOrganisationID).Count();
return Context.PeopleView
.Where(o => o.OwningOrganisationID == owningOrganisationID)
.OrderBy(orderBy + " " + orderByDirection.ToString())
.Skip(skip)
.Take(records)
.ToList();
}
}
这不仅看起来很糟糕,而且容易出错,我会在几个不同的实体上使用相同类型的代码(PersonModel,OrganizationModel,DocumentModel等......)
只是想知道是否有人对清洁代码有更好的想法?
答案 0 :(得分:0)
使用更正确的问题解决方案更新
不使用反射,您可以使用以下模式:
IFilterable
方法FilterClause(string filter)
类
IFilterable
,PersonModel
等)上实施OrganizationModel
课程。)IFilterable
个对象编写扩展名因此,基本上对于要应用相同过滤的每个实体,您可以实现IFilterable
并定义 属性和 这些属性将用于哪些过滤
以下是一些说明上述概念的代码。首先,定义IFilterable
并在您的实体类(PersonModel
,OrganizationModel
等)上实现它。)
/// <summary>
/// Specifies that the class can be filterable
/// </summary>
interface IFilterable {
/// <summary>
/// Specifies the way the filtering will occur
/// </summary>
/// <param name="filter"></param>
/// <returns></returns>
bool FilterClause(string filter);
}
//partial class definition for PersonModel
public partial class PersonModel: IFilterable{
//entity properties (normaly these are generated by EF)
public int Id { get; set; }
public int OwningOrganisationID { get; set; }
public string City { get; set; }
public string CountryName { get; set; }
public string Forename { get; set; }
public string PersonTypeName { get; set; }
public string Postcode { get; set; }
public string Surname { get; set; }
//Implementation of IFiltrable
public bool FilterClause(string filter) {
return City.ToLower().Contains(filter)
|| CountryName.ToLower().Contains(filter)
|| Forename.ToLower().Contains(filter)
|| PersonTypeName.ToLower().Contains(filter)
|| Postcode.ToLower().Contains(filter)
|| Surname.ToLower().Contains(filter);
}
}
//partial class definition for OrganizationModel
public partial class OrganizationModel: IFilterable{
//Implementation of IFiltrable
public bool FilterClause(string filter) {
//replace 'true' with code that will apply filtering for the OrganizationModel class
return true;
}
}
现在在IQueryable
对象上定义一个扩展,该扩展将对实现'IFilterable'的对象应用过滤
static class FilterableEntensions{
/// <summary>
/// Filters a IFilterable enumeration
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
/// <param name="filter"></param>
/// <returns></returns>
public static IQueryable<T> WithFiltering<T>(this IQueryable<T> query, string filter) where T: IFilterable {
if (string.IsNullOrWhiteSpace(filter)) {
//filter is empty, return original query
return query;
}
else {
//apply the filter
return query.Where(x => x.FilterClause(filter));
}
}
}
通过上述定义,您的GetPeople
方法可以重写(见下文)。它还首先查询id仅设置totalCount
值,并且仅查询最终查询的分页ID
public List<PersonModel> GetPeople(int owningOrganisationID, int skip, int records, out int totalCount, Ordering orderByDirection, string filter, string orderBy = "") {
List<PersonModel> result = new List<PersonModel>();
if (string.IsNullOrEmpty(orderBy)) {
orderBy = "PersonID";
}
if (!string.IsNullOrWhiteSpace(filter)) {
filter = filter.ToLower();
}
//use a first query to take only the ids of the data that match the filter.
List<int> peopleViewIds = Context.PeopleView
.Where(p => p.OwningOrganisationID == owningOrganisationID)
.WithFiltering(filter) //use our extension here!!!
.OrderBy(orderBy + " " + orderByDirection.ToString())
.Select(p => p.Id).ToList();
//set the 'out' parameter to the total count of the retrieved ids
totalCount = peopleViewIds.Count;
if (totalCount > 0) {
//page the ids accordingly (the sorting of the ids was applied in the previous query)
List<int> pagedPeopleViewIds = peopleViewIds.Skip(skip).Take(records).ToList();
//use the paged ids to make a second query, this time only with the required ids.
//This should be really fast if you have PersonModel.Id is a PRIMARY KEY or you have an index attached on this column
//Please note the reuse of the OrderBy, this will ensure the correct order on the paged result
result = Context.PeopleView.Where(p => pagedPeopleViewIds.Contains(p.Id))
.OrderBy(orderBy + " " + orderByDirection.ToString())
.ToList();
}
return result;
}