4

I'm trying to build out an entity model and database closely based on the entities defined on http://www.schema.org using Code First and Migrations. The bottom line is all entities are inherited from an Entity "Thing".

Migrations build the database but any attempt to Seed the database fails.

Everything inherits from Thing:

    namespace Entities.Models
    {
                public class Thing
                {
                    public Thing()
                    {            
                        Id = Guid.NewGuid();
                        Name = String.Empty;
                    }

                    public Guid           Id               { get; set; }
                    public virtual string Name             { get; set; }

                }

            public class Person : Thing
            {
                public Person()
                    : base()
                {
                    Friends = new List<Person>();
                }

                public string GivenName { get; set; }
                public string FamilyName { get; set; }
                public string Email { get; set; }

                public virtual ICollection<Person> Friends { get; set; }
            }

            public class Event : Thing
            {
                public Event()
                    : base()
                {
                    Attendees = new List<Person>();
                }

                public virtual ICollection<Person> Attendees { get; set; }
                public TimeSpan Duration { get; set; }
                public DateTime? endDate { get; set; }
                public DateTime? StartDate { get; set; }

            }

        public class ThingMap : EntityTypeConfiguration<Thing>
        {
            public ThingMap()
            {
                // Primary Key
                this.Property(t => t.Id)
                    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

                // Properties
                this.Property(t => t.Name)
                    .IsOptional()
                    .HasMaxLength(200);

                // Table & Column Mappings
                this.ToTable("entity_Thing");
          }
       }
    public class PersonMap : EntityTypeConfiguration<Person>
    {
        public PersonMap()
        {
            // Properties
            this.Map<Person>(t =>
            {
                t.MapInheritedProperties();
                t.ToTable("entity_Person");
            });

            // Table & Column Mappings
        }
    }

    public class EventMap : EntityTypeConfiguration<Event>
    {
        public EventMap()
        {
            // Properties
            this.Map<Event>(t =>
            {
                t.MapInheritedProperties();
                t.ToTable("entity_Event");
            });

            // Table & Column Mappings
        }
    }

    public class CitriusSpotsContext : DbContext
    {
        static CitriusSpotsContext()
        {
            Database.SetInitializer<CitriusSpotsContext>(null);
        }

        public CitriusSpotsContext()
            : base("Name=CitriusSpotsContext")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new ThingMap());
            modelBuilder.Configurations.Add(new PersonMap());
            modelBuilder.Configurations.Add(new EventMap());
        }

        public DbSet<Thing> Things { get; set; }
        public DbSet<Person> People { get; set; }
        public DbSet<Event> Events { get; set; }
    }

}
John Palmer
  • 1,032
  • 1
  • 9
  • 23

2 Answers2

3

I am currently working with a similar model, I know this answer is late, but it may help.

To start, TPH, TPT, and TPC are mechanisms for modeling inheritance in our databases. If we do not need to model inheritance for polymorphic queries, updates, or saves, we do not need to follow the TP* conventions.

Let me restate that. TPH, TPT, and TPC are optional database inheritance modeling strategies. If our application does not require polymorphic queries, updates, or inserts, we do not need to follow the TP* conventions.

My basic project setup is very much like yours. In my project, I have an abstract class from which every class in my project inherits. It is named XModelBase and I believe it corresponds to your Thing class.

I use this abstract class to implement some base methods that wire my biz rule validation into Entity Framework's validation mechanism. This class also ensures auditing values are being captured for each and every entity and the class houses other universal properties (KeyId) as well as provides the prototype/template for universal processes.

The only real difference between our models is that my XModelBase has a int as the datatype for the primary key (which all classes subsequently inherit) while you are using a Guid datatype for your primary key.

If I am correct, you and I will never need to perform a query that looks like:

Scenario 1:

var query = from t in context.Things select t;

That type of query doesn't make sense in our scenario. Why would we want to select every object in our database? We wouldn't and we don't

We will also never save objects through our abstract class like:

Scenario 2:

var person = new Person() {Email = "something@somewhere.com"};
context.Things.Add(person);

Instead, we'd just do:

Scenario 3:

var person = new Person() {Email = "something@somewhere.com"};
context.People.Add(person);

Since we do not need to accommodate either Scenario 1 or Scenario 2, we don't need Things to be a separate base table (TPT). We also don't need or want to access or save our sub-classed tables in TPC's invisible polymorphic fashion; therefore, when you think about it, we really will never need the following property:

public DbSet<Thing> Things { get; set; }

We only need this DbSet property in our object context when we want/need to model polymorphic associations.

Removing that property from our context and getting rid of our model configuration for the base class is the first step to inheritance freedom.

Next, we will remove the MapInheritedProperties() from our subclasses model configurations because inherited properties will be mapped automatically. We just leave our .ToTable designation of our subclassed objects.

Again, I have an int for my XModelBase base classes primary key so I can simply mark it with the [Key] attribute like:

[Key]
public int KeyId { get; set; }

But because I am not creating a table or using DbSet for my XModelBase class, all of the inheriting sub-classes will have independent auto-incrementing primary keys that were configured with this one [Key] attribute in my XModelBase class.

If I understood your question correctly, this information should point you in the right direction, but if I didn't address your question, I'd be curious to know how you ended up resolving the issues.

Hope this helps!

Vesselin Obreshkov
  • 1,087
  • 11
  • 26
-2

It seems like you're working on a code-first approach, and you're trying to generate your schema as c# classes.

To use code-first, your base class must inherit from DbContext, and then you can build up proper methods for database communication.

In your case, Thing should be inherited from DbContext since it will be your repository, and then you can begin creating your Entities.

Entities are simple object classes, so you can inherit them from any other class. An example structure could be like this:

class Thing : DbContext
{
    public DbSet<Product> Products { get; set; }
}

class Product
{
    public int Id { get; set; }
    public int ProductName { get; set; }
}

For further information, http://weblogs.asp.net/scottgu/archive/2010/07/23/entity-framework-4-code-first-custom-database-schema-mapping.aspx and http://www.codeproject.com/Articles/318010/Entity-Framework-Code-First-Let-s-Try-It

Hope this will help.

Tequilalime
  • 611
  • 9
  • 29