9

While modelling my domain classes, I found that Entity Framework lets you model inheritance relationships, but doesn't support promoting a base type instance to its derived type, i.e. changing an existing Person row in the database to an Employee, which derives from Person.
Apparently, I wasn't the first to wonder about this, because this question has been asked and answered on Stack Overflow multiple times (e.g. see here and here).

As indicated in these answers, Entity Framework doesn't support this because this isn't allowed in Object-Oriented Programming either: once an instance is created, you cannot change its run-time type.
Fair enough, from a technical perspective I can understand that once a single block of memory is allocated for an object, tacking on a few extra bytes afterwards to hold the derived type's fields in will probably require the entire memory block to be reallocated, and as a consequence, will mean that the object's pointer has now changed, which in turn introduces even more problems. So I get that this would be difficult to implement, and therefore not supported in C#.

However, aside from the technical component, the answers (and here too, see final paragraph on page 1) also seem to imply that it is considered bad design when you want to change an objects run-time type, saying that you shouldn't need this kind of type-changing and should use composition for these situations instead.

Frankly, I don't get why - I'd say its perfectly valid to want to work Employee instances in the same way as you would with a Person instance (i.e. by inheriting Employee from Person), even if at some point in time a Person will be hired as an Employee, or an Employee quits and becomes a Person again.
Conceptually, I don't see anything wrong with this?

Can anyone explain this to me?

--Edit, to clarify, why is this considered bad design:

public class Person
{
    public string Name { get; set; }
}

public class Employee: Person
{
    public int EmployeeNr { get; set; }

    public decimal Salary { get; set; }
}

...but this isn't?

public class Person
{
    public string Name { get; set; }

    public EmployeeInfo EmployeeInfo { get; set; }
}

public class EmployeeInfo
{
    public int EmployeeNr { get; set; }

    public decimal Salary { get; set; }
}
Community
  • 1
  • 1
Leon Bouquiet
  • 4,159
  • 3
  • 25
  • 36
  • The use of Interfaces can also allow you to enforce some rules on your Classes. – GameAlchemist Jan 26 '14 at 12:52
  • Think about this: how would you correctly set the extra properties an `Employee` may have? For example, if each `Employee` has a `Salary` property, how would you be able to promote an arbitrary `Person` to a *valid* `Employee` if you do not know its salary? More generally: when designing by contract, how would you fulfil the additional rules imposed on an `Employee` instance (e.g. having a valid salary)? – Mattias Buelens Jan 26 '14 at 12:53
  • @MattiasBuelens: I'm not talking about using an arbitrary Person in the place where an Employee is expected, I'm wondering why I shouldn't model Employee as a subclass of Person but rather as an aggregate? – Leon Bouquiet Jan 26 '14 at 13:18
  • Who says your code (`public class Person { public string Name { get; set; } } public class Employee: Person { public int EmployeeNr { get; set; } public decimal Salary { get; set; } }`) is bad design? To me it looks uncontroversial. Where is the problem? – Jeppe Stig Nielsen Jan 26 '14 at 13:54
  • @Jeppe because you fix the trait of being employable to a human, which may not hold true in the future. It is, as usual, a quite badly connecting real-world OO example, but I tried to address the issue in my answer. – CodeCaster Jan 26 '14 at 13:57
  • @CodeCaster I am not sure I get it. Is this about the semantics of persons and employees? Or will it in general be bad design to use inheritance? The only thing the derived class does is introduce two additional properties. Of course if you choose to let your class `C` derive from another class `B`, then you "fix" all `C` to be also `B`, but is that controversial? **EDIT:** Ah, this is specific for objects that are to be stored in a database? – Jeppe Stig Nielsen Jan 26 '14 at 14:13
  • @Jeppe it _can be_. If the inheritance tree has to change often or causes limitations because of this design (see multiple inheritance questions), you _can be_ better off using composition. A good example of bad inheritance not involving robots would be `Edible` (`Eatable`?) inheriting from `Fruit`, like that's the only thing you can eat. If your only concern is fruit you may not notice it and it may never cause any trouble, but it's a less optimal design for reuse nevertheless. – CodeCaster Jan 26 '14 at 14:19
  • @Jeppe it's not really database specific, but about the design in general. I just can't figure out in what situation one would ever (practically) use `Employee employee = (Employee)new Person();`. – CodeCaster Jan 26 '14 at 14:30

3 Answers3

2

Consider this code:

Person person   = new Person { Name = "Foo" };
Person employee = new Employee { Name = "Bar", EmployeeNr = 42 };

However employee is declared as Person, the actual instance it is referring to is of type Employee. This means you can cast it to that:

Employee employee2 = (Employee)employee;

When you try that with person:

Employee employee3 = (Employee)person;

You'll get an exception in runtime:

Unable to cast object of type 'Person' to type 'Employee'.

So you're right in that this is a technical impossibility, as C# is implemented. You can work around it though, by creating a constructor in Employee:

public Employee(Person person, int employeeNr, decimal salary)
{
    this.Name = person.Name;
    EmployeeNr = employeeNr;
    Salary = salary;
}

