我已经构建了一个存储库,该存储库仅基于Scott Millett的“Professional ASP.NET Design Patterns”中的示例公开IEnumerable。
然而,因为他主要使用NHibernate他的如何实现查询对象模式的例子,或者更确切地说如何最好地将查询翻译成EF中有用的东西,有点缺乏。
我正在寻找使用EF4实现查询对象模式的一个很好的例子。
编辑:本书中简单示例的主要问题是CreateQueryAndObjectParameters仅处理2个案例,Equal& LesserThanOrEqual - 不完全是一个完整的查询解决方案。它使用一个字符串来构建标准 - 与NHibernate相比,这是一种非常粗略的方法来处理它。他说他将为第10章示例提供EF代码,但不在下载中。因此寻找一个真实世界的例子。
答案 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;
}