I have not written to this blog in a while. But I will try to more often.
I was looking for a way in Linq to bring certain records in focus by being first in the sort. After Looking around and see this post. I came up with the following.
public static class linqExtentions
{
public static IEnumerable SpecificRecordFirst(this IQueryable query, string PropertyToTest,object PropertyValue)
{
Type propertyType = query.GetType().GetGenericArguments()[0];
PropertyInfo property = propertyType.GetProperty(PropertyToTest, BindingFlags.Instance | BindingFlags.Public);
MethodInfo whereMethod = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => m.Name == "Where").ToArray()[0].MakeGenericMethod(propertyType);
ParameterExpression parameter = Expression.Parameter(propertyType,"m");
MemberExpression member = Expression.MakeMemberAccess(parameter,propertyType.GetProperty(PropertyToTest));
BinaryExpression equal = ParameterExpression.Equal
(
member,
(PropertyValue != null) ? Expression.Constant(PropertyValue, PropertyValue.GetType()) : null
);
LambdaExpression lambda = Expression.Lambda(typeof(Func<,>).MakeGenericType(propertyType, typeof(Boolean)), equal, member.Expression as ParameterExpression);
IQueryable query2 = whereMethod.Invoke(null, new Object[] { query, lambda }) as IQueryable;
if (query2.Count() < 1) throw new Exception("SpecificRecordFirst- First Record Doesnt Exist");
if (query2.Count() > 1)
throw new Exception("SpecificRecordFirst- First Record is not unique");
yield return query2.First();
BinaryExpression Notequal = ParameterExpression.NotEqual
(
member,
(PropertyValue != null) ? Expression.Constant(PropertyValue, PropertyValue.GetType()) : null
);
LambdaExpression lambda2 = Expression.Lambda(typeof(Func<,>)
.MakeGenericType(propertyType, typeof(Boolean)), Notequal, member.Expression as ParameterExpression);
IQueryable query3 = whereMethod.Invoke(null, new Object[] { query, lambda2 }) as IQueryable;
foreach (var elem in query3)
{
yield return elem;
}
}
}
I wrote this 6 in the morning. I am wondering If this could be done differently.
EDIT
I thought about this a little more . Here
public static IEnumerable SpecificRecordsFirst(this IQueryable query, Expression<Func> expression)
{
Func func = expression.Compile();
var firstRecords = query.Where(func.Invoke);
foreach (var firstRecord in firstRecords)
{
yield return firstRecord;
}
var secondRecords = query.Except(firstRecords.AsEnumerable());
foreach (var secondRecord in secondRecords)
{
yield return secondRecord;
}
}
Much better IMHO
Posted by joemele