Estoy tratando de crear una clase rápida para que pueda hacer que el código de ordenación de escritura para una grilla sea mucho más fácil de trabajar y mantener, y para mantener baja la repetición de código. Para ello se me ocurrió con la clase siguiente:¿Cómo puedo almacenar dinámicamente expresiones usadas para orden de Linq?
public class SortConfig<TSource, TRelatedObject> where TSource : class where TRelatedObject : class
{
public IList<SortOption> Options { get; protected set; }
public SortOption DefaultOption { get; set; }
public SortConfig()
{
Options = new List<SortOption>();
}
public void Add(string name, Expression<Func<TSource, object>> sortExpression, TRelatedObject relatedObject, bool isDefault = false)
{
var option = new SortOption
{
FriendlyName = name,
SortExpression = sortExpression,
RelatedObject = relatedObject
};
Options.Add(option);
if (isDefault)
DefaultOption = option;
}
public SortOption GetSortOption(string sortName)
{
if (sortName.EndsWith("asc", StringComparison.OrdinalIgnoreCase))
sortName = sortName.Substring(0, sortName.LastIndexOf("asc", StringComparison.OrdinalIgnoreCase));
else if (sortName.EndsWith("desc", StringComparison.OrdinalIgnoreCase))
sortName = sortName.Substring(0, sortName.LastIndexOf("desc", StringComparison.OrdinalIgnoreCase));
sortName = sortName.Trim();
var option = Options.Where(x => x.FriendlyName.Trim().Equals(sortName, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
if (option == null)
{
if (DefaultOption == null)
throw new InvalidOperationException(
string.Format("No configuration found for sort type of '{0}', and no default sort configuration exists", sortName));
option = DefaultOption;
}
return option;
}
public class SortOption
{
public string FriendlyName { get; set; }
public Expression<Func<TSource, object>> SortExpression { get; set; }
public TRelatedObject RelatedObject { get; set; }
}
}
La idea es que se crea una configuración rápida de las diferentes opciones de clasificación, lo que orderBy expresión se utiliza para eso, y opcionalmente un objeto que está relacionada con la opción de clasificación Esto permite que el código para que parezca:
protected void InitSortConfig()
{
_sortConfig = new SortConfig<xosPodOptimizedSearch, HtmlAnchor>();
_sortConfig.Add("name", (x => x.LastName), lnkSortName, true);
_sortConfig.Add("team", (x => x.SchoolName), lnkSortTeam);
_sortConfig.Add("rate", (x => x.XosRating), lnkSortRate);
_sortConfig.Add("pos", (x => x.ProjectedPositions), null);
_sortConfig.Add("height", (x => x.Height), lnkSortHeight);
_sortConfig.Add("weight", (x => x.Weight), lnkSortWeight);
_sortConfig.Add("city", (x => x.SchoolCity), lnkSortCity);
_sortConfig.Add("state", (x => x.SchoolState), lnkSortState);
}
y luego me puede ordenar con sólo hacer
// Get desired sorting configuration
InitSortConfig();
var sortOption = _sortConfig.GetSortOption(sort);
bool isDescendingSort = sort.EndsWith("desc", StringComparison.OrdinalIgnoreCase);
// Setup columns
InitSortLinks();
if (sortOption.RelatedObject != null)
{
// Make modifications to html anchor
}
// Form query
var query = PodDataContext.xosPodOptimizedSearches.AsQueryable();
if (isDescendingSort)
query = query.OrderByDescending(sortOption.SortExpression);
else
query = query.OrderBy(sortOption.SortExpression);
Esto funciona muy bien cuando la variable ordenada es una cadena, pero cuando no es una cadena consigo la siguiente excepción: Cannot order by type 'System.Object'.
Supongo que esto se debe a que estoy almacenando la expresión como Expression<Func<TSource, object>>
y no siendo más específico acerca de ese segundo genérico. No entiendo cómo puedo mantener todas mis opciones de clasificación diferentes (incluso para propiedades que no sean cadenas) en una clase.
Creo que uno de los problemas es que la cláusula Linq.OrderBy()
toma Expression<Func<TSource, TKey>>
ya que es el parámetro, pero no estoy envolviendo la cabeza en torno a cómo Linq.OrderBy()
es capaz de inferir lo TKey
debería ser, y por lo tanto no puede entender cómo tomar ventaja de esa inferencia para almacenar estas expresiones con el TKey
apropiado.
¿Alguna idea?
Tome un vistazo a [esta] (http://weblogs.asp.net/scottgu/archive/2008/01 /07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx) – Nestor
Gracias, pero prefiero que la clasificación esté especificada por el código en lugar de la cadena especificada, especialmente porque la estructura de datos de mi grid no es un modelo de datos 1: 1 con mi base de datos, por lo que la ordenación debe traducirse de la grilla especificada a una ordenación de base de datos de todos modos – KallDrexx
¿No está usando una cadena mágica cuando obtiene la opción de ordenar de todos modos? –