存储库上的EF查询对象模式示例

时间:2012-08-14 05:48:12

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

我已经构建了一个存储库,该存储库仅基于Scott Millett的“Professional ASP.NET Design Patterns”中的示例公开IEnumerable。

然而,因为他主要使用NHibernate他的如何实现查询对象模式的例子,或者更确切地说如何最好地将查询翻译成EF中有用的东西,有点缺乏。

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

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

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

根据书(Scott Millett的“专业ASP.NET设计模式”),您可以使用此代码[我改进了一些行]:

  • 基础设施层:

  • 标准类:(每个查询可以包含一些标准)

    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类来翻译查询(在存储库层中):

    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;
    }