我正在尝试添加ThenById()
方法,该方法将在调用OrderBy()
上的IOrderedQueryable
之后启动:
public static IOrderedQueryable<TEntity> ThenById<TEntity>(this IQueryable<TEntity> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var command = "ThenBy";
var thenByProperty = "Id";
var type = typeof(TEntity);
if (type.GetProperty(thenByProperty) == null)
{
throw new MissingFieldException(nameof(thenByProperty));
}
var param = Expression.Parameter(type, "p");
var property = type.GetProperty(thenByProperty, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var propertyAccess = Expression.MakeMemberAccess(param, property);
var orderByExpression = Expression.Lambda(propertyAccess, param);
var resultExpression = Expression.Call(
typeof(IOrderedQueryable),
command,
new Type[] { type, property.PropertyType },
source.Expression,
Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}
我收到以下错误消息:
类型为'System.Linq.IOrderedQueryable'的通用方法'ThenBy'与提供的类型实参和实参不兼容。如果该方法是非泛型的,则不应该提供任何类型的参数。
答案 0 :(得分:3)
ThenBy
扩展方法在System.Linq.Queryable
类中,而不在IOrderedQueryable
中。您只需要在代码中替换它即可:
public static IOrderedQueryable<TEntity> ThenById<TEntity>(
this IOrderedQueryable<TEntity> source)
{
//snip
var resultExpression = Expression.Call(
typeof(System.Linq.Queryable),
command,
new Type[] { type, property.PropertyType },
source.Expression,
Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}
请注意,该方法应扩展IOrderedQueryable
,而不仅仅是IQueryable
。
但是,如果TEntity
没有Id
属性,则此操作将在运行时失败。我的偏好是为所有具有Id
属性的实体提供接口,并在此处使用一般约束。这样,您可以完全避免使用表达式,并获得编译时的安全性。例如:
public interface IHasId
{
int Id { get; set; }
}
public class SomeEntity : IHasId
{
public int Id { get; set; }
public string Name { get; set; }
//etc
}
这简化了您的扩展方法:
public static IOrderedQueryable<TEntity> ThenById<TEntity>(
this IOrderedQueryable<TEntity> source)
where TEntity : IHasId
{
return source.ThenBy(e => e.Id);
}