EF Core 继承问题(HasDiscriminator)
EF Core Inheritance issue (HasDiscriminator)
这是 parent 摘要 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
这是一个 child 摘要 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; }
}
还有另外 children classes:
public class RequestTaxi : TransportRequest
{
}
public class RequestVanet: TransportRequest
{
}
public class RequestWomenTaxi : TransportRequest
{
}
public class RequestMotorCycle: TransportRequest
{
}
public class RequestLuxaryTaxi: TransportRequest
{
}
这是我的 ApplicationDBContext class 相关代码:
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));
这是我的迁移 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");
}
我的问题是为什么要添加这样的专栏:
RequestMotorCycle_DirectionPoints
并每五次重复一次 children class ?
事实上我有六个 DirectionPoints 列!!!
例如,如何才能只有一个 DirectionPoints?
问题是所有这些属性都在 TransportRequest
class 中定义,但 TransportRequest
未指定为 实体 (只有 Request
和最终的派生实体),因此 EF Core 假定它只是一个基础 class,并且所有派生的 classes 属性都是不同的。
EF Core 文档的 Including & Excluding Types 部分解释了 class 实体被识别为 实体 :
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.
如您所见,TransportRequest
不是 DbSet
,未在 OnModelCreating
中提及,也未被导航引用 属性。
要解决这个问题,只需 "mention" 它在 OnModelCreating
:
// ...
model.Entity<TransportRequest>();
// ...
这是 parent 摘要 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
这是一个 child 摘要 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; }
}
还有另外 children classes:
public class RequestTaxi : TransportRequest
{
}
public class RequestVanet: TransportRequest
{
}
public class RequestWomenTaxi : TransportRequest
{
}
public class RequestMotorCycle: TransportRequest
{
}
public class RequestLuxaryTaxi: TransportRequest
{
}
这是我的 ApplicationDBContext class 相关代码:
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));
这是我的迁移 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");
}
我的问题是为什么要添加这样的专栏:
RequestMotorCycle_DirectionPoints
并每五次重复一次 children class ?
事实上我有六个 DirectionPoints 列!!!
例如,如何才能只有一个 DirectionPoints?
问题是所有这些属性都在 TransportRequest
class 中定义,但 TransportRequest
未指定为 实体 (只有 Request
和最终的派生实体),因此 EF Core 假定它只是一个基础 class,并且所有派生的 classes 属性都是不同的。
EF Core 文档的 Including & Excluding Types 部分解释了 class 实体被识别为 实体 :
By convention, types that are exposed in
DbSet
properties on your context are included in your model. In addition, types that are mentioned in theOnModelCreating
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.
如您所见,TransportRequest
不是 DbSet
,未在 OnModelCreating
中提及,也未被导航引用 属性。
要解决这个问题,只需 "mention" 它在 OnModelCreating
:
// ...
model.Entity<TransportRequest>();
// ...