C# 表达式按关键字段对通用查询进行排序

我有一个通用方法,我想在其中IQueryable<T>按其关键字段对 an 进行排序(可以安全地假设只有一个)。因此:


void DoStuff<T>(...) 

{

   IQueryable<T> queryable = ... // given

   PropertyInfo keyField = ... // given

   var sortedQueryable = queryable.OrderBy(<some expression here>);

   ...

}

如何定义一个Expression将返回的keyField属性,T以便它可以工作?


慕村225694
浏览 138回答 3
3回答

慕桂英546537

这并不太难,但是您需要调用OrderBywith reflection,因为您事先不知道关键字段的类型。因此,鉴于您已经显示的代码,您将执行以下操作:// Build up the property expression to pass into the OrderBy methodvar parameterExp = Expression.Parameter(typeof(T), "x");var propertyExp = Expression.Property(parameterExp, keyField);var orderByExp = Expression.Lambda(propertyExp, parameterExp);// Note here you can output "orderByExp.ToString()" which will give you this://&nbsp; x => x.NameOfProperty// Now call the OrderBy via reflection, you can decide here if you want&nbsp;// "OrderBy" or "OrderByDescending"var orderByMethodGeneric = typeof(Queryable)&nbsp; &nbsp; .GetMethods()&nbsp; &nbsp; .Single(mi => mi.Name == "OrderBy" && mi.GetParameters().Length == 2);var orderByMethod = orderByMethodGeneric.MakeGenericMethod(typeof(T), propertyExp.Type);// Get the resultvar sortedQueryable = (IQueryable<T>)orderByMethod&nbsp; &nbsp; .Invoke(null, new object[] { queryable, orderByExp });

拉丁的传说

与 DavidG 答案中的想法相同,但方法不同// build lambda expression (T t) => t.KeyFieldvar type = typeof(T);var parameter = Expression.Parameter(type, "k");var lambda = Expression.Lambda(Expression.Property(parameter, keyField), parameter);// get source expressionvar baseExpression = queryable.Expression;// call to OrderByvar orderByCall = Expression.Call(&nbsp; &nbsp; typeof(Queryable),&nbsp; &nbsp; "OrderBy",&nbsp; &nbsp; new[] {type, keyField.PropertyType},&nbsp; &nbsp; baseExpression, lambda);// sorted resultvar sorted = queryable.Provider.CreateQuery<T>(orderByCall);

潇湘沐

我喜欢使用具有 T 类型 Id 属性的接口 IBaseEntity。这将使您的查询:void DoStuff<IBaseEntity>(...)&nbsp;{&nbsp; &nbsp;IQueryable<IBaseEntity> queryable = ... // given&nbsp; &nbsp;var sortedQueryable = queryable.OrderById(e=> e.Id); //extension method&nbsp; &nbsp;...}扩展方法:public static IQueryable<IBaseEntity<T>> OrderById<T>(this IQueryable<IBaseEntity<T>> query){&nbsp; &nbsp;return query.OrderBy(e => e.Id);}每个实体都会实现 IBaseEntity 并具有类似的东西public partial class MyEntity : IBaseEntity<long>{&nbsp; [Required]&nbsp; public override long&nbsp; Id&nbsp;&nbsp; {&nbsp; &nbsp; get { return base.Id;}&nbsp; &nbsp; set { base.Id = value;}&nbsp; }}然后在上下文中modelBuilder&nbsp; .Entity<MyEntity>()&nbsp; .ToTable("DatabaseTable", "DatabaseSchema")&nbsp; .HasKey(e => e.Id)&nbsp; .Property(e => e.Id)&nbsp; .HasColumnName("DatabasePrimaryKey")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);注意:这需要在上下文和实体中进行一些设置。数据库可以具有您想要的任何键,您可以将它们单独映射到上下文的 OnModelCreating 方法中的属性 Id。
打开App,查看更多内容
随时随地看视频慕课网APP