我有一种方法,我使用Linq对其进行过滤并将其转换为List,但是对于请求的调用,它会提前转换为列表。请参阅此处的自定义方法示例:
public IEnumerable<ItemModel> GetAll()
{
var output = new List<ItemModel>();
this.DataLayer.GetItems() //returns IQueryable<SomeWeirdItemModel>
.Where(i => i.IsActive == true)
.ToList()
.ForEach(i => output.Add(new ItemModel(i)));
return output;
}
问题是,当我执行this.GetAll().Where(i => i.StartDate >= DateTime.Now)
时,我的自定义方法将其转换为从数据库中检索一切的List,然后我的请求按日期过滤。如何获取被调用的Linq并将其实现到我的自定义方法中?
这样的东西?
this.DataLayer.GetNewsItems().Where(i => i.IsActive == true && (REQUESTED FILTER HERE?))
答案 0 :(得分:2)
这里有几个问题。
首先,ToList()将返回与数据库中的Where子句匹配的所有项。你不能做ToList()并且不能立即执行查询。
其次,你要归还IEnumerable<ItemModel>
。 IEnumerables也会立即执行查询。如果要向返回的类型添加其他参数,则必须返回IQueryable<ItemModel>
。
第三,使用Constructor参数进行此操作可能很困难,因为这需要在代码中进行处理,而不是在数据库中进行处理。 @dasblinkenlight的解决方案可能有效,但我无法测试。我猜他知道他在说什么。
您需要将其代码更改为:
public IQueryable<ItemModel> GetAll()
{
return this.DataLayer.GetNewsItems()
.Where(i => i.IsActive)
.Select((v,i) => new ItemModel(i));
}
修改强>
如果您坚持使用构造函数参数作为投影类型,那么您将不得不在某处妥协,例如将过滤器传递给您的方法。
这样的事情:
public IEnumerable<ItemModel> GetItemsByDate(DateTime date)
{
return this.DataLayer.GetNewsItems()
.Where(i => i.IsActive && i.Date == date)
.AsEnumerable()
.Select(x => new ItemModel(x));
}
当您调用该方法时,它仍然会执行查询(您不能对输出应用任何其他过滤器并让它在数据库中执行),但它只会返回与IsActive和Date过滤器匹配的对象。
你也可以应用这样的任意表达式:
public IEnumerable<ItemModel> GetItemsByDate(Expression<Func<SomeWeirdItemModel,bool>> filter)
{
return this.DataLayer.GetNewsItems()
.Where(i => i.IsActive && filter)
.AsEnumerable()
.Select(x => new ItemModel(x));
}
然后你可以这样做:
var items = DataLayer.GetAll(x => x.Date == date);
var others = DataLayer.GetAll(x => x.Date == date && x.Title.Length > 5 && x.Test = "X");
// etc..
不幸的是,您必须在参数中公开SomeWeirdModel,因为表达式必须对其进行过滤,否则您将不得不做很多工作来尝试翻译过滤器。