EF Core Inheritance issue (HasDiscriminator)

c# ef-core-2.1 ef-migrations entity-framework entity-framework-core

Question

This is parent abstract class :

public enum RequestType
{
    TaxiRequester,
    WomenTaxiRequester,
    LuxaryTaxiRequester,
    MotrCycleRequester,
    VanetRequester
}
public enum PaymentType
{
    Cash = 0,
    Credit=1,
    Free=2
}

public abstract class Request
{
    protected Request()
    {
        PersonsRequests = new HashSet<PersonRequest>();
        WorkerRequestNotification= new HashSet<WorkerRequestNotification>();
    }

    #region EFValidator

    [Required]
    [Key]
    #endregion

    public Guid RequestId { get; set; }
    #region EFValidator

    [Required]

    #endregion

    public string CodeSafar { get; set; }

    #region EFValidator

    [Required]

    #endregion

    public DateTime RequestDate { get; set; }
    #region EFValidator

    [Required]

    #endregion

    public DateTime RequestWorkDate { get; set; }

    #region EFValidator

    [Column(TypeName = "nvarchar(max)")]

    #endregion

    public string DestinationAddress { get; set; }
    #region EFValidator

    [Column(TypeName = "nvarchar(max)")]
    [Required]
    #endregion

    public string DestinationLat { get; set; }
    #region EFValidator

    [Column(TypeName = "nvarchar(max)")]
    [Required]
    #endregion

    public string DestinationLon { get; set; }
    #region EFValidator

    [Required]

    #endregion
    public DateTime ApproveDate { get; set; }
    public DateTime DoneDate { get; set; }
    #region EFValidator

    [Required]

    #endregion

    public long Price { get; set; }
    #region EFValidator

    [Required]

    #endregion

    public Status Status { get; set; }
    #region EFValidator

    [Required]

    #endregion

    public PaymentType PaymentType { get; set; }

    #region EFRelation
    public virtual ICollection<PersonRequest> PersonsRequests { get; set; }
    public virtual ICollection<WorkerRequestNotification> WorkerRequestNotification { get; set; }
    public virtual ICollection<Chat> Chats { get; set; }

    #endregion

    #region RatingRelations

    public virtual Rating Rating { get; set; }

    #endregion

This is a child abstract class :

public abstract class TransportRequest : Request
{
    #region EFValidator

    [Required]
    [Column(TypeName = "nvarchar(max)")]

    #endregion

    public string SourceAddress { get; set; }
    #region EFValidator

    [Required]
    [Column(TypeName = "nvarchar(max)")]

    #endregion

    public string SourceLat { get; set; }
    #region EFValidator

    [Required]
    [Column(TypeName = "nvarchar(max)")]

    #endregion

    public string SourceLon { get; set; }

    #region EFValidator

    [Required]

    #endregion

    public double Distance { get; set; }
    #region EFValidator

    [Column(TypeName = "nvarchar(max)")]

    #endregion

    public string DirectionPoints { get; set; }
}

And these are another children classes:

public class RequestTaxi : TransportRequest
{

}
public class RequestVanet: TransportRequest
{

}
 public class RequestWomenTaxi : TransportRequest
{

}
 public class RequestMotorCycle: TransportRequest
{

}
public class RequestLuxaryTaxi: TransportRequest
{

}

And this is my ApplicationDBContext class related code :

model.Entity<Request>()
            .HasMany(p => p.Chats)
            .WithOne(b => b.Request)
            .HasForeignKey(p => p.RequestId);
        model.Entity<Request>()
            .HasMany(p => p.PersonsRequests)
            .WithOne(b => b.Request)
            .HasForeignKey(p => p.RequestId);
        model.Entity<Request>()
            .HasOne(p => p.Rating)
            .WithOne(b => b.Request)
            .HasForeignKey<Rating>(p => p.RequestId);
        model.Entity<Request>()
            .HasMany(p => p.WorkerRequestNotification)
            .WithOne(b => b.Request)
            .HasForeignKey(p => p.RequestId);

        model.Entity<Request>().Property(p => p.RequestId).ValueGeneratedOnAdd();
        model.Entity<Request>()
            .HasDiscriminator<int>(name: "Type")
            .HasValue<RequestTaxi>(value: Convert.ToInt32(value: RequestType.TaxiRequester))
            .HasValue<RequestWomenTaxi>(value: Convert.ToInt32(value: RequestType.WomenTaxiRequester))
            .HasValue<RequestLuxaryTaxi>(value: Convert.ToInt32(value: RequestType.LuxaryTaxiRequester))
            .HasValue<RequestMotorCycle>(value: Convert.ToInt32(value: RequestType.MotrCycleRequester))
            .HasValue<RequestVanet>(value: Convert.ToInt32(value: RequestType.VanetRequester));

And this is my migration class :

protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropIndex(
            name: "IX_Request_CodeSafar",
            table: "Request");

        migrationBuilder.AlterColumn<string>(
            name: "CodeSafar",
            table: "Request",
            nullable: false,
            oldClrType: typeof(string));

        migrationBuilder.AddColumn<string>(
            name: "RequestMotorCycle_DirectionPoints",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<double>(
            name: "RequestMotorCycle_Distance",
            table: "Request",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestMotorCycle_SourceAddress",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestMotorCycle_SourceLat",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestMotorCycle_SourceLon",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestTaxi_DirectionPoints",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<double>(
            name: "RequestTaxi_Distance",
            table: "Request",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestTaxi_SourceAddress",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestTaxi_SourceLat",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestTaxi_SourceLon",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestVanet_DirectionPoints",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<double>(
            name: "RequestVanet_Distance",
            table: "Request",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestVanet_SourceAddress",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestVanet_SourceLat",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestVanet_SourceLon",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestWomenTaxi_DirectionPoints",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<double>(
            name: "RequestWomenTaxi_Distance",
            table: "Request",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestWomenTaxi_SourceAddress",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestWomenTaxi_SourceLat",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.AddColumn<string>(
            name: "RequestWomenTaxi_SourceLon",
            table: "Request",
            type: "nvarchar(max)",
            nullable: true);

        migrationBuilder.CreateIndex(
            name: "IX_Person_ApplicationUsersId1",
            table: "Person",
            column: "ApplicationUsersId",
            unique: true);

        migrationBuilder.CreateIndex(
            name: "IX_Person_ApplicationUsersId2",
            table: "Person",
            column: "ApplicationUsersId",
            unique: true);

        migrationBuilder.CreateIndex(
            name: "IX_Person_ApplicationUsersId3",
            table: "Person",
            column: "ApplicationUsersId",
            unique: true);

        migrationBuilder.AddForeignKey(
            name: "FK_Person_ApplicationUsers_ApplicationUsersId1",
            table: "Person",
            column: "ApplicationUsersId",
            principalTable: "ApplicationUsers",
            principalColumn: "Id");

        migrationBuilder.AddForeignKey(
            name: "FK_Person_ApplicationUsers_ApplicationUsersId2",
            table: "Person",
            column: "ApplicationUsersId",
            principalTable: "ApplicationUsers",
            principalColumn: "Id");

        migrationBuilder.AddForeignKey(
            name: "FK_Person_ApplicationUsers_ApplicationUsersId3",
            table: "Person",
            column: "ApplicationUsersId",
            principalTable: "ApplicationUsers",
            principalColumn: "Id");
    }

My question is why added some column like these :

RequestMotorCycle_DirectionPoints

and repeated for every five children class ?

In fact I have six DirectionPoints column!!!

How can I have only one DirectionPoints for example ?

1
1
6/8/2018 6:42:43 PM

Accepted Answer

The problem is that all these properties are defined in the TransportRequest class, but TransportRequest is not specified to be an entity (only the Request and the final derived entities), hence EF Core assumes it's just a base class, and all derived classes properties are different.

The Including & Excluding Types section of the EF Core documentation explains what classes are identified as entities:

By convention, types that are exposed in DbSet properties on your context are included in your model. In addition, types that are mentioned in the OnModelCreating method are also included. Finally, any types that are found by recursively exploring the navigation properties of discovered types are also included in the model.

As you can see, TransportRequest is not a DbSet, not mentioned in the OnModelCreating and not referenced by navigation property.

To fix the issue, simply "mention" it in the OnModelCreating:

// ...
model.Entity<TransportRequest>();
// ...
3
6/8/2018 6:41:45 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow