我们如何在Entity Framework中进行对象过滤?

5

当使用实体框架中的Code First定义对象上下文时,例如:

public class DomainContext : DbContext
{
    public DomainContext() { }
    public virtual DbSet<News> News { get; set; }
}

我们都知道,可以通过以下方式查询“新闻”(例如,获取今天发布的所有新闻):
var ctx = new DomainContext();
ctx.News.Where(x => x.PublishedDate == DateTime.Now.Date)

但是,这里有一个问题:是否有一种方法可以将预定义的过滤/条件应用于通过ctx.News传递的所有查询?比如说,我想让所有在ctx.News上的查询都隐式地应用“今天发布”的过滤器?


为什么不添加一个名为NewsToday的属性,该属性返回“今天新闻”的查询结果?例如:http://msdn.microsoft.com/en-us/library/bb882532.aspx - Fox32
4个回答

3

在查询新闻时,无法添加自动条件(过滤器)。所有发布的示例都有效,但仅当您直接查询News时才有效。例如,如果您加载指向News的导航属性,则示例将失败。

EDMX通过条件映射解决了这个问题,但这会带来其他非常严重的缺点。条件映射是固定的(无法在不重新构建模型的情况下更改),并且每种类型只能有一个条件 - 就像TPH降级为单个实体类型。此外,条件映射中定义的条件可能无法与“今天”一起使用。条件映射在代码优先方法中不可用。


2
我不认为可以像您提出的那样向DbSet<News>对象添加过滤器。但是,您应该能够编写另一个函数:
public virtual IEnumerable<News> TodaysNews
{
    get { return News.WHere(n => n.PublishDate == DateTime.Today); } 
}

然后,如果您在其他地方进行了查询,例如:

var todaysGoodNews = from n in ctx.TodaysNews
                     where n.IsGood == true
                     select n;

如果将这两个查询合并成一个,那么在发送到服务器时会将它们合并而不是分为两个独立的查询。我不确定在使用 IEnumerable<> 时是否适用,或者您是否需要返回其他内容(例如 IQueryable<>)。

编辑:

我刚刚看到你对下面另一个发帖者的回复。我想我花了太长时间来输入/格式化。我不知道有没有办法像那样应用过滤器,但我们的解决方案是否有效?您甚至可以使 TodaysNews 成为通过上下文直接访问该对象的唯一方式之一。


嗯,它有点起作用。但是它比那更加复杂,我想自动地能够“隐藏”普通的“新闻”从而使其与应用程序的其余部分分离开来(这不是一个特定的应用程序,而是一种通用的解决方案,基本上是要在整个公司中作为库重复使用)。 - thr

0
你可以在你的上下文中添加一个新属性:
public IEnumerable<News> TodaysNews
{
    get
    {
        return this.News.Where(x => x.PublishedDate == DateTime.Now.Date);
    }
}

然后可以对该属性应用任何进一步的过滤/排序等操作。

更新:

如果您无法使用预过滤查询,则另一个选项是在数据库中创建一个视图并将实体映射到该视图。该视图可以基于当前日期。


正确,但遗憾的是这不是我想要的。在EF中,没有办法对特定类型的所有对象应用隐式查询过滤器吗? - thr
看我的更新。也许将实体映射到视图可以解决你的问题。 - Jacob

0

EntityFramework.Filters库在过滤器值的生命周期方面存在一些问题(请参见问题部分)。EntityFramework.DynamicFilters(https://github.com/jcachat/EntityFramework.DynamicFilters)没有这些问题,但需要将外键建模为实体类中的属性。 - bloparod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接