Entity Framework Table Per Type inheritance with discriminator column - ef-code-first

I am using EF5 TPT and thus don't expect a discriminator column. Why is it being created?
The ( simplified) table classes are;
[Table("SalesDocumentHeaders")]
public abstract class SalesDocumentHeader : LoggedEntity
{
[ForeignKey("CreatedByUserId")]
public virtual User CreatedBy { get; set; }
[Required]
public int CreatedByUserId { get; set; }
[Required]
public virtual DateTime? DocumentDate { get; set; }
[Required]
public String ReferenceNumber { get; set; }
}
[Table("SalesOrders")]
public class SalesOrder : SalesDocumentHeader
{
[Required]
public String CustomerOrderNumber { get; set; }
public DateTime? DeliverBy { get; set; }
public virtual SortableBindingList<SalesOrderLine> Lines { get; set; }
}
public abstract class LoggedEntity
{
public int Id { get; set; }
public Guid RowId { get; set; }
[ConcurrencyCheck]
public int RowVersionId { get; set; }
}
The context contains
public DbSet<SalesOrder> SalesOrders { get; set; }
public DbSet<SalesDocumentHeader> SalesDocumentHeaders { get; set; }
The SalesDocumentHeader table creates with a Discriminator column. What am I doing wrong?
it makes no difference whether SalesDocumentHeader is declared as abstract or not

because I had another class which inherited from SalesDocumentHeader which I forgot to mark with the table attribute

Related

When creating a one-to-one relationship in an entity it throws an error The navigation property 'StudentModel' was not found on the dependent type

I want to create one to one relation between tables. My table is
public class StudentModel
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime DateOfBirth { get; set; }
[Required, Display(Name="Department Name")]
public int DeptId { get; set; }
//navigration proprty
[ForeignKey("DeptId")]
public virtual DepartmentModels Department { get; set; }
public virtual StudentRegistrationModels StudentRegistration { get; set; }
}
and my other table is
public class StudentRegistrationModels
{
[Key]
public int StudentId { get; set; }
[Required]
public int CourseId { get; set; }
[Required]
public DateTime EnrollDate { get; set; }
public bool IsPaymentComplete { get; set; }
//navigration proprty
[ForeignKey("StudentId")]
public virtual StudentModel Student { get; set; }
[ForeignKey("CourseId")]
public virtual CourseModels Course { get; set; }
//oneToOneStudentRegistration
}
But when I make migration it throws an error:
Unable to determine the principal end of an association between the types 'StudentManagementSystem.Models.StudentModel' and 'StudentManagementSystem.Models.StudentRegistrationModels'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Why is this occurring?
I believe the issue is that you have a single StudentRegistrationModel instance in your StudentModel, where the StudentRegistrationModel looks to be more of a Many-to-Many structure. Can a single student only be registered to a single course? If that were the case it would make more sense for StudentModel to just have a CourseModel reference. Since a Student probably has multiple courses, it would probably make more sense for StudentModel to have:
public virtual ICollection<StudentRegistrationModels> StudentRegistration { get; set; } = new List<StudentRegistrationModels>();
Then ensuring that your model configuration maps out the relationship. This can be done with an attribute, as part of the DbContext OnModelCreating, or using an EntityTypeConfiguration. With Attributes:
[InverseProperty("Student")] // Tells EF this collection corresponds to the Student on the StudentRegistrationModel.
public virtual ICollection<StudentRegistrationModels> StudentRegistration { get; set; } = new List<StudentRegistrationModels>();
Maybe try to add [Key] annotation to Id field in StudentModel.
using System.ComponentModel.DataAnnotations;
public class StudentModel
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime DateOfBirth { get; set; }
[Required, Display(Name="Department Name")]
public int DeptId { get; set; }
//navigration proprty
[ForeignKey("DeptId")]
public virtual DepartmentModels Department { get; set; }
public virtual StudentRegistrationModels StudentRegistration { get; set; }
}
or if it won't work try map relationship in OnModelCreating in your data context.

Base entity in many to many relationships

I'm trying to implement BaseEntity class.
There i have fields:
Id, CreatedDateTime, UpdatedDateTime, CreatedBy, UpdatedBy.
In my repository class i point this:
public interface IRepositoryBase<TEntity> where TEntity : BaseEntity
Is it will be correct to inherit BaseEntity also in every many-to-many entity?
Like this:
public class OrderDish
{
public int OrderId { get; set; }
public Order Order { get; set; }
public int DishId { get; set; }
public Dish Dish { get; set; }
}
If your BaseEntity looks like this:
public interface BaseEntity
{
DateTime? CreatedDate { get; set; }
DateTime? UpdatedDate { get; set; }
string CreatedBy { get; set; }
string UpdatedBy { get; set; }
}
Create an Entity class from BaseEntity like:
public class Entity : BaseEntity
{
protected Entity(){}
public virtual string CreatedBy { get; set; }
public virtual DateTime? CreatedDate { get; set; }
public virtual string UpdatedBy { get; set; }
public virtual DateTime? UpdatedDate { get; set; }
}
Inherit the other entitites from Entity like:
public class OrderDish : Entity
{
public int OrderId { get; set; }
public Order Order { get; set; }
public int DishId { get; set; }
public Dish Dish { get; set; }
}
You will be able to access the properties this way

Create SQLite table from an inherited class

I want to create a SQLite table based on the GroupEntity class which inherits from the Entity class.
When I try to create a table directly from GroupEntity class without inheritance - table creates successfully.
I am using SQLite-net, Version=1.4.118.0 in Xamarin.Forms PCL project.
public class Entity
{
public virtual int Id { get; set; }
public DateTime CreatedOn { get; set; }
public int CreatedById { get; set; }
public DateTime ModifiedOn { get; set; }
public int ModifiedById { get; set; }
}
public class GroupEntity : Entity
{
[SQLite.PrimaryKey]
public int Id { get; set; }
public string Name { get; set; }
public int PhotoFileId { get; set; }
public int UnreadMessageCount { get; set; }
public Guid LastMessageId { get; set; }
}

Allow null in model when using Code first

I have an model like this:
public class EquipmentEmployee
{
public int EquipmentEmployeeID { get; set; }
public int EmployeeID { get; set; }
public Employee Employee { get; set; }
public int EquipmentID { get; set; }
public Equipment Equipment { get; set; }
public int RequisitionID { get; set; }
public Requisition Requisition { get; set; }
public DateTime From { get; set; }
public DateTime To { get; set; }
public string Comment { get; set; }
}
I use Mvc scaffolding for creating my controllers, repositories and views. Int the create View I'm not able to POST since I dont have values for "to" and "RequisitionID". I have not added [Required] to them. Is this possible? To POST and have those two null?
You should declare optional fields using a nullable type
public int? RequisitionID { get; set; }
To accept the null values you can use the following solution.
public int? RequisitionID { get; set; }

EF5 Inheritance with code first

I've multiple smaller versions of classes that maps to single database table
e.g
UserBrief Class:
[Table("Users")]
public partial class UserBrief
{
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
UserAdmin Class
[Table("Users")]
public partial class UserAdmin : UserBrief
{
public int RoleID { get; set; }
}
UserHR Class
[Table("Users")]
public partial class UserHR : UserBrief
{
public string EmailAddress { get; set; }
public string Phone { get; set; }
}
User Class
[Table("Users")]
public partial class User
{
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int RoleID { get; set; }
public string EmailAddress { get; set; }
public string Phone { get; set; }
}
I've multiple bounded contexts. Depending on functionality of context I've used above classes.
If I add single class in context and Ignore all other classes then it works fine.
e.g
public DbSet<UserHR> UserHRs { get; set; }
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<UserBrief>();
modelBuilder.Ignore<UserAdmin >();
modelBuilder.Ignore<User>();
}
Now if I added UserBrief and UserHRs
It gives error "Invalid column name 'Discriminator'" as EF assumes that this is Table per Hierarchy (TPH) approach.
I've been searching for solution, but can't find how to do this.
Any ideas?
Thanks in advance.
The inherited classes in the POCO objects for the TPH approach should represent sub-types of the class, not just property sections. Having the User table which is a combination of UserHR and UserAdmin breaks this representation.
You could attempt to add a Discriminator property to the User table to fix the error, but I would suggest either just using the Users table with nullable properties or modeling your objects as 1-to-1 relationships:
public class UserBrief
{
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual UserAdmin UserAdmin { get; set; }
public virtual UserHR UserHR { get; set; }
}
public class UserAdmin
{
[Key]
[ForeignKey("UserBrief")]
public int EmployeeID { get; set; }
public int RoleID { get; set; }
public virtual UserBrief UserBrief{ get; set; }
}
public class UserHR
{
[Key]
[ForeignKey("UserBrief")]
public int EmployeeID { get; set; }
public string EmailAddress { get; set; }
public string Phone { get; set; }
public virtual UserBrief UserBrief{ get; set; }
}

Resources