Question

Getting an error when trying to set a ForeignKeyAttribute in a base class

class User { }

abstract class FruitBase
{    
   [ForeignKey("CreateById")]
   public User CreateBy{ get; set; }

   public int CreateById{ get; set; }     
}

class Banana : FruitBase { }

class DataContext : DbContext
{    
   public DbSet<Banana> Bananas { get; set; }
}

If I move the FruitBase code into the banana, all is well, but I don't want to, as there will be many many fruit and I want to remain relatively DRY if I can

Is this a know issue that will be fixed by March? Does anyone know a work around?

Was it helpful?

Solution

The problem caused by the fact that in your DbContext you put DbSet<Banana> instead of DbSet<FruitBase>. The following object model works as expected:

public class User 
{
    public int UserId { get; set; }
}

public abstract class FruitBase
{
    public int Id { get; set; }
    public int CreateById { get; set; }

    [ForeignKey("CreateById")]
    public User CreateBy { get; set; }
}

public class Banana : FruitBase { }

public class DataContext : DbContext
{        
    public DbSet<FruitBase> Fruits { get; set; }                
}

You have to be aware that by doing this, you are essentially creating a Polymorphic Association and as of CTP5, not all of the inheritance mapping strategies allow polymorphic association. Here it works fine because you've used Table per Hierarchy (TPH).

Update: Use Table per Type (TPT) Strategy:

Polymorphic Associations work with TPT as well:

public class StackoverflowTestContext : DbContext
{
    public DbSet<FruitBase> Fruits { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Banana>().ToTable("Bananas");
    }         
}

OTHER TIPS

as discussed above, this is TPC (Table per Concrete Type), the answer/work around here is to take the ForeignKeyAttribute out of the base

class User{}

abstract class AuditObjectBase{ // was FruitBase

   // [ForeignKey("CreateById")]
   public abstract User CreateBy{ get; set; } // made abstract

   public int CreateById{ get; set; } // both get and set required public

}

class ItemOne : AuditObjectBase{ // Was Banana

   // added
   [ForeignKey("CreateById")]
   public override User CreateBy{ get; set; }
}

class ItemTwo : AuditObjectBase{ // Added

   [ForeignKey("CreateById")]
   public override User CreateBy{ get; set; }
}

class DataContext : DbContext{

   DbSet<ItemOne> ItemOnes{ get; set; }
   DbSet<ItemTwo> ItemTwos{ get; set; }
}

Not completely DRY but at least when you create an object which uses the AuditObjectBase it will force you to implement the Foreign Key property, some nice comments to remind you of the attribute and away you go

Basically it seams, attributes should be added to the class declared in the DbContext as an Entity, in this case has a DbSet property.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top