Search code examples
c#oopinheritanceinterfacefluent-nhibernate

Abstract classes and Fluent Nhibernate


My domain has an object called a Car. It has several properties

public abstract class Car : ICar
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Model { get; set; }
    public string Color { get; set; }
    public abstract string Drive();
}

it implements interface ICar

public interface ICar
{
    string Color { get; set; }
    int Id { get; set; }
    string Model { get; set; }
    string Name { get; set; }
    string Drive();
}

now I want there to be two inherited types. They inherit Car, and implement ICar.

class SportCar: Car, ICar
{
    public override string Drive()
    {
        return ("vroooomvroooomvroooomvroooom i'm a sports car - "+ Name);
    }
 }

and

class Truck: Car, ICar
{
    public override string Drive()
    {
        return ("grrrrrrrrrrrr i'm a sports truck- " + Name);
    }
}

So now i have two vehicles that fullfill the contract, and have a different way of driving.

cool

This works nicely, so elsewhere in my app I can have a method like this and we are happy

public string DoDrive(ICar c)
    {
        return c.Drive();
    }

But now I want my Car object to be persisted to a database using fluent nhibernate. I only want one table Car, and trucks and sportscars to be in the same table. I can create an enum to identify whether its a sportcar or truck. thats not a peoblem. but how to I map my car object.

I cant use an abstract class for nhibernate

thanks!


Solution

  • If you want all your cars to be persisted in the same table, you need to implement a mapping strategy called table per class hierarchy.

    First, map your abstract class as below:

    public class CarMap : ClassMap<Car>
    {
        public CarMap()
        {
            Id(x => x.Id);
            Map(x => x.Color);
            Map(x => x.Model);
            Map(x => x.Name);
            DiscriminateSubClassesOnColumn("Type");
        }
    }
    

    The table will have a "Type" column. This is called the discriminator column.

    Then map all your concrete classes. Each concrete class will have a "discriminator value":

    public class SportCarMap : SubclassMap<Car>
    {
        public SportCarMap()
        {
            DiscriminatorValue("SportCar");
    
            //If your Sport Car has specific properties:
            //Map(x => x.BrakeHorsePower);
        }
    }
    
    public class TruckMap : SubclassMap<Car>
    {
        public TruckMap()
        {
            DiscriminatorValue("Truck");
    
            //If your Truck has specific properties:
            //Map(x => x.MaxLoad);
        }
    }