Walkthrough: Annotating an Object Model for Parent-Child Relationships

PostSharp provides several custom attributes that you can apply to your object model to describe the parent-child relationships in a natural and concise way. The AggregatableAttribute aspect is applied to the object model classes, and the properties are marked with ChildAttribute, ReferenceAttribute and ParentAttribute custom attributes. You can also use AdvisableCollection<T> and AdvisableDictionary<TKey, TValue> classes to make your collection properties aware of the Aggregatable pattern.

Below you can find a detailed walkthrough on how to add parent-child relationships implementation into existing object models.

This topic contains the following sections:

Applying through PostSharp Tools for Visual Studio

When applying any of the threading model patterns using the wizard you may encounter the Relationships page.

aggregatablewizard

This page provides you with the ability to establish the relationships between objects in an object tree. Simply select the option desired for each complex object and the wizard will add these attributes for you.

Note Note

The wizard process will not address or change collections in the object parent-child relationships. You will need to change collection types by hand.

Applying manually

To apply the Aggregatable to an object model:

  1. Add the AggregatableAttribute attribute to the parent and children classes. In the following examples, an Invoice object owns several instances of the InvoiceLine class, therefore both classes must be annotated with AggregatableAttribute. However, the Invoice does not own the Customer to which it is associated, so the Customer class does not need the custom attribute.

    Note Note

    It is not strictly necessary to add the AggregatableAttribute aspect to a class whose instances will be children but not parents, unless you want to track the relationship to the parent using the IAggregatable.Parent property or the ParentAttribute custom attribute in this class (see below).

    C#
    [Aggregatable]
    public class Invoice
    {
      public Invoice()
      {
         this.Lines = new List<InvoiceLine>();
      }
    
        public Customer Customer { get; set; }
        public IList<InvoiceLine> Lines { get; set; }
      public Address DeliveryAddress { get; set; }
    }         
    
    [Aggregatable]
    public class InvoiceLine
    {
      private Product product;
      public decimal Amount { get; set; }
    }   
    
    [Aggregatable]
    public class Address
    {
    }
  2. Annotate fields and automatic properties of all aggregatable classes with the ChildAttribute or ReferenceAttribute custom attribute. Fields or properties of a value type must not be annotated.

    C#
    [Aggregatable]
    public class Invoice
    {
      public Invoice()
      {
         this.Lines = new List<InvoiceLine>();
      }
    
        [Reference]
        public Customer Customer { get; set; }
    
        [Child]
        public IList<InvoiceLine> Lines { get; private set; }
    
      [Child]
      public Address DeliveryAddress { get; set; }
    }                
    
    [Aggregatable]
    public class InvoiceLine
    {
      [Reference]
      private Product product;
    
      public decimal Amount { get; set; }
    }  
    
    [Aggregatable]
    public class Address
    {
    }
  3. Modify the code to use AdvisableCollection<T> and AdvisableDictionary<TKey, TValue> instead of standard .NET collections for children fields. This change is necessary because all objects assigned to children fields/properties must be aware of the Aggregatable pattern.

    In our code example, we need to modify the constructor of the Invoice class and assign an AdvisableCollection<T> to the Lines field instead of a List.

    C#
    public Invoice()
    {
       this.Lines = new AdvisableCollection<InvoiceLine>();
    }
  4. Optionally, add a field or property to link back from the child object to the parent, and add the ParentAttribute to this field/property. PostSharp will automatically update this field or property to make sure it refers to the parent object.

    In this example, we are adding a ParentInvoice property to the InvoiceLine class to link back to the Invoice class.

    C#
    [Aggregatable]
    public class InvoiceLine
    {
      [Reference]
      private Product product;
    
      public decimal Amount { get; set; }
    
      [Parent]
      public Invoice ParentInvoice { get; private set; }
    }
    Tip Tip

    For better encapsulation, setters of parent properties should have private visibility. In case of parent fields, the private visibility is preferred. User code should not manually set a parent field or property.

See Also