I have a method that helps to dynamically build a query on a client:
public virtual IList<TEntity> Fill(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
includeProperties = includeProperties ?? "";
var qctx = new TQueryContext
{
QueryType = filter == null ? CommonQueryType.FillAll : CommonQueryType.FillWhere,
Filter = filter,
OrderBy = orderBy
};
qctx.Includes.AddRange(includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
_detachedServerRepo.Read(qctx);
return qctx.Entities;
}
I want to send qctx to a server repo which might be on another machine. Since a TQueryContext will be typed from QueryContextBase defined in part as below I can't serialize it.
public class QueryContextBase<TEntity, TKey>
where TEntity : StateTrackedObject
where TKey : IEquatable<TKey>
{
public TKey ID { get; set; }
public string Alf { get; set; }
public List<TEntity> Entities { get; set; }
public List<string> Includes { get; set; }
public Expression<Func<TEntity, bool>> Filter { get; set; }
public Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> OrderBy { get; set; }
}
How can I create similar properties to Filter and OrderBy so I can serialize them and then build up the query in the server repo as below:
protected override void FillWhere(TQueryContext qctx)
{
qctx.Entities.AddRange(this.Fill(qctx.Filter, qctx.OrderBy,
qctx.GetIncludesAsString()));
}
protected override void FillAll(TQueryContext qctx)
{
qctx.Entities.AddRange(this.Fill(null, qctx.OrderBy, qctx.GetIncludesAsString()));
}
public virtual IEnumerable<TEntity> Fill(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
includeProperties = includeProperties ?? "";
try
{
IQueryable<TEntity> querySet = DbSet;
if (filter != null)
{
querySet = querySet.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
querySet = querySet.Include(includeProperty.Trim());
}
return (orderBy == null) ? querySet.ToList() : orderBy(querySet).ToList();
}
catch (Exception ex)
{
return ex.ThrowDalException<IEnumerable<TEntity>>(OperationType.Read, ex.Message, ex);
}
}
You're right not to want to reinvent the wheel. Check out Serialize.Linq.
You could solve your problem with this library as below:
In your client repo:
public virtual IList<TEntity> Fill(Expression<Func<TEntity, bool>> filter = null,
Expression<Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>>> orderBy = null,
string includeProperties = "") {
includeProperties = includeProperties ?? "";
try
{
var qctx = new TQueryContext
{
QueryType = filter == null ? CommonQueryType.FillAll : CommonQueryType.FillWhere,
FilterNode = filter == null ? null : filter.ToExpressionNode(),
OrderByNode = orderBy == null ? null : orderBy.ToExpressionNode()
};
And then in your QueryContext just add the extra property and convert:
public ExpressionNode FilterNode { get; set; }
public Expression<Func<TEntity, bool>> Filter
{
get {
return FilterNode == null ? null : FilterNode.ToBooleanExpression<TEntity>();
}
}
public ExpressionNode OrderByNode { get; set; }
public Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>> OrderBy
{
get {
return OrderByNode == null ? null : OrderByNode.ToExpression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With