EF查询对象模式在仓储中的示例

4
我已经建立了一个仓库,它只展示IEnumerable接口,主要是基于Scott Millett的“Professional ASP.NET设计模式”一书中的例子。然而,他大多数使用NHibernate来演示如何实现查询对象模式,或者更确切地说,如何将查询转换为EF中的有用内容,这方面的示例有点欠缺。我正在寻找一个好的使用EF4实现查询对象模式的例子。编辑:该书中简单示例的主要问题在于CreateQueryAndObjectParameters仅处理两种情况,Equal和LesserThanOrEqual - 并不完全满足查询需求。同时,它使用字符串来构建标准- 与NHibernate相比,这是一种非常粗糙的处理方式。他说会提供第10章示例的EF代码,但未在下载中提供。因此,寻找一个真实世界的例子。
2个回答

3

你可能已经厌倦了听到我这些话,但是本地支持的 IQueryable 是 EF 所需的唯一查询对象模式实现。


谢谢 - 这就是我为这个项目采取的方法 :) 尽管出于兴趣,我仍然很想看到这样的实现。 - Dale K
@Dale Burrell,为什么您认为IQueryable不符合“查询对象模式”的实现要求? - smartcaveman

0
根据Scott Millett的书《Professional ASP.NET Design Patterns》,您可以使用以下代码(我改进了一些行):
  • 基础设施层:

  • Criterion类:(每个查询可以包含一些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: 根据需要添加其余的条件运算符。
    }
    
  • OrderByClause类:

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

    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("无法向命名查询添加其他条件");
    }
    
    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
    
    <p>现在在您的<strong>服务层</strong>中:</p>
    
    <pre><code>    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;
        }
    

谢谢Iman - 如您所提到的,我有这本书,所以您再次输入所有内容非常专注 :) 不幸的是,这只是一个琐碎的例子(就像在书中一样),他说他会为第10章提供EF代码,但无法下载。该示例的主要问题是CreateQueryAndObjectParameters仅处理2种情况,即Equal和LesserThanOrEqual - 并不完全是查询解决方案。与NHibernate相比,使用字符串构建标准的方法非常粗糙 - 我希望有人有更好的方法。无论如何,还是谢谢。 - Dale K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接