How to: Model Horizontal Inheritance with the Visual Designer

This article is relevant to entity models that utilize the deprecated Visual Studio integration of Telerik Data Access. The current documentation of the Data Access framework is available here.

Horizontal inheritance can only be enabled for the topmost class in a hierarchy. Each immediate subclass is stored in its own table with a "copy" of the fields from the superclass. A horizontally mapped class itself, i.e. the superclass, does not have a table. Therefore, a horizontally mapped class cannot be directly persisted; only subclasses of the class can be stored in the database. For this reason, it is recommended (but not required) for horizontally mapped classes to be declared as abstract.

It is recommended (but not required) for horizontally mapped classes to be declared as abstract.

This topic demonstrates how to implement horizontal inheritance mapping with the Telerik Data Access Visual Designer.

  1. Create a new empty console application in Visual Studio.
  2. For this walkthrough, you will need to create a new empty database named AnimalKingdom on your server.
  3. Add a new Telerik Data Access Domain Model to your project. Name the domain model AnimalKingdomDomainModel. In the Select Domain Model Type Dialog, select the Empty Domain Model option.

  4. Click Finish to generate empty model. The next several steps demonstrate how to create a sample inheritance hierarchy in the Visual Designer.

  5. If the generated domain model is not opened in the Visual Designer, double click it in the Solution Explorer to open it.
  6. Next, you have to declare several entities in the Visual Designer. To add a new entity in the design surface, open the Toolbox and drag the Domain Class item onto the design surface. To add a new property to a domain class, right-click the target domain class, point to Add, and then click Property. Another way to add a new property is to right-click the Properties section in the domain class, and then select Add new Property. Add four entities with the following characteristics:

    1. Animal - this will be the base class in the hierarchy. It exposes the following properties:
      1. AnimalId - this is the primary key for the entity. The type of this property is Int32. The Identity property of AnimalId is set to True.
      2. Name - the type of this property is String.
    2. Dog - derives from Animal. Exposes the following properties:
      1. DogId - this is the primary key for the entity. The type of this property is Int32. The Identity property of DogId is set to True.
      2. Age - the type of this property is Int32.
    3. Cat - derives from Animal. Exposes the following properties:
      1. CatId - this is the primary key for the entity. The type of this property is Int32. The Identity property of CatId is set to True.
      2. LivesLeft - the type of this property is Int32.
    4. WienerDog - derives from Dog. Exposes the following properties:
      1. WienerDogId - this is the primary key for the entity. The type of this property is Int32. The Identity property of WienerDogId is set to True.
      2. Length - the type of this property is Decimal.
  7. Finally, your model should look like the snapshot below.

  8. The next step is to define inheritance associations. For that purpose, open the Toolbox pane (from the main menu, point View and select Toolbox). Select the Inheritance item.

  9. Select the objects to be included in the inheritance by clicking the derived entity first (Cat or Dog) on the design surface and then clicking the base entity on the design surface (Animal). Do the same for the WienerDog entity. However, it must derive from the Dog entity.
  10. When you specify all inheritance relationships, your model should look like the snapshot below:

  11. As you know, horizontal inheritance can only be enabled for the topmost class in a hierarchy. Each immediate subclass is stored in its own table with a "copy" of the fields from the superclass. In this walkthrough, there are two topmost classes - Animal and Dog. That's why you have to change the inheritance strategy for those classes.

  12. Select the Animal entity and open the Mapping Details Editor. Navigate to the Inheritance Mappings section. Change the Inheritance Strategy to Horizontal. Save your model.

  13. Now take a look at the entities in the Visual Designer. They have changed. All properties of the base Animal class are now copied to the Implementations section of all subclasses.

  14. The WienerDog class derives from the Dog class. So do the same steps for the Dog entity too. Select the Dog entity and open the Mapping Details Editor. Navigate to the Inheritance Mappings section. Change the Inheritance Strategy to Horizontal. Save your model.

  15. Now take a look at the entities in the Visual Designer. All properties of the base Dog class are now copied to the Implementations section of the WienerDog class.

  16. You have to create tables in the relational part of the model for each subclass. For the sake of simplicity, default mapping will be used. Select the Cat entity in the Visual Designer and open the Mapping Details Editor (View->Other Windows->Entity Diagrams Details Editor). In the Table Mappings section, check the Use Default Mapping option.

    Do the same for the WienerDog entity. Note, that for the Dog and Animal entities, the Use Default Mapping option is disabled.

  17. The only step left is to update the database with the changes made so far to the model. To do so, rebuild the project and start the Update Database from Model Wizard (right-click on an empty area in the Visual Designer and choose Update Database from Model). In the Setup Database Connection dialog specify a connection string to the AnimalKingdom database which was created on step 2. On the second page of the wizard, you need to select the Create Database strategy. On the Summary Page (the third page), you could review the generated script and execute it. Execute the script. For more information about the Update Database from Model wizard, take a look at How to: Update an Existing Database Schema.

  18. Spend some time to analyze the generated script. As you can see only two tables will be created - Cat and WienerDog. The Animal class is a base class in a horizontal inheritance hierarchy. That's why its fields will be copied in the Cat, Dog and WienerDog tables. However, the Dog entity is a base class too and its fields will be copied in the WienerDog table.

  19. The final SQL script is listed in the code-snippet below:

    -- HorizontalInheritanceDemo.Cat
    CREATE TABLE [cat] (
       [animal_id] INT NOT NULL,               -- Animal.animalId
       [nme] varchar(255) NULL,                -- Animal.name
       [cat_id] INT NOT NULL,                  -- catId
       [lives_left] INT NOT NULL,              -- livesLeft
       CONSTRAINT [pk_cat] PRIMARY KEY ([cat_id])
    )
    GO
    -- HorizontalInheritanceDemo.WienerDog
    CREATE TABLE [wiener_dog] (
       [animal_id] INT NOT NULL,               -- Dog.Animal.animalId
       [nme] varchar(255) NULL,                -- Dog.Animal.name
       [dog_id] INT NOT NULL,                  -- Dog.dogId
       [age] INT NOT NULL,                     -- Dog.age
       [wiener_dog_id] INT NOT NULL,           -- wienerDogId
       [lngth] NUMERIC(20,10) NOT NULL,        -- length
       CONSTRAINT [pk_wiener_dog] PRIMARY KEY ([wiener_dog_id])
    )
    GO
    
  20. Execute the generated script. Now you are ready to start working with your domain model.

    using (EntitiesModel dbContext = new EntitiesModel())
    {
       WienerDog dog = new WienerDog();
       dog.Age = 12;
       dog.AnimalId = 1;
       dog.DogId = 2;
       dog.WienerDogId = 3;
       dog.Name = "Jeff";
       dog.Length = 3;
       dbContext.Add(dog);
       dbContext.SaveChanges();
       foreach (WienerDog animal in dbContext.WienerDogs)
       {
           Console.WriteLine(animal.Name);
       }
    }
    
    Using dbContext As New EntitiesModel()
     Dim dog As New WienerDog()
     dog.Age = 12
     dog.AnimalId = 1
     dog.DogId = 2
     dog.WienerDogId = 3
     dog.Name = "Jeff"
     dog.Length = 3
     dbContext.Add(dog)
     dbContext.SaveChanges()
     For Each animal As WienerDog In dbContext.WienerDogs
      Console.WriteLine(animal.Name)
     Next animal
    End Using