I've been looking into the specification pattern for my repositories, I'm using EF4 inside my repositories to query the database and map the selected entities by passing in an expression, something like this:-
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _objectSet.Where<TEntity>(predicate);
}
This works okay if your just working with the one object set but say if you wanted to select all the comments made by a user that are greate开发者_StackOverflow中文版r than 128 chars and the user is active. How would you create a specification when two or more object sets are used?
Example:-
class User
{
public string Name { get; set; }
public bool Active { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public User()
{
Posts = new List<Post>();
}
}
class Post
{
public string Text { get; set; }
public DateTime Created { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public Post()
{
Comments = new List<Comment>();
}
}
class Comment
{
public string Text { get; set; }
public DateTime Created { get; set; }
}
To do this in Linq is :-
var results = from u in users
from p in u.Posts
from c in p.Comments
where u.Active && c.Text.Length > 128
select c;
How would you then convert that to a specification class? Maybe I am just not seeing something as it seems like a reasonable thing to do :)
EDIT
The specification interface:
public interface ISpecification<TEntity>
{
bool IsSatisfiedBy(TEntity entity);
}
First of all your current setup doesn't allow such query because User
and Comment
are not related. You can select only all comments related to posts related to user but you don't know who posted comments.
Just add relation between User
and Comment
and you can simply use:
var results = from c in context.Comments
where c.User.Active and c.Text.Length > 128
select c;
This will be easily possible in your Specification pattern. Anyway if you want to build complex condition from Comment
in your Find
method you must expose navigation properties to allow that.
Funny I was just reading about OCP (Open Closed Principle) and the Specification pattern, and I was wondering whether it's actually worth implementing the Specification pattern in my project. I'm just worried I might end up with a huge pile of specifications due to the fact that I have several entities and I query by several criteria.
Anyway, here's one (actually two) of my favorite blog posts about the patterns you're using (which I'm using as well):
Entity Framework 4 POCO, Repository and Specification Pattern
Specification Pattern In Entity Framework 4 Revisited
精彩评论