As you see, you'll have to instantiate the Person part of the Employee yourself. This is tedious and error-prone code, but now we come to your actual question: why could this be considered a inferior design?

The answer lies in favoring composition over inheritance:

Composition over inheritance (or Composite Reuse Principle) in object-oriented programming is a technique by which classes may achieve polymorphic behavior and code reuse by containing other classes that implement the desired functionality instead of through inheritance.

The essence:

To favor composition over inheritance is a design principle that gives the design higher flexibility, giving business-domain classes and more stable business domain in the long term. In other words, HAS-A can be better than an IS-A relationship.

To keep in the terms of your real-world example: in the future, we might have to employ Androids, who definitely don't inherit from Person, but could use a EmployeeInfo record.


As for your Entity Framework specific question:

I'd say its perfectly valid to want to work Employee instances in the same way as you would with a Person instance (i.e. by inheriting Employee from Person), even if at some point in time a Person will be hired as an Employee, or an Employee quits and becomes a Person again.

If, for now, you know you're only going to employ humans (don't forget YAGNI), I cannot imagine an example where this issue would come up. When you want to show all persons, you iterate that repository:

using (var context = new MyContext())
{
    foreach (var person in context.Persons)
    {
        PrintPerson(person);
    }
}

And when you want to list all employees, you do exactly the same, but with the Employee repository:

using (var context = new MyContext())
{
    foreach (var Employee in context.Employees)
    {
        PrintEmployee(Employee);
    }
}

And if in some cases you want to know whether someone is an employee, you'd have to hit the database again:

public Empoyee FindEmployeeByName(string name)
{
    using (var context = new MyContext())
    {
        return context.Employees.FirstOrDefault(e => e.Name == name);
    }
}

Which you can then call using a Person instance:

Empoyee employee = FindEmployeeByName(person.Name);
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Thanks for the clarification on favouring composition over inheritance, I didn't know there was a wikipedia article on that... – Leon Bouquiet Jan 27 '14 at 14:22
2

You are over-analyzing this. Polymorphism is very well supported in .NET and there's never any way that you can unsafely upcast, a friendly InvalidCastException is always there to remind you that you got it wrong. It can even be safely done in C++ (dynamic_cast<>), not exactly a language well-known for a lack of ways to shoot your leg off.

The runtime support for it is the key. Dbase engines don't have any.

It was the playground for venture capital around the turn of the century. Already flowing freely thanks to the dot com boom. Objected oriented databases where promised as jet-packs for everybody. But that busted too, none of them ever close to being dominant. Ever heard of Gemstone, db4o, Caché, odbpp? Competing with existing engines is a tall task, performance and reliability is everything in that market segment and it is very hard to catch up to 20 years of fine-tuning. So there was just no point in adding support for it in a data access layer.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • In the sentence 'never any way that you can unsafely upcast, a friendly InvalidCastException..'. Should 'upcast' be 'downcast'? Incorrect upcasting gives a compiler error. Unsafe downcasting gives the InvalidCastException. Might just be that I am reading it wrong. – acarlon Jan 26 '14 at 21:43
  • Both terms are used. Gravity tends to ensure that the "base" of something is at the bottom. – Hans Passant Jan 26 '14 at 22:21
  • Ah, OK. Confusing. I always got told off for using down/upcast in the more intuitive gravitational way. – acarlon Jan 26 '14 at 22:28
2

Frankly, I don't get why - I'd say its perfectly valid to want to work Employee instances in the same way as you would with a Person instance (i.e. by inheriting Employee from Person), even if at some point in time a Person will be hired as an Employee, or an Employee quits and becomes a Person again. Conceptually, I don't see anything wrong with this?

I understand this as Person -> Employee -> Person? IE it is still a person but he/she/it gets attributed with "employment" and then "downgraded" to just a person?

Inheritance is very useful when the object does not change type during runtime, for example when you create an equity-object you can be quite sure you do not want to turn it into an FRA, even though both are subclasses of securities. But whenever something might change during runtime, such as behaviour, try using composition instead. In my previous example, the security subclasses might inherit from a top-level asset class, but the methods used for putting a market value on an asset should be put there by a behavioral pattern, such as the strategy pattern, since you might want to use different methods during one runtime.

For the case you are describing you should not use inheritance. Always favor composition over inheritance whenever possible. If something changes during runtime, it should definitely not be put there by inheritance!

You could compare it to lives, a human is born a human and dies a human, a cat is born a cat and dies a cat, an object of a certain type should be created as one type and garbage collected as the same type. Don't change what something is, change how it behaves or what it knows, through behavioral composition.

I would recommend you to have a look at Design Patterns: Elements of Reusable Object-Oriented Software which quite thoroughly covers some very useful design patterns.

flindeberg
  • 4,887
  • 1
  • 24
  • 37
  • So if I understand correctly, it is because it's much easier to change behaviour at runtime through composition than it is through inheritance that one should lean towards composition? For behaviour that doesn't need to change during the lifetime of an AppDomain, inheritance would be fine? – Leon Bouquiet Jan 27 '14 at 14:21
  • @Astrotrain That is exactly what i mean :) – flindeberg Jan 28 '14 at 08:42