我可能完全误解了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后端完全不可知?
答案 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
个实例。
这可能不适合您的情况,但您可以使用此模式来查看它是否会带您进入任何地方。