我需要按字符串对查询进行排序,找到效果很好的this。问题是它无法处理复杂属性相关实体,例如“ComplexProperty.Property”“RelatedEntity.Property”,因为它只搜索主类。
我想我应该能够通过a解析部分[0]。并以某种方式递归检查每种类型,但我无法弄清楚如何。这可能还是我走到了尽头?
这样做的原因是我有一个带有webgrid的“旧”解决方案(MVC 3),而webgrid需要所有数据来进行排序(这是一个脱机的EF4解决方案)而且只需要很长时间。我需要将排序传递给查询,并仅在分页中检索该页面的帖子。 webgrid使用sort和sortdir参数调用相同的控制器,并使用ajax进行更新。
如果不可能,也许还有另一种解决方案,我应该看看,任何人都可以提示一下吗?
编辑并澄清 今天,解决方案获取所有违规,将它们发送到webGrid并让webgrid进行分页和排序。该解决方案已经存在多年,并且违规表已经发展到页面非常慢的程度,这主要是因为每次都会获取所有数据。我已经实现了对存储库的分页,只接收了一部分类。今天的存储库与IEnumerable以及表示和存储库之间的ServiceLayer(业务)一起使用,总是将List返回到表示层。
这是我希望能够使用的SQL
SELECT vi.ViolationId, ar.AreaName
FROM [Violation] vi
join [ControlPoint] cp on vi.ControlPointId = cp.ControlPointId
join [Area] ar on ar.AreaId = cp.AreaId
order by ar.AreaName
我需要使用orderBy(string sortExpression)这样做。
violations.OrderBy("ControlPoint.Area.AreaName")
并发现此功能(上面已链接)作为此基础。
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, string sortExpression)
{
sortExpression += "";
string[] parts = sortExpression.Split(' ');
bool descending = false;
string property = "";
if (parts.Length > 0 && parts[0] != "")
{
property = parts[0];
if (parts.Length > 1)
{
descending = parts[1].ToLower().Contains("esc");
}
PropertyInfo prop = typeof(T).GetProperty(property);
// handle Prop.SubProp
// prop.GetType().GetProperty
if (prop == null)
{
throw new Exception("No property '" + property + "' in + " + typeof(T).Name + "'");
}
if (descending)
return list.OrderByDescending(x => prop.GetValue(x, null));
else
return list.OrderBy(x => prop.GetValue(x, null));
}
return list;
}
答案 0 :(得分:0)
好的,现在它正在工作,我发布了我的最终结果。感谢所有的意见,如果没有所有评论,我会认为这是不可行的
首先是所有辅助方法
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string property, bool descending)
{
if(!descending)
return ApplyOrder<T>(source, property, "OrderBy");
else
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenBy");
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenByDescending");
}
static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
object result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda });
return (IOrderedQueryable<T>)result;
}
public static bool TryParseSortText(this string sortExpression, out string property, out bool descending)
{
descending = false;
property = string.Empty;
if (string.IsNullOrEmpty(sortExpression))
return false;
string[] parts = sortExpression.Split(' ');
if (parts.Length > 0 && !string.IsNullOrEmpty(parts[0]))
{
property = parts[0];
if (parts.Length > 1)
{
descending = parts[1].ToLower().Contains("esc");
}
}
else
return false;
return true;
}
然后在服务层我有这个
public PagedResult<Violation> GetViolationByModule(PagedRequest pagedRequest, long moduleId, long stakeHolderId, Expression<Func<Violation, bool>> filter, string sort = "")
{
return ExceptionManager.Process(() => _GetViolationByModule(pagedRequest, moduleId, stakeHolderId, filter, sort),
"ServicePolicy");
}
private PagedResult<Violation> _GetViolationByModule(PagedRequest pagedRequest, long moduleId, long stakeHolderId, Expression<Func<Violation, bool>> filter, string sort = "")
{
var query = ViolationRepository.GetViolationByModule(moduleId, stakeHolderId);
if(!string.IsNullOrEmpty(sort))
{
string sortProperty = string.Empty;
bool desc = false;
if(sort.TryParseSortText(out sortProperty, out desc))
{
query = query.OrderBy(sortProperty, desc);
}
}
if (filter != null)
{
query = query.Where(filter);
}
var violations = _GetPagedResult(pagedRequest, query);
foreach (var violation in violations.Results)
{
var user = FrontendUserRepository.GetFrontendUserByName(violation.ReportBy);
if (user != null)
{
violation.ReportUserInitial = user.Initial;
}
else
{
violation.ReportUserInitial = violation.ReportBy;
}
}
return violations;
}
从控制器我可以通过
来调用它 var pagedUnamendedViolationList = ViolationService.GetViolationByModule(new PagedRequest() { Page = page, PageSize = pageSize },
moduleId,
stakeholderId,
v => (fUser == null || v.ControlPoint.Area.FronendUsers.Contains(fUser)) && !v.IsAmended,
"ControlPoint.Area.AreaName DESC"
);