Add TPT Inherited Code First Model to Linq Fluent API - entity-framework

I'm having problems extending the Fluent API to my inheritance classes. I have taken the TPT (table per type) method and each type of the inheritance has a table. I like table per type because the database is fully normalized and easy to maintain. I am not getting the inherited model ServiceCompany to work with the Fluent API.
Base Abstract Class
public abstract class Vendor
{
[Key]
public int VendorID { get; set; }
[Required]
public string CompanyName { get; set; }
[Required]
public int StreetNumber { get; set; }
[Required]
public string StreetName { get; set; }
}
Inherited ServiceCompany Class from Vendor
[Table("ServiceCompanies")]
public class ServiceCompany : Vendor
{
public string ACHClaim { get; set; }
public virtual ICollection<SubContractorCompany> SubContractorCompanies { get; set; }
public virtual ICollection<ServiceCompanyUser> SubContractorUsers { get; set; }
}
Where I added the entity models to enable the Fluent API with onModelCreating()
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<Vendor> Vendors { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ServiceCompany>().ToTable("ServiceCompanies");
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I would like to be able to do something like this with the fluent API.
var ListofServiceCompanies = db.ServiceCompanies.All()
and not like this
var ListofServiceCompanies = db.Vendor.SelectMany( Vendor is a ServiceComapny...etc)
I prefer to set up the entities correctly and make the code nice and easy to use. Any insight or knowledge is appreciated.

You can do that by calling OfType extension method like below:
var ListofServiceCompanies = db.Vendor.OfType<Vendor>().ToList();
Or you can just add a DbSet<ServiceCompany> ServiceCompanies { get; set; } into your DbContext so it will look like this:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<Vendor> Vendors { get; set; }
public DbSet<ServiceCompany> ServiceCompanies { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ServiceCompany>().ToTable("ServiceCompanies");
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Then just call:
var ListofServiceCompanies = db.ServiceCompanies.ToList();

Related

How to configure a one-to-one relationship with identity class and two db context

Let me try to explaine. I have 2 classes, one class called ApplicationUser that inherit from IdentityUser to insert some properties and one class called Company. I would like to create a one-to-one relationship between both to allow me to access the user and navigate to his companies. I am using 2 different dbContext, one for the identity and one for the rest of entities so i don't know how and which dbContext should i configure it. Could you please assist me?
THAT IS MY APPLICATIONUSER CLASS:
`
public class ApplicationUser : IdentityUser
{
public string Fullname { get; set; }
public override string Email { get => base.Email; set => base.Email = value; }
public string UplandUsername { get; set; }
public DateTime Nascimento { get; set; }
public decimal Saldo { get; set; }velEnum UplandLevel { get; set; }
public string FotoPerfil { get; set; }
public Company Company { get; set; } // RELATION HERE
}
`
THAT IS MY COMPANY CLASS:
`
public class Company : BaseEntity
{
public string Name { get; set; }
public string Country { get; set; }
public string Department { get; set; }
public string Usuario_Id { get; set; } // REFERENTIAL USER ID
public ApplicationUser User { get; set; } // RELATION HERE
}
`
THAT IS MY DBCONTEXT OF IDENTITY:
`
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
{
}
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) { }
}
`
THAT IS MY DBCONTEXT OF THE REST OF ENTITIES, INCLUDING COMPANY:
`
public class MagnatumDbContext : DbContext
{
public MagnatumDbContext(DbContextOptions<MagnatumDbContext> options) : base(options) { }
public DbSet<Company> Companies { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(e => e.GetProperties()
.Where(p => p.ClrType == typeof(string))))
property.SetColumnType("varchar(100)");
modelBuilder.ApplyConfigurationsFromAssembly(typeof(MagnatumDbContext).Assembly);
base.OnModelCreating(modelBuilder);
}
}
`
I would like to know how to configure this one to one relationship and where to configure it (applicationDBContext or MagnatumDbContext).

Invalid column name when using Entity Framework Core Table Per Hierarchy Inheritance

I am new to EF Core and am trying to use TPH Inheritance with Entity Framework Core
I have the following classes defined
public class WorkItem {
public Guid Id { get; set; }
public string WorkItemType { get; set; }
public string Description { get; set; }
}
public class Job : WorkItem {
public string BillingNotes { get; set; }
}
In my context, I have
public class JobContextNew : DbContext {
public virtual DbSet<WorkItem> WorkItem { get; set; }
public virtual DbSet<Job> Job { get; set; }
public JobContextNew(DbContextOptions<JobContextNew> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<WorkItem>(entity => entity.Property(e => e.Id).ValueGeneratedNever());
modelBuilder.Entity<WorkItem>()
.HasDiscriminator(workitem => workitem.WorkItemType)
.HasValue<Job>(nameof(Job));
}
}
If I omit the field in Job, it will pull the data just fine but when I add the BillngNotes back in I get the following error: Invalid column name 'BillingNotes
Can anyone tell me what I might be doing wrong?

How to configure one-to-one relations to the same table in Entity Framework Core

I have a model as follows:
public class Category : BaseEntity
{
public string Name { get; set; }
public virtual Category Parent { get; set; }
public string Description { get; set; }
}
Parent property is related to the same table. How can i configure it?
I'm imagining something like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>()
.HasOne(a => a.Parent)
.OnDelete(false);
}
I'm newbie with Entity framework core, please help me !!!
Resoled by:
public class Category : BaseEntity
{
public string Name { get; set; }
public int? ParentId{ get; set; } /*added*/
[ForeignKey("ParentId")] /*added*/
public virtual Category Parent { get; set; }
public string Description { get; set; }
}

EF Core TPH Discriminator ignores base entities

I have two DbContext. A BaseDbContext and one that inherits from the BaseDbContextcalled FemaleDbContext.
public class BaseDbContext : DbContext
{
public BaseDbContext(DbContextOptions options) : base(options) { }
public virtual DbSet<Person> Person { get; set; }
public virtual DbSet<House> House { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().ToTable("Person", "dbo");
modelBuilder.Entity<House>().ToTable("House", "dbo");
modelBuilder.Entity<Person>().HasOne(e => e.House).WithMany(e => e.Persons);
modelBuilder.Entity<House>().HasMany(e => e.Persons).WithOne(e => e.House);
}
}
The goal is to extend the Person entity with another property. I do not want to use shadow properties because its too dynamic. So I am trying to make it work using TPH. Here is my other context:
public class FemaleDbContext : BaseDbContext
{
public DbSet<Female> Female { get; set; }
public FemaleDbContext(DbContextOptions<FemaleDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Female>().HasBaseType<Person>();
base.OnModelCreating(modelBuilder);
}
}
As you can see, my sub-context should use the Female entity instead of the Person. The problem is that when I run this.Context.Female.ToList() on my SubDbContext, only entities with the value Female inside the Discriminator field inside my database are returned. Entities with the value Person in that table are returned. But I want to get every entity.
Also, here are my entities:
public class Person
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Middlename { get; set; }
public string Lastname { get; set; }
}
public class Female : Person
{
public bool? IsPregnant { get; set; }
}
How can I configure my DbContext that this.Context.Female.ToList() returns both Females and Persons. Note that this.Context.Person.ToList() already returns everything, not only Persons

Table per Concrete Type Mapping Issue in EF Code First 4.2

I'm getting a EntityType 'User' has no key defined. Define the key for this EntityType error.
Model:
public abstract class KeyedEntityBase
{
public int ID { get; private set; }
}
public class User : KeyedEntityBase
{
public string UserName { get; private set; }
public string EmailAddress { get; private set; }
}
Context:
public class LSBPortalContext : DbContext
{
public LSBPortalContext()
: base("LSBPortalDB")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("User");
});
base.OnModelCreating(modelBuilder);
}
}
The issues was that I didn't actually map the KeyedEntityBase class. Once I did that it all worked properly.