I thought I’d share this approach to having named associations. Let’s say you have an Address class with a Name property on it, your Employee can have a property like this
1 var homeAddress = new Address(.....);
2 homeAddress.Line1 = "192 Blah Street";
3 homeAddress.Line2 = "etc";
4 employee.Addresses["Home"] = homeAddress;
5
6 var workAddress = new Address(.....);
7 workAddress.Line1 = "123 Meh Road";
8 workAddress.Line2 = "etc";
9 employee.Addresses["Work"] = workAddress;
Once you have created your Employee and Address classes add a private association from Employee to Address named something like _Addresses. Then add the following code to the Employee class.
1 IdentifiedAssociation<string, NamedPostalAddress> postalAddresses;
2 public IdentifiedAssociation<string, NamedPostalAddress> PostalAddresses
3 {
4 get
5 {
6 if (postalAddresses == null)
7 postalAddresses = new IdentifiedAssociation<string, NamedPostalAddress>(
8 //Delete existing value on unlink
9 true,
10 //Get association
11 () => this._Addresses,
12 //Object matches identifier
13 (address, identifier) => string.Compare(identifier, address.Name, true) == 0,
14 //Set object identifier
15 (address, identifier) => address.Name = identifier);
16 return postalAddresses;
17 }
18 }
19
You might want to make the setter for the indexed property (Address.Name in this case) to internal so that only business classes can alter it. The generic code to implement this identified association is as follows
1 public class IdentifiedAssociation<TIdentifier, TAssociated> : IEnumerable<TAssociated>
2 where TAssociated : IEcoObject
3 {
4 readonly bool DeleteOnUnlink;
5 readonly Func<IList<TAssociated>> GetAssociation;
6 readonly Func<TAssociated, TIdentifier, bool> ObjectMatchesIdentifier;
7 readonly Action<TAssociated, TIdentifier> SetIdentifier;
8
9 public IdentifiedAssociation(
10 bool deleteOnUnlink,
11 Func<IList<TAssociated>> getAssociation,
12 Func<TAssociated, TIdentifier, bool> objectMatchesIdentifier,
13 Action<TAssociated, TIdentifier> setIdentifier)
14 {
15 Contract.Requires(getAssociation != null);
16 Contract.Requires(objectMatchesIdentifier != null);
17 Contract.Requires(setIdentifier != null);
18
19 DeleteOnUnlink = deleteOnUnlink;
20
21 GetAssociation = getAssociation;
22 ObjectMatchesIdentifier = objectMatchesIdentifier;
23 SetIdentifier = setIdentifier;
24 }
25
26 public TAssociated this[TIdentifier identifier]
27 {
28 get
29 {
30 return GetAssociation().SingleOrDefault(x => ObjectMatchesIdentifier(x, identifier));
31 }
32 set
33 {
34 var currentValue = this[identifier];
35 if (currentValue != null && currentValue.Equals(value))
36 return;
37 if (currentValue != null && DeleteOnUnlink)
38 currentValue.AsIObject().Delete();
39 if (value != null)
40 {
41 GetAssociation().Add(value);
42 SetIdentifier(value, identifier);
43 }
44 }
45 }
46
47 public IEnumerator<TAssociated> GetEnumerator()
48 {
49 return GetAssociation().GetEnumerator();
50 }
51
52 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
53 {
54 return GetEnumerator();
55 }
56 }
57