views:

98

answers:

1

I am trying to figure out something with EF4 Code Only. If i use TPH and i wanted to change a saved Person to Instructor or vice versa, how would i accomplish this. My POCO classes:

    public class Person
{
    public int PersonId { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
}
public class Instructor : Person
{
    public DateTime? HireDate { get; set; }
}

public class Student : Person
{
    public DateTime? EnrollmentDate { get; set; }
}

public class Admin : Person
{
    public DateTime? AdminDate { get; set; }
}

public class PersonConfiguration : EntityConfiguration<Person>
{
    public PersonConfiguration()
    {
        this.HasKey(u => u.PersonId).Property(u => u.PersonId).IsIdentity();
        MapHierarchy()
            .Case<Person>(p => new
            {
                p.PersonId,
                p.FirstName,
                p.LastName,                    
                PersonCategory = 0
            })
            .Case<Instructor>(i => new
            {

                i.HireDate,
                PersonCategory = 1
            })
            .Case<Student>(s => new
            {
                s.EnrollmentDate,
                PersonCategory = 2
            })
            .Case<Admin>(a => new
            {

                a.AdminDate,
                PersonCategory = 3
            }).ToTable("Person");

    }
}

Lets say i have a person:

var person1 = new Person { FirstName = "Bayram", LastName = "Celik" };
context.People.Add(person1);
context.SaveChanges();

Later on i want to make this person an admin. How would i accomplish this.

var person = context.People.FirstOrDefault();
Admin test = person as Admin; // wont work

following will change the HireDate column but my discriminator field PersonCategory is still 0. So it is still not an Admin type as far as EF concerns

Admin admin = new Admin();
admin.PersonId = person.PersonId;
admin.AdminDate = DateTime.Now;

context.ObjectContext.Detach(person);
context.People.Attach(admin);
var customerEntry = context.ObjectContext.ObjectStateManager.GetObjectStateEntry(admin);
customerEntry.SetModified();
customerEntry.SetModifiedProperty("AdminDate");
A: 

You can't ever change the type of an object. You can't do it in C#, and the EF doesn't work around this. This is a fundamental principle of OOP.

Instead, you need to fix your model design. As I wrote a while back:

One of the mental barriers that you have to get over when designing a good object relational mapping is the tendency to think primarily in object oriented terms, or relational terms, whichever suits your personality. A good object relational mapping, though, incorporates both a good object model and a good relational model. For example, let’s say you have a database with a table for People, and related tables for Employees and Customers. A single person might have a record in all three tables. Now, from a strictly relational point of view, you could construct a database VIEW for employees and another one for customers, both of which incorporate information from the People table. When using a one VIEW or the other, you can temporarily think of an individual person as "just" an Employee or "just" a Customer, even though you know that they are both. So someone coming from this worldview might be tempted to do an OO mapping where Employee and Customer are both (direct) subclasses of Person. But this doesn’t work with the data we have; since a single person has both employee and customer records (and since no Person instance can be of the concrete subtype Employee and Customer simultaneously), the OO relationship between Person and Employee needs to be composition rather than inheritance, and similarly for Person and Customer.

Craig Stuntz
Thanks for the detailed explanation. I did take code from all in one framework http://1code.codeplex.com/ . And could not resist the thought to try what i was trying.
Bcelik

related questions