开发者

Filters in DDD Repository

There is Campaign Entity and for that, I have CampaignRepository which have this functions

  1. public IList FindAll();
  2. public Campaign FindByCampaignNumber(string number);

But now i want this criterias -:

  1. Find campaigns that are created today.
  2. Find campaigns that are created in this month
  3. Find top 5 latest campaigns.
  4. Find campaigns that are created in 开发者_StackOverflowthis year.

So for all these campaigns filters,

Do i create separate function for each of them in repository ?

and implement like this way.

Getall campaigns and then filter required campaigns, but i do not want all campaigns. While searching in google i find this solution's

1: http://russelleast.wordpress.com/2008/09/20/implementing-the-repository-and-finder-patterns/

Is there any method i can avoid multiple functions or do i go ahead and create seperate functions for each of this filter ?


Have you considered implementing Specification pattern in your application? Maybe it looks like an overkill, but it may prove useful if your app will have some complex user filter options.

class CampaignSpecification
{
    public CampaignSpecification Number(string number);
    public CampaignSpecification DateBetween(DateTime from, date to);
    public CampaignSpecification Year(DateTime year);
} //I have omitted all the AND/OR stuff it can be easily implemented with any SQL like query language

Here is an example how loading from the repository may look like

var  campaignList = CampaignRepository.load(
            new CampaignSpec()
                .Number("2")
                .Year(DateTime.Now);

Also I'd like to add that it depends much on what kind of data access solution you are using, it makes implementing easier when you know what kind of API you will be using(Criteria API, SQL or whatever) so you can tweak your Specification interface to make its implementation simpler.

UPDATE: if you are implementing specifications in .NET using linq and nHibernate please check out http://linqspecs.codeplex.com/


I would go with creating two Specifications: TopCampaignSpec and CampaingCreatedSpec.

var spec = CampaignCreatedSpec.ThisYear();
var campaigns = CampaignsRepository.FindSatisfying(spec);

CampaingCreatedSpec can also be replaced with more generic DateRange class if you need this functionality elsewhere:

var thisYear = DateRange.ThisYear();
var campaigns = CampaignsRepository.FindByDateRange(spec);

I also highly recommend staying away from 'generic' repositories and entities. Please read this

From DDD perspective it does not matter whether data access code is implemented as SQL/HQL/ICriteria or even web service call. This code belongs to repository implementation (data access layer). This is just a sample:

public IList<Campaign> FindByDateRange(CampaignCreatedSpec spec) {
    ICriteria c = _nhibernateSession.CreateCriteria(typeof(Campaign));
    c.Add(Restrictions.Between("_creationDate", spec.StartDate, spec.EndDate));
    return c.List<Campaign>();
}


Here is how I would do this:

class Campaigns{
  IEnumerable<Campaign> All(){...}
  IEnumerable<Campaign> ByNumber(int number){...}
  IEnumerable<Campaign> CreatedToday(){...}
  IEnumerable<Campaign> CreatedThisMonth(){...}
  IEnumerable<Campaign> CreatedThisYear(){...}
  IEnumerable<Campaign> Latest5(){...}

  private IQueryable<Campaign> GetSomething(Something something){
    //used by public methods to dry out repository
  }
}

Reasoning is simple - it matters by what You are interested to look for campaigns (that knowledge is part of Your domain). If we explicitly state functions to reflect that, we will always know it.


Is it appropriate to add all this methods in campaign repository ?

I don't see anything wrong with that.

Arnis i want some code, how u implementing Created today function in domain itself, Are you injecting repository here in this function ? Thanks for your cooperation

I wouldn't implement CreatedToday function in my domain. It would sit in repository and repository implementations should not be concern of domain. If You mean how I would use Campaign repository and if it should be used from domain - no, it should not be used from within of domain. If You mean if I would inject repository inside of repository - You are listening too much of xzibit.


You should be able to do all of the above with the following repository method:

List<Campaign> findCampaigns(Date fromCreationDate, Date toCreationDate, int offset, Integer limit) {

   if (fromCreationDate != null) add criteria...
   if (toCreationDate != null) add criteria...
   if (limit != null) add limit...
}

This is how I do it and it works very well.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