views:

260

answers:

3

Hi all,

I ve got an employee that holds several addresses in a collection.

public class Employee
{
    public string Name { get; set; }

    public AddressCollection Addresses { get; }
}


public class AddressCollection : IEnumerable<Address>
{
    private readonly Employee employee;
    private IList<Address> items = new List<Address>();

    public void AddAddress(Address address)
    {
        if (items.Contains(address)) return;

        address.Employee = employee;
        items.Add(address);
    }

    public void RemoveAddress(Address address)
    {
        items.Removce(address);
    }

    /// further IEnumerable implementations
}

public class Address
{
    public AddressType Type { get; set; }
    public City City { get; set; }
    public string Street { get; set; }

    public DateTime ValidFrom { get; set; }
    public DateTime ValidTo { get; set; }
}

public enum AddressType
{
    Default,
    ShippingAddress
}

Only one address of a certain type can be valid at a time. So when adding an address of Type Default valid from 1-1-2009 to 15-1-2009 and then another address of Type Default valid from 10-1-2009 to 15-1-2009 an exception needs to be thrown.

What would be the best approach from a DDD perspective? Of course within the AddAddress method I could iterate through the existing addresses and throw an exception.

But since this business rule needs to be checked on the presentation layer to show a message to the user, shouldn't I use a specification for this which I can use internally as well as in the presentation layer?

How would you solve this?

A: 

I would recommend using the Validation Application Block from the Enterprise Library released by the Microsoft Patterns and Practices team.

This allows you to put the validation logic on the domain object (maintaining DDD), but also to populate the object, and then ask is it valid, rather than throwing an exception.

I'm not sure what your UI is, but the Validation Application Block can be integrated with ASP.NET, Windows Forms, and WCF.

MJ Richardson
+2  A: 

First, I would get rid of your AddressCollection class and implement its members on Employee.

For validating rules like this I recommend the specification pattern. It doesn't need to be as complicated as the Wikipedia article, it can simply be:

public class CanAddAddressToEmployeeSpec
{
    public bool IsSatisfiedBy(Address candidate)
    {  // logic to check address }
}

You can then use that class to check if an Address can be added to an Employee before adding it so that your Employee object doesn't enter an invalid state. I also often add a Messages property to a specification that returns an explanation if IsSatisifiedBy is false.

If you need more confidence, you can create a similar specification for EmployeeAddressesAreValidSpec taking an Employee as the candidate argument to IsSatisfiedBy and check that before persisting data.

Jamie Ide
A: 

I agree with Richo. Start looking at the Validation Application Block. This article might help you as it describes how to integrate VAB with O/RM frameworks. While the article focuses on LINQ to SQL and Entity Framework, I'd expect no surprises for NHibernate.

Steven