0

我有一个方法,我使用 Linq 对其进行过滤并将其转换为列表,但它被转换为列表以提早请求调用。请参阅此处的自定义方法示例:

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),我的自定义方法将其转换为从数据库中检索所有内容的列表,然后我的请求按日期过滤。如何获取被调用的 Linq 并将其实现到我的自定义方法中?

像这样的东西? this.DataLayer.GetNewsItems().Where(i => i.IsActive == true && (REQUESTED FILTER HERE?))

4

1 回答 1

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,因为表达式必须对其进行过滤,否则您将不得不做很多工作来尝试翻译过滤器。

于 2013-06-24T23:56:51.933 回答