【问题标题】:EF Query Object Pattern over Repository Example存储库示例上的 EF 查询对象模式
【发布时间】:2012-08-10 09:31:44
【问题描述】:

我已经构建了一个存储库,它主要基于 Scott Millett 的“专业 ASP.NET 设计模式”中的示例公开 IEnumerable。

但是,因为他主要使用 NHibernate,所以他的示例关于如何实现查询对象模式,或者更确切地说,如何最好地将查询转换为 EF 中有用的东西,有点缺乏。

我正在寻找一个使用 EF4 实现查询对象模式的好例子。

编辑:书中简单示例的主要问题是 CreateQueryAndObjectParameters 仅处理 2 种情况,Equal 和 LesserThanOrEqual - 不完全是一个完整的查询解决方案。它使用字符串来构建标准 - 与 NHibernate 相比,这是一种非常粗略的处理方式。他说他将提供第 10 章示例的 EF 代码,但下载中没有。因此寻找一个真实世界的例子。

【问题讨论】:

    标签: c# entity-framework-4 repository-pattern objectquery


    【解决方案1】:

    此时您可能已经厌倦了听到我的消息,但原生支持的 IQueryable 是 EF 所需的唯一查询对象模式实现。

    【讨论】:

    • 谢谢 - 这是我为该项目采取的方法 :) 尽管出于兴趣,我仍然希望看到这样的实现。
    • @Dale Burrell,您为什么认为 IQueryable 不符合“查询对象模式”的实现条件?
    【解决方案2】:

    根据这本书(Scott Millett 的“Professional ASP.NET Design Patterns”),您可以使用以下代码 [我改进了一些行]:

    • 基础设施层:

    • Criterion 类:(每个 Query 可以包含一些 Criterion)

      public class Criterion
      {
      private string _propertyName;
      private object _value;
      private CriteriaOperator _criteriaOperator;
      
      public Criterion(string propertyName, object value,
                       CriteriaOperator criteriaOperator)
      {
          _propertyName = propertyName;
          _value = value;
          _criteriaOperator = criteriaOperator;
      }
      
      public string PropertyName
      {
          get { return _propertyName; }
      }
      
      public object Value
      {
          get { return _value; }
      }
      
      public CriteriaOperator criteriaOperator
      {
          get { return _criteriaOperator; }
      }
      
      public static Criterion Create<T>(Expression<Func<T, object>> expression, object value, CriteriaOperator criteriaOperator)
      {
          string propertyName = PropertyNameHelper.ResolvePropertyName<T>(expression);
          Criterion myCriterion = new Criterion(propertyName, value, criteriaOperator);
          return myCriterion;
      }
      }
      
    • CriteriaOperator 类:

      public enum CriteriaOperator
      {
          Equal,
          LesserThanOrEqual,
          NotApplicable
          // TODO: Add the remainder of the criteria operators as required.
      }
      
    • OrderByClause 类:

      public class OrderByClause
      {
          public string PropertyName { get; set; }
          public bool Desc { get; set; }
      }
      
    • 查询类:

      public class Query
      {
      private QueryName _name;
      private IList<Query> _subQueries = new List<Query>();
      private IList<Criterion> _criteria = new List<Criterion>();
      
      public Query()
          : this(QueryName.Dynamic, new List<Criterion>())
      { }
      
      public Query(QueryName name, IList<Criterion> criteria)
      { 
          _name = name;
          _criteria = criteria;
      }
      
      public QueryName Name
      {
          get { return _name; }
      }
      
      public bool IsNamedQuery()
      {
          return Name != QueryName.Dynamic;
      }
      
      public IEnumerable<Criterion> Criteria
      {
          get {return _criteria ;}
      }          
      
      public void Add(Criterion criterion)
      {
          if (!IsNamedQuery())
              _criteria.Add(criterion);
          else
              throw new ApplicationException("You cannot add additional criteria to named queries");
      }
      
      public IEnumerable<Query> SubQueries
      {
          get { return _subQueries; }
      }
      
      public void AddSubQuery(Query subQuery)
      {
          _subQueries.Add(subQuery);
      }
      
      public QueryOperator QueryOperator { get; set; }
      
      public OrderByClause OrderByProperty { get; set; }
      }
      
    • PropertyNameHelper 类:

      public static class PropertyNameHelper
      {
          public static string ResolvePropertyName<T>(
                             Expression<Func<T, object>> expression)
          {
              var expr = expression.Body as MemberExpression;
              if (expr == null)
              {
                  var u = expression.Body as UnaryExpression;
                  expr = u.Operand as MemberExpression;
              }
              return expr.ToString().Substring(expr.ToString().IndexOf(".") + 1);
          }
      }
      

      您还需要一个 QueryTranslator 类来翻译查询(在 Repository 层):

      public class TimelogQueryTranslator : QueryTranslator
      {
      public ObjectQuery<Timelog> Translate(Query query)
      {
          ObjectQuery<Timelog> timelogQuery;
      
          if (query.IsNamedQuery())
          {
              timelogQuery = FindEFQueryFor(query);
          }
          else
          {
              StringBuilder queryBuilder = new StringBuilder();
              IList<ObjectParameter> paraColl = new List<ObjectParameter>();
              CreateQueryAndObjectParameters(query, queryBuilder, paraColl);
      
              //[Edited By= Iman] :
              if (query.OrderByProperty == null)
              {
                  timelogQuery = DataContextFactory.GetDataContext().Timelogs
                  .Where(queryBuilder.ToString(), paraColl.ToArray());
              }
              else if (query.OrderByProperty.Desc == true)
              {
                  timelogQuery = DataContextFactory.GetDataContext().Timelogs
                  .Where(queryBuilder.ToString(), paraColl.ToArray()).OrderBy(String.Format("it.{0} desc", query.OrderByProperty.PropertyName));
              }
              else
              {
                  timelogQuery = DataContextFactory.GetDataContext().Timelogs
                      .Where(queryBuilder.ToString(), paraColl.ToArray()).OrderBy(String.Format("it.{0} asc", query.OrderByProperty.PropertyName));
              }
              //[Edited By= Iman] .
      
          }
      
          return timelogQuery;
      }
      //-------------------------------------------------------------
          public abstract class QueryTranslator
      {
          public void CreateQueryAndObjectParameters(Query query, StringBuilder queryBuilder, IList<ObjectParameter> paraColl)
          {
              bool _isNotFirstFilterClause = false;
      
              foreach (Criterion criterion in query.Criteria)
              {
                  if (_isNotFirstFilterClause)
                  {
                      queryBuilder.Append(" AND "); //TODO: select depending on query.QueryOperator
                  }
                  switch (criterion.criteriaOperator)
                  {
                      case CriteriaOperator.Equal:
                          queryBuilder.Append(String.Format("it.{0} = @{0}", criterion.PropertyName));
                          break;
                      case CriteriaOperator.LesserThanOrEqual:
                          queryBuilder.Append(String.Format("it.{0} <= @{0}", criterion.PropertyName));
                          break;
                      default:
                          throw new ApplicationException("No operator defined");
                  }
      
                  paraColl.Add(new ObjectParameter(criterion.PropertyName, criterion.Value));
      
                  _isNotFirstFilterClause = true;
              }
          }
      }
      

    现在在您的服务层

        public IEnumerable<Timelog> GetAllTimelogsFor(int iadcId, byte workShift)
        {
            Query query = new Query(QueryName.Dynamic,new List<Criterion>());
            query.Add(Criterion.Create<Timelog>(t=>t.IadcId, iadcId, CriteriaOperator.Equal));
            query.QueryOperator = QueryOperator.And;
            query.Add(Criterion.Create<Timelog>(t=>t.Shift, workShift, CriteriaOperator.Equal));
            query.OrderByProperty = new OrderByClause { PropertyName = "FromTime", Desc = false };
    
            IEnumerable<Timelog> timelogs = _timelogRepository.FindBy(query);
    
            return timelogs;
        }
    

    【讨论】:

    • 谢谢伊曼 - 正如我提到的我有这本书,所以你非常专注于再次输入所有这些:) 不幸的是,尽管这是一个微不足道的例子(如书中所述),但他说他将提供第 10 章的 EF 代码,但无法下载。该示例的主要问题是 CreateQueryAndObjectParameters 仅处理 2 种情况,Equal 和 LesserThanOrEqual - 不完全是一个完整的查询解决方案。与 NHibernate 相比,使用字符串来构建标准也是一种非常粗略的处理方式——我希望有人有更好的东西。无论如何,谢谢。
    猜你喜欢
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-11
    • 1970-01-01
    • 2011-10-16
    相关资源
    最近更新 更多