4

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

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

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

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

4

2 回答 2

2

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

于 2012-09-05T15:36:02.313 回答
0

根据这本书(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;
    }
于 2013-07-25T10:18:22.490 回答