7

I have a DbContext with set up different DbSet<T>s with all types that derive from the same base class:

public class Foo : Entity { }
public class Bar : Entity { }

MyDbContext : DbContext
{
  public DbSet<Foo> Foos { get; set; }
  public DbSet<Bar> Bars { get; set; }
}

Is it possible to get all entities which have the Entitybase class in one query, like:

DbContext.Set<Entity>();  // doesn't work

I tried to introduce an explicit DbSet<Entity> to the DbContext, but that results in one big table for all entities in the database.

Additional question: If this works somehow, what about querying for interfaces?

Edit:

I followed the instructions on Ladislav Mrnka's link and did my mappings like follows:

MyDbContext : DbContext
{
  public DbSet<Entity> Entities { get; set; }

  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    // Foo
    modelBuilder.Entity<Foo>().Map(x =>
    {
      x.MapInheritedProperties();
      x.ToTable("Foo");
    })
    .HasMany(x => x.Tags).WithMany();

    modelBuilder.Entity<Foo>()
        .Property(x => x.Id)
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

    // Bar
    // same thing for Bar and a bunch of other Entities

    base.OnModelCreating(modelBuilder);
  }
}

This throws now the error

The property 'Id' is not a declared property on type 'Foo'. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property.

I also tried to set the Key explicitly to the Id property:

modelBuilder.Entity<Foo>().Map(x => {...})
  .HasKey(x => x.Id)
  .HasMany(x => x.Tags).WithMany();

What am I missing?

davehauser
  • 5,844
  • 4
  • 30
  • 45
  • Take a look here: http://stackoverflow.com/q/353284/114029 – Leniel Maccaferri Apr 28 '11 at 13:15
  • Thanks for the link. But seems like this is an answer using the database-first approach wheras I'm looking for a solution with the code-first approach. Maybe am I missing something here, but I don't find any hint for my problem. – davehauser Apr 28 '11 at 13:22

2 Answers2

4

You need to introduce TPC inheritance. After that DbContext.Set<Entity>() will work and you will still have table per entity.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • Thanks, hoped you would see my question ;-) Looks like what I'm looking for, but haven't got it work yet, fighting with a bunch of errors... right now with _The property 'Id' is not a declared property on type 'Foo'..._. Id is declared in the base class, any idea? – davehauser Apr 28 '11 at 18:06
  • Sounds like you forgot to use `MapInheritedPropeties` but hard to say when I don't see your mappings. – Ladislav Mrnka Apr 28 '11 at 18:15
  • I just updated my question with the mappings I tried. Did not forget `MapInheritedProperties`, think I followed the instructions exactly... Maybe I have some additional "special requirements" with my entities... :-) – davehauser Apr 28 '11 at 19:03
  • Since this gave me the answer to my original question I set this as my accepted answer. Thanks. – davehauser Apr 28 '11 at 23:17
2

Just to your problem in your Edit section:

The error message indicates that you have the Id key property in your base class Entity. Then you need to configure the key property on this class and not on the derived Foo class:

modelBuilder.Entity<Entity>()
    .Property(x => x.Id)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Slauma
  • 175,098
  • 59
  • 401
  • 420
  • Makes sense. Now I get the next error: _The type 'Foo' cannot be mapped as defined because it maps inherited properties from types that use entity splitting or another form of inheritance. Either choose a different inheritance mapping strategy so as to not map inherited properties, or change all types in the hierarchy to map inherited properties and to not use splitting._ :-) – davehauser Apr 28 '11 at 19:53
  • @Dave: No clue, I've never seen this exception. It's likely that it has to do with this part of your mapping of foo: `.HasMany(x => x.Tags)`. What is `Tag`? Is it also derived from your base class? Did you also define TPC mapping for this type? – Slauma Apr 28 '11 at 20:10
  • Hm, another interpretation: *"it maps inherited properties from types that use ... another form of inheritance"* So, the "types" which `Foo` inherits from is your base class `Entity`. This type uses "another form of inheritance" which could mean that there is another from `Entity` derived type `Foo2` which doesn't map inherited properties. If you didn't configure the mapping for `Foo2` it uses TPH ("another form of inheritance") by default and not TPC. This could mean that you need to configure TPC explicitely for **all** types in the hierarchy to get rid of the exception. – Slauma Apr 28 '11 at 20:21
  • @Slauma: Tag is also derived from my base class. I also had the suspicion that this could cause the error, so I tried the same with a type `Tag` that doesn't derive from `Entity`. I defined these mappings for all of my types that derive from the base class (including `Tag`). Entity implements two interfaces, maybe that is the problem? – davehauser Apr 28 '11 at 20:57
  • @Dave: I don't think that the interfaces are a problem. I think you need to simplify your model step by step in an test environment and look when the error disappears. Without seeing your full model it's hard to say what could be wrong. And perhaps make a new question about this problem to get more attention. – Slauma Apr 28 '11 at 22:35
  • @Slauma: Thanks for your effort! – davehauser Apr 28 '11 at 23:16