查询IQueryable与ORM完全分离?

时间:2015-08-27 20:00:47

标签: c# entity-framework nhibernate orm iqueryable

我可能完全误解了IQueryable引擎盖下发生的事情,所以如果我错了,我欢迎纠正。

我的数据库中有一个日志表,我希望使用Kendo UI表在前端Web应用程序上查看。

这些javascript组件非常光滑;他们可以基于多个维度来定位和限制通过连接传输的数据...例如,我可以按日志日期组织排名前100的记录,过滤DEBUG或INFO,其中用户是" Joe User&# 34。

这对IEnumerable<LogEntry>对象起作用就好......但是表中有很多LogEntry个对象,我认为这应该是非常糟糕的表现为日志表继续增长。

我想实现这样的服务:

public interface ILogBrowsingService
{
    IQueryable<LogEntry> Logs { get; }
}

...使用ORM(EF,NHibernate,Telerik DataAccess,尚未决定)在另一个程序集中的具体实现,这将允许将一些(希望是大多数)繁重的查询卸载到数据库服务器。我基本上会对服务中暴露的IQueryable运行查询...但是,我想我会很快遇到问题,因为这个服务将在它自己的特定于服务的数据上下文中运行,并且它自己的Linq-To -X实现。我相信我会遇到这个实现的问题,处理数据库上下文生命周期和IQueryable支持等等。

我正在玩捕捉&#34;查询&#34;针对泛型IQueryable<LogEntry>并将其作为参数传递给要针对具体实现进行重放的服务,但我不知道我将如何做到这一点,但是这些内容有以下几点:

public interface ILogBrowsingService
{
    IList<LogEntry> GetLogEntryQueryResults(IQuery<LogEntry> query);
}

我不知道IQuery<LogEntry>会是什么样子。

我真的不想尝试编写一个服务/存储库模式,该模式将包含此表的多种可搜索性排列。我想象一个没有的问题,或者是否有一个&#34;正确的&#34;如何实现我想要做的事情,对ORM后端完全不可知?

1 个答案:

答案 0 :(得分:0)

我使用了这种称为查询对象模式的模式,我认为这种模式类似于您在此处尝试实现的模式。该模式不会自动记录查询并为您重放它们,但它允许您以可以重放的方式编写查询,并且还可以避免模式(如存储库)的副作用。

我们将定义接口IQuery<T>,如下所示

public interface IQuery<T> where T : EntityBase<T>
{
    IEnumerable<T> Run(IQueryable<T> queryable);
}

如果您没有共同的实体库实现,则可以忽略where约束。

根据我们查询的内容,我们将有一个非常具体的接口实现。例如,我们可以实现一个查询来获取日志条目,具体取决于它们是DEBUG,INFO还是ERROR

public class LogEntriesByTypeQuery : IQuery<LogEntry>
{
    private readonly int type;

    public LogEntriesByTypeQuery(string type)
    {
        this.type = type;
    }

    public IEnumerable<LogEntry> Run(IQueryable<LogEntry> logEntries)
    {
        return (from e in logEntries
            where e.Type == type
            select e).ToList();
    }
}

我们现在可以编写非常具体的查询,具体取决于我们想从数据库中获取什么。您可以组合多个筛选条件,也可以为每个筛选条件编写单独的查询。与规范模式不同,此模式不会使您能够将多个不同的查询组合在一起。

然后我们需要一些东西来运行这个查询。 QueryRunner可以很方便

public class QueryRunner : IRunQuery
{
    private readonly ISession session;

    public QueryRunner(ISession session)
    {
        this.session = session;
    }

    public IEnumerable<T> Run<T>(IQuery<T> query) where T : EntityBase<T>
    {
        return query.Run(session.Query<T>());
    }
}

在服务类中,您可以依赖IRunQuery(如果您正在使用依赖项注入)并创建要执行的查询对象的实例并将其传递给Run方法IRunQuery个实例。

这可能不适合您的情况,但您可以使用此模式来查看它是否会带您进入任何地方。

相关问题