Domain driven design would not have been complete if inheritance strategies were not integrated into Rapid. Rapid now supports several inheritance strategies namely :
  • Discriminatory Inheritance (Table Per Hierarchy (TPH)): : This strategy maps subclasses to a single entity base class using Discriminatory standards. Child entities are mapped with DiscriminatorValue("Discriminator", "NonPerishable") attribute, the first parameter is the column which will discriminate the subclass, the second parameter is the value inserted into the discriminator table. For example, if we have a Person class and we want Employee and Customer classes to inherit from the Person class using the discriminatory strategy, we would mark the Person class with Entity attribute, and then we would map both the Employee and Customer classes with the discriminator attribute : More details can be found here Discriminatory Relationship
  • Table per subclasses in hierarchy : This inheritance strategy allows for subclasses to be mapped as entity and the parent class not mapped at all. This gives us the abilities to maintain shared properties within the base class. For example if our Person class is not mapped with entity attribute, and our Employee and Customer classes are mapped with entity properties, suppose there is a property called FirstName which is common to both classes, the best place to put such property, would be in the parent Person class.
  • Table Per Type (TPT) : This inheritance strategy will be the talk of this page and its an added feature to Rapid to ensure it conforms to Object mapping standards. This allows all Parent and child classes to be mapped as entities to different tables. The parent class owns the primary keys while the child classes hold foreign keys. Given the following inheritance structure :

Base Class

    [Entity("Person")]
    public partial class Person {
        
        private String firstname;                
        private Int32 personid;
        
        
        [Field("FirstName")]
        public virtual String FirstName {
            get {
                return firstname;
            }
            set {
                this.firstname = value;
            }
        }
                
        [Key("PersonId", AutoKey=true)]
        public virtual Int32 PersonId {
            get {
                return personid;
            }
            set {
                this.personid = value;
            }
        }        
    }


Subclass
    [Entity("Employee", RelationColumn = "PersonId")]
    public partial class Employee : Person {
        
        private String employeenumber;        
        private String grade;
                
        [Field("EmployeeNumber", Exclude = "Cancelled")]
        public virtual String EmployeeNumber {
            get {
                return employeenumber;
            }
            set {
                this.employeenumber = value;
            }
        }
        
        [Field("Grade")]
        public virtual String Grade {
            get {
                return grade;
            }
            set {
                this.grade = value;
            }
        }
}

Explanation

If you notice the Person class, it has a property PersonId which is attributed as the Key using Rapid attribute. This class will be the one to hold the primary keys in the inheritance. Only the base class holds the key.

Now all said and done, if you notice the child class Employee , it is also mapped with entity attribute, but with an extra attribute property RelationColumn , this relation column is required if the name of joining column (That is the foreign key in the Employee table ) is different from the primary key in the Person table. For the above mapping, the PersonId key property in the Person class is the same name as the RelationColumn = "PersonId" in the Employee class. This can be re mapped as follows because Rapid will reuse the parent primary key name if you do not specify a RelationColumn in the sublasses entity mapping :


    [Entity("Employee")]
    public partial class Employee : Person {
        
        private String employeenumber;        
        private String grade;
                
        [Field("EmployeeNumber", Exclude = "Cancelled")]
        public virtual String EmployeeNumber {
            get {
                return employeenumber;
            }
            set {
                this.employeenumber = value;
            }
        }
        
        [Field("Grade")]
        public virtual String Grade {
            get {
                return grade;
            }
            set {
                this.grade = value;
            }
        }
}


The above code will still work, so far the primary key column in the Parent PersonId is the same as the Foreign key column in the Employee table. All that said and done. Table per classes in hierarchy was a contribution by Shawn Shaddock. Thanks again.

Last edited Feb 7, 2010 at 6:58 PM by ahmedsalako, version 13

Comments

No comments yet.