mark_dj
mark_dj

Reputation: 994

DDD - Invalidating expirable

Currently diving into DDD and i've read most of the big blue book of Eric Evans. Quite interesting so far :)

I've been modeling some aggregates where they hold a collection of entities which expire. I've come up with a generic approach of expressing that:

public class Expirable<T>
{
    public T Value { get; protected set; }
    public DateTime ValidTill { get; protected set; }

    public Expirable(T value, DateTime validTill)
    {
        Value = value;
        ValidTill = validTill;
    }
}

I am curious what the best way is to invalidate an Expirable (nullify or omit it when working in a set). So far I've been thinking to do that in the Repository constructor since that's the place where you access the aggregates from and acts as a 'collection'.

I am curious if someone has come up with a solution to tackle this and I would be glad to hear it :) Other approaches are also very welcome.

UPDATE 10-1-2013:

This is not DDD with the CQRS/ES approach from Greg Young. But the approach Evans had, since I just started with the book and the first app. Like Greg Young said, if you have to make good tables, you have to make a few first ;)

Upvotes: 0

Views: 425

Answers (3)

mark_dj
mark_dj

Reputation: 994

Have been reading up on DDD with CQRS/ES (Greg Young approach) and found a great example on the MSDN site about CQRS/ES: http://msdn.microsoft.com/en-us/library/jj554200.aspx

In this example they use the command message queue to queue a Expire message in the future, which will call the Aggregate at the specified time removing/deactivate the expirable construct from the aggregate.

Upvotes: 0

mark_dj
mark_dj

Reputation: 994

I've added a method to my abstract repository InvalidateExpirable. An example would be the UserRepository where I remove in active user sessions like this: InvalidateExpirable(x => x.Sessions, (user, expiredSession) => user.RemoveSession(expiredSession));.

The signature of InvalidateExpirable looks like this: protected void InvalidateExpirable<TExpirableValue>(Expression<Func<T, IEnumerable<Expirable<TExpirableValue>>>> selector, Action<T, Expirable<TExpirableValue>> remover). The method itself uses reflection to extract the selected property from the selector parameter. That property name is glued in a generic HQL query which will traverse over the set calling the remove lambda. user.RemoveSession will remove the session from the aggregate. This way the I keep the aggregate responsible for it's own data. Also in RemoveSession an domain event is raised for future cases.

See: https://gist.github.com/4484261 for an example

Works quite well sofar, I have to see how it works further down in the application though.

Upvotes: 0

Aaron Hawkins
Aaron Hawkins

Reputation: 2691

There are probably multiple ways to approach this, but I, personally, would solve this using the Specification pattern. Assuming object expiration is a business rule that belongs in the domain, I would have a specification in addition to the class you have written. Here is an example:

public class NotExpiredSpecification
{
    public bool IsSatisfiedBy(Expirable<T> expirableValue)
    {
        //Return true if not expired; otherwise, false.
    }
}

Then, when your repositories are returning a list of aggregates or when performing any business actions on a set, this can be utilized to restrict the set to un-expired values which will make your code expressive and keep the business logic within the domain.

To learn more about the Specification pattern, see this paper.

Upvotes: 1

Related Questions