- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们正在使用 Entity Framework 和“POCO”生成器来创建我们的类型,这些类型会传递到各个层并且它们属于(已更改以保护无辜者)命名空间 Company.Application.Project.Module。这些 POCO 对象都继承自一个为我们处理一些基本内容的基类。
我想编写一个函数,可以获取这些对象的集合并按属性名称对它们进行排序。
我已经编写了以下函数——它完成了我想做的事情的要点,但我不喜欢它有几个原因:
1) 这不适用于任何对象类型,它必须是 SortHelper 类知道的对象类型(因此是最后一个 using 语句)。
2) “POCO”对象的 Type 和 BaseType 似乎不一致——这取决于您在应用程序中调用此函数的位置(单元测试项目与从我们的 MVP 应用程序的演示对象调用),这会导致问题使用我加粗的行,因为如果它抓取了错误的类型,属性将不会出现在下面的行中。
在演示者对象中,.GetType 显示为:类名_96D74E07A154AE7BDD32624F3B5D38E7F50333608A89B561218F854513E3B746...在 System.Data.Entity.DynamicProxies 命名空间内。
这就是代码在该行显示 .GetType().BaseType 的原因,它给出了我:类(class)名称...在 Company.Application.Project.Module 中
但是在单元测试中,.GetType() 显示为Company.Application.Project.Module 中的类名
并且 BaseType 显示为Company.Application.Project.Module 中的基类
...这更有意义,但我不理解这种不一致——这种不一致让我害怕。
3) 通常讨厌使用反射来做这件事。
如果有人有更好的方法来做到这一点,或者甚至是使反射与 namespace /类型一起工作的修复程序——我当然会很感激!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Company.Application.Project.Module;
namespace Company.Application.Project
{
public static class SortHelper
{
public static IOrderedQueryable<T> Sort<T>(this IQueryable<T> source, string propertyName, bool descending)
{
// bail out if there's nothing in the list
if (source == null)
{
return null;
}
if (source.Count() == 0)
{
return source as IOrderedQueryable<T>;
}
// get the type -- or should it be the BaseType? Nobody knows!
Type sourceType = source.First().GetType().BaseType;
// this works fine _assuming_ we got the correct type on the line above
PropertyInfo property = sourceType.GetProperty(propertyName);
if (descending)
{
return source.OrderByDescending(e => property.GetValue(e, null));
}
else
{
return source.OrderBy(e => property.GetValue(e, null));
}
}
}
}
最佳答案
在我看来,根本没有充分的理由这样做。您正在使用 OrderBy
你的函数中的扩展方法,为什么不调用它而不是这个函数呢?除非您的示例中没有显示某些内容,否则该函数除了弄清楚如何调用 OrderBy
之外什么都不做。 (或 OrderByDescending
)然后调用它。
如果只是想使用 bool 标志在升序和降序之间切换(不必在每个要排序的地方都使用 if 语句),那么我强烈建议采用以下方法:
public static IOrderedQueryable<TSource> Sort<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, bool descending = false)
{
if (descending) return source.OrderByDescending(keySelector);
else return source.OrderBy(keySelector);
}
它整洁干净,您仍然可以使用 lambda 表达式来定义键,而无需依赖于您的模型,您可以(可选地)使用 bool 标志将排序顺序更改为降序,并且没有反射.这是双赢! ;)
[开始编辑以回应评论]
好的,现在我已经再次运行 VS2010,我能够找到一种方法来封装排序 ASP.NET GridView 控件时使用的 SortExpression,正如所 promise 的那样。所以就在这里。
由于我们没有为这个问题定义模型,所以我将创建一个简单的模型。
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
public virtual List<Order> Orders { get; set; }
}
public class Order
{
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public decimal TotalPurchaseAmount { get; set; }
public string Comments { get; set; }
public bool Shipped { get; set; }
public virtual Customer Customer { get; set; }
}
那么让我们假设我们有一个 CustomerDetails.aspx 页面,我们想向该页面添加一个 GridView 以列出订单。
<asp:GridView ID="gvOrders" AutoGenerateColumns="false" runat="server"
AllowSorting="true" OnSorting="gvOrders_Sorting">
<Columns>
<asp:BoundField DataField="OrderID" SortExpression="OrderID" HeaderText="Order ID" />
<asp:BoundField DataField="OrderDate" SortExpression="OrderDate" HeaderText="Order Date" />
<asp:BoundField DataField="TotalPurchaseAmount" SortExpression="TotalPurchaseAmount" HeaderText="Total Purchase Amount" />
<asp:BoundField DataField="Comments" SortExpression="Comments" HeaderText="Comments" />
<asp:BoundField DataField="Shipped" SortExpression="Shipped" HeaderText="Shipped" />
</Columns>
</asp:GridView>
在后面的代码中,有一个静态字典对象:
protected static readonly Dictionary<string, Expression<Func<Order, object>>> sortKeys = new Dictionary<string,Expression<Func<Order,object>>>()
{
{ "OrderID", x => x.OrderID },
{ "OrderDate", x => x.OrderDate },
{ "TotalPurchaseAmount", x => x.TotalPurchaseAmount },
{ "Comments", x => x.Comments },
{ "Shipped", x => x.Shipped }
};
然后是处理排序的函数:
protected void gvOrders_Sorting(object sender, GridViewSortEventArgs e)
{
string exp = ViewState["gvOrders_SortExp"] as string;
if (exp == null || exp != e.SortExpression)
{
e.SortDirection = SortDirection.Ascending;
ViewState["gvOrders_SortExp"] = e.SortExpression;
ViewState["gvOrders_SortDir"] = "asc";
}
else
{
string dir = ViewState["gvOrders_SortDir"] as string;
if (dir == null || dir == "desc")
{
e.SortDirection = SortDirection.Ascending;
ViewState["gvOrders_SortDir"] = "asc";
}
else
{
e.SortDirection = SortDirection.Descending;
ViewState["gvOrders_SortDir"] = "desc";
}
}
if (e.SortDirection == SortDirection.Ascending)
// There's a MyCustomer property on the page, which is used to get to the Orders
{ gvOrders.DataSource = MyCustomer.Orders.OrderBy(sortKeys[e.SortExpression]); }
else
{ gvOrders.DataSource = MyCustomer.Orders.OrderByDescending(sortKeys[e.SortExpression]); }
gvOrders.DataBind();
}
就是这样。
我承认 gvOrders_Sorting
方法真的很困惑,但这就是使用 GridView
进行自定义排序的本质.它可以进一步封装,但我决定保持简单。 (我实际上开始着手创建一个可以处理排序和分页的帮助程序类,但是 .NET 4.0 中的自定义分页比自定义排序更糟糕!)
希望你喜欢。 ;)
[更正]
我刚刚注意到编写的代码存在问题。 MyCustomer.Orders
将是 List<Order>
不是IQueryable<Order>
.所以要么改变 sortKeys
成为Dictionary<string, Func<Order, object>>
,或将调用更改为 MyCustomer.Orders.AsQueryable().OrderBy(sortKeys[e.SortExpression])
或 MyDbContext.Orders.Where(o => o.Customer == MyCustomer).OrderBy(sortKeys[e.SortExpression])
.我把选择权留给你。 ;)
关于c# - 完成 IQueryable 通用列表排序的更好方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17578974/
var page = pagesRepository.GetPages(); var categoryPages = page.ChildCategoryPages; var articlePages
是否可以将 IQueryable 对象转换为 IQueryable,其中 T 是映射实体? (T 将是 POCO 类)。 提前致谢。 最佳答案 就 Cast() 它。假设它是相同类型的可查询。否则你可
我只是想知道为什么会有一个 IQueryable没有通用功能的版本? 最佳答案 The generic IQueryable is the one you use most often in meth
我有一个 IQueryable它是根据一些输入参数(排序和过滤器)创建的。 可以应用这个 IQueryable到 DbSet我有DbContext ? 例如: // create the query
我们正在尝试转换 IQueryable 的实例到 IQueryable , SpecificEntityObject类型仅在运行时已知。 我们已尝试使用下面的代码,该代码无法编译,因为类型或命名空间
最近几天我在互联网上搜索了解决方案,但没有找到我想要的。基本上,这是我的问题: 我有一个需要实现的接口(interface),它有一个返回 IQueryable 的方法(我无权访问该接口(interf
与IEnumerable相同对比IEnumerable .这是疏忽吗?或者当您没有指定类型来实现像 .Count() 这样的扩展时,是否存在问题? , .Where()等不可能? 最佳答案 来自doc
这是 Automapper 专业人员的问题。我已经尝试做查询映射好几天了——但没有成功。似乎 Automapper 不打算按照我想要的方式使用它。但也许我错了。那么问题来了…… 我有这样的类(clas
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭去年。 Improve th
我有一个类Something实现 ISomething .如何从 IQueryable 转换/转换到 IQueryable .当我尝试转换时,我能够编译,但转换的结果始终为 NULL。 背景:我这样做
我了解协方差,并且我知道一般来说在 v4.0 之前它在 C# 中是不可能的。 但是我想知道一个具体案例。有什么方法可以进行转换IQueryable至IQueryable通过以某种方式创建一个包装类,该
如果IQueryable接口(interface)在服务器中执行查询表达式,而不是像 IEnumerable 那样获取所有记录,为什么是IQueryable未被 IEnumerable 取代哪里可以更
这个问题在这里已经有了答案: Why covariance and contravariance do not support value type (4 个答案) 关闭 7 年前。 为什么编译器不
我想做这样的事情 public IQueryable GetPaged(IQueryable query, int startIndex, int pageSize) {
我正在开发一个使用新 Web API 的项目,我注意到有人从 Get 方法返回了一个 IQueryable。 我的理解是 IQueryable 可用于提高性能(延迟执行),但我认为 HTTP 连接另一
我正在重构我的 EF 存储库类以使其可测试,遵循这篇优秀博客文章中的建议: https://blog.iannelson.uk/testing-linq-queries/ 一切都很好,我也能够像在博客
我有一个包含 IQueryable 的通用函数其中每一行都包含一个具有一组属性的类的实例。 我有另一个类 (MyClass),它具有与上面的类 T 相同的一些属性...即相同的名称和数据类型。 我还有
我正在尝试使用 Automapper 将 IQueryable 映射到 IQueryable 以生成 Linq。我正在开发一个带有 Entity Framework 和 oracle 11g 的 We
我有一个对象是: IQueryable 我想将它传递给一个函数,该函数需要: IQueryable Foo 确实实现了 IFoo 为什么不能编译?什么是最好的转换方式来让这项工作发挥作用? 最佳答案
我有一个查询可以获取一些过滤后的数据,但它给了我一些奇怪的结果。使用 VS Code 调试器查看附件图像(var source 是一个 Queryable,类似于 _dbContext.ModelNa
我是一名优秀的程序员,十分优秀!