A day in the life...

public class GeekEarth : Earth { }
posts - 26, comments - 8236, trackbacks - 0

Tuesday, April 12, 2011

Identified associations (maps)

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

posted @ Tuesday, April 12, 2011 10:57 AM | Feedback (346) |

Powered by: