How to use abstract classes in EF - entity-framework

I have a DbContext class like
abstract public class CostCenter
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
abstract public Guid ID
{
get;
set;
}
abstract public string CostCenterName
{
get;
set;
}
}
but i cannot run add-migration and update-database commands its give me error , note abstract class is my need here ,

You should derive a new class from CostCenter and add the derived class as a DbSet to your DbContext.
Examples:
[Table("SomeCostCenter")]
public class SomeCostCenter : CostCenter
{
}
And:
[Table("AnotherCostCenter")]
public class AnotherCostCenter : CostCenter
{
}
And, on your DbContext:
DbSet<SomeCostCenter> { get; set; }
DbSet<AnotherCostCenter> { get; set; }
Note that these are set up to use Table-Per-Type (TPT) inheritance to store each derived type in a separate table. There are other options for this such as Table-Per-Hierarchy (TPH) or Table-Per-Concrete class (TPC). You can search on each of these terms to determine which works best in your scenario.
This might be worth a quick read:
http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph

Related

Entity Framework: Inherit from Custom DbContext

Is it possible to inherit a custom DBContext and then modify the entities of the inherited context has without modifying the base tables with discriminator columns?
public class BaseDbContext: DbContext {
public IDbSet<BaseClass> BaseClasses { get; set; }
}
public class BaseClass {
public int Id { get; set; }
etc...
}
public class NewDbContext: BaseDbContext {
public IDbSet<NewBaseClass> NewBaseClasses { get; set; }
}
public class NewBaseClass: BaseClass {
public string SomePropertyName { get; set; }
}
I have a project that is setup for a base database structure use the BaseDbContext. If I created a new database with the same schema and added a column to the BaseClasses table called SomePropertyName. I want to create a new DbContext that derives from the BaseDbContext, and then add the extra property to the new class, NewBaseClass.
Any guidance would be greatly appreciated.

DevExpress XAF EF with TPC , abstract class is only visible in model designer at run time

I want to use Table Per Concrete Class as the inheritance strategy for my XAF Code First EF project.
I use the wizard to create the project and then paste in classes from the following
namespace Solution12.Module.BusinessObjects {
public abstract class BaseBO // abstract class helpful in getting TPC
{
[Key]
public int Id { get; set; }
public string Description { get; set; }
}
[NavigationItem("People")]
[Table("People")] // explicit table name is helpful in preventing TPH
public class Person : BaseBO
{
public string PersonName { get; set; }
}
[NavigationItem("Organisation")]
[Table("Organisations")]
public class Organisation : BaseBO
{
public string OrganisationName { get; set; }
}
public class Solution12DbContext : DbContext {
...
public DbSet<Organisation> Organisations{ get; set; }
public DbSet<Person> People { get; set; }
//public DbSet<BaseBO> baseBOs { get; set; } // having this will cause TPT instead of TPC
}
}
This all works as I want, to create the database structure.
However I cant see the abstract class in the model designer at design time.
I can see the abstract class and it's views in the model designer at run time.
How can I get the model designer to show the abstract class BaseBO at design time?
This is a significant issue for us because run-time customizations are stored in the database and hence not part of our source control.
A ticket for this problem can also be found at Dev Express Support here however this is a more concise statement of what we now understand to be the problem.
It seems that if we pop the following into each concrete class then we get the desired behavior
[NotMapped]
public BaseBO BaseBo {
get
{
return (BaseBO)this;
}
}

Entity Framework 6 Table per Hierarchy (TPH) bug

I've created an abstract class with some base properties:
public abstract class BaseModel
{
public BaseWishModel()
{
}
[Key]
public int Id { get; set; }
public virtual string Title { get; set; }
public bool IsPublished { get; set; }
public bool IsSpam { get; set; }
}
My item class:
public class PrivateItem : BaseModel
{
[NotMapped]
public string PurposesIds { get; set; }
}
My OnModelCreating method:
modelBuilder.Entity<BaseModel>()
.Map<PrivateItem>(r => r.Requires("Discriminator").HasValue((int)Enums.Type.Private))
.ToTable("Items");
When I save the data it's generates next sql:
INSERT [dbo].[Items]([Title], [IsPublished], [ShortDescription1], [ShortDescription2], [Discriminator])
I don't know why it's generates ShortDescription1 and ShortDescription1
As, according to your comment, you have other classes inheriting from BaseModel, and with no other configuration from you, EF uses TPH by default.
Basically this leads to a single table for all the classes hierarchy.
As all classes of the hierarchy are persisted in the same table when an insert, for one class, is done, all columns (of the hierarchy) are populated. The non used by the class columns are populated by null or default value.
This bring the ShortDescription1 and ShortDescription2 in your insert query.

Entity Framework Eager Loading Table-Per-Type Inheritance derived class

Using a table-per-type inheritance model and Entity Framework Code First, I am trying to eager load a list of derived class. Please note that I can't change the model.
I have the following model (overly simplified)
public class Training
{
public string Name { get; set; }
public IList<Person> Persons { get; set; }
}
public abstract class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
[Table("Students")]
public class Student : Person
{
public string StudentNumber { get; set; }
public IList<Training> Trainings { get; set; }
}
[Table("Instructors")]
public class Instructor : Person
{
public DateTime StartingDate { get; set; }
public IList<Training> Trainings { get; set; }
}
I want to query Training by name and eager load all the persons including the derived class (Student and Instructor). Back in April 2011, Tom Dykstra seemed to claim it wasn't possible.
The current version of the Entity Framework doesn't support eager loading for one-to-zero-or-one relationships when the navigation property is on the derived class of a TPH inheritance structure.
Has this changed? I am using EF5.
I don't see why ...
var list = context.Trainings.Include(t => t.Persons)
.Where(t => t.Name == someName)
.ToList();
... shouldn't work. EF should populate the Persons list with concrete Student and Instructor entities.
You neither have a "one-to-zero-or-one relationship" nor is your navigation property (Training.Persons) "on the derived class". So, I think the mentioned limitation does not apply to your model and query.

Multiple inheritance with Entity Framework TPC

I tried to map some classes using Entity Framework in TPC style and got the following error:
Error: The type 'A' 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.
This error occurs when I use the following classes:
public abstract class BaseEntityTest
public abstract class BaseEntityTest2 : BaseEntityTest
public abstract class BaseEntityTest3 : BaseEntityTest2
public class A: BaseEntityTest3 // this class is the only one with a table in the db
In the OnModelCreating method I added the following code to get the TPC mapping
modelBuilder.Entity<A>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("A");
});
When I exclude BaseEntityTest2 from the structure (so that A inherits only from BaseEntityTest instead of BaseEntityTest2) the error goes away. Does that mean that it is not possible to create this mapping or do I just miss something?
EDIT:
Properties of classes:
public abstract class BaseEntityTest
{
[Key]
public Guid Id { get; set; }
public String Info { get; set; }
[Required]
public DateTime CreationDate { get; set; }
[Required]
public String CreationUser { get; set; }
[Required]
public DateTime ModificationDate { get; set; }
[Required]
public String ModificationUser { get; set; }
[ConcurrencyCheck]
[Required]
public int LockVersion { get; internal set; }
}
public abstract class BaseEntityTest2 : BaseEntityTest
{
[Required]
public string Name { get; set; }
public string Description { get; set; }
}
public abstract class BaseEntityTest3: BaseEntityTest2
{
[Required]
public DateTime FromDate { get; set; }
public DateTime ThruDate { get; set; }
}
public class A: BaseEntityTest3{
public String Test { get; set; }
}
The error occurs for EF 4.3.1 and earlier versions, but not for EF 4.4 and EF 5.0. (EF 4.4 is actually EF 5.0, but with .NET 4.0 as target platform.)
BUT: The error occurs only if you are using your abstract classes as entities in your model, that means
you either have DbSets for them in your context class, like
public DbSet<BaseEntityTestX> BaseEntityTestXs { get; set; }
or you have some Fluent mapping for BaseEntityTestX, some modelBuilder.Entity<BaseEntityTestX>()... stuff
or you are using one of the BaseEntityTestX as a navigation property in another (concrete) entity type
Do you need any of this?
Having a DbSet<BaseEntityTestX> in your context would only make sense if you really want to query for one of the abstract entities, like:
List<BaseEntityTest> list = context.BaseEntityTests
.Where(b => b.Info == "abc").ToList();
The result is of course a list of concrete entities that inherit from BaseEntityTest, but it can be a mix of different types, like some As and some Bs. Do you need such queries? Or do you only want to query for some of the concrete objects:
List<A> list = context.As
.Where(b => b.Info == "abc").ToList();
In the latter case you don't need a DbSet for the abstract base classes and you don't need any inheritance mapping. You can just remove the DbSet<BaseEntityTestX> from your context class and remove the TPC mapping and your error will go away.
The last point - having a navigation property to one of the abstract entities in another entity - doesn't make sense with TPC mapping. It is just not mappable to a relational database because with TPC mapping there is no table for the abstract entity, hence there is no target the foreign key relationship could refer to from the table of the concrete class that has the navigation property.
The error will also disappear if you extend your TPC mapping to the base classes:
modelBuilder.Entity<BaseEntityTestX>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("BaseEntityTestX");
});
But it will create tables for those abstract entities that don't seem to make sense to me.
in EF6.0 its happed when
EntityTypeConfiguration'<'YourBaseClass'>'
did not detailed ALL your derived class with
this.Map<DerivedClass1>(m =>
{
m.MapInheritedProperties();
m.ToTable("..");
});
if just one dervied class in the assembley not configured like so
you get this exception