Download ServicePredicateBuilder.zip 15.8KB
Introduction
If you worked with WCF and EntityFramework, you faced with a big problem. Serializing Expressions
As you know, You can't serilize .Net Expression. so, you will have two choices:
1. Creating a method (Operation Contract) for each needing.
2. Creating another thing (class) to add predicates in a serializable form and send it via services.
ServicePredicateBuilde is that it. you can create predicates with it and send it via services and in service side get the expressions easily.
Background
There are some other libraries to do that, you can find them with googling 'serializable expression'
Unfortunately, most of them are old and don't update anymore. We couldn't use them easily.
Using the code
Install-Package ServicePredicateBuilder
Let us a review on ServicePredicateBuilder
class
[Serializable]
[DataContract]
public class ServicePredicateBuilder<TEntity> where TEntity : class
{
[DataMember]
public Criteria<TEntity> Criteria { get; set; }
[DataMember]
public SortCondition<TEntity> SortCondition { get; set; }
[DataMember]
public List<string> IncludedNavigationProperties { get; set; }
private List<Expression<Func<TEntity, object>>> _includedNavigationPropertiesExpression;
public List<Expression<Func<TEntity, object>>> IncludedNavigationPropertiesExpression
{
...
}
[DataMember]
public PaginationData PaginationData { get; set; }
public ServicePredicateBuilder<TDestination> Cast<TDestination>() where TDestination : class
{
...
}
}
Now, Let us code with ServicePredicateBuilder
At first, assume we have an Entity named User
, Now we wanna create a predicate on User
ServicePredicateBuilder servicePredicateBuilder = new ServicePredicateBuilder
{
IncludedNavigationProperties = new List<string> { "Attachments", "Posts" },
PaginationData = new PaginationData
{
PageNumber = page,
ItemsPerPage = itemsPerPage
}
};
Criteria<User> firstCritaria = Critaria.True<User>();
firstCritaria = firstCritaria.And(entity => entity.FirstName, OperatorEnum.Like, "Mohammad");
firstCritaria = firstCritaria.And>(entity =>entity.LastName, OperatorEnum.Like, "Dayyan");
firstCritaria = firstCritaria.And(entity =>entity.Comments.Count, OperatorEnum.GreaterThanOrEqual, 5);
Criteria<User> secondCritaria = Critaria.True<User>();
secondCritaria = secondCritaria.And(entity =>entity.FirstName, OperatorEnum.Like, "Vahid");
secondCritaria = secondCritaria.And(entity =>entity.LastName, OperatorEnum.Like, "Jafari");
secondCritaria = secondCritaria.And(entity =>entity.Comments.Count, OperatorEnum.GreaterThanOrEqual, 5);
Criteria<User> finalCritaria = firstCritaria.Or(secondCritaria);
servicePredicateBuilder.Critaria = finalCritaria;
SortCondition<User> sortCondition = SortCondition<User>.OrderBy(q=>q.FirstName);
sortCondition = sortCondition.ThenByDescending(q => q.LastName);
List<User> users = clientService.GetUser(servicePredicateBuilder);
[OperationContract]
public List<User> GetUser(ServicePredicateBuilder<User> servicePredicateBuilder)
{
using(ModelEntities context = new ModelEntities())
{
Func<IEnumerable<User>, IOrderedQueryable<User>> enumerableSortingFunc = servicePredicateBuilder.SortCondition.GetIEnumerableSortingFunc();
Func<IQueryable<User>, IOrderedQueryable<User>> queryableSortingFunc = servicePredicateBuilder.SortCondition.GetIQueryableSortingFunc();
Expression<Func<User, bool>> predicate = servicePredicateBuilder.Criteria.GetExpression();
return enumerableSortingFunc(context.where(predicate));
}
}
History
15th August 2015: First Post
6th October 2015: fix a bug in GetIEnumerableSortingExpression
29th November 2015: Support > >= < <= operators for string fields
30th November 2015: Fix a bug in GetExpression
method