提问人:Özlem Karabulut 提问时间:11/6/2023 更新时间:11/6/2023 访问量:19
如何使用 EF Core 实现 Table-Per-Type 以实现层次结构?
How to implement a Table-Per-Type for hiearchy with EF Core?
问:
- 我尝试使用 ef core 在数据库中实现层次结构。我有继承自 User 类的 Retailer 和 Admin 类。 我尝试创建迁移并使用 TPT 方法。似乎为所有三个类创建了表,但我无法使用 id 属性将表相互链接。我试图用MSSQL实现insert sql,它说
“表'dbo。Admin' 没有 identity 属性。无法执行 SET 操作。 以下是我的表视图: 管理员和零售商表 用户表
- 我的课程如下:
namespace ECommerce.Data.Domain;
[Table("User", Schema = "dbo")]
public class User : BaseModel
{
public string Name { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string UserName { get; set; }
public int RoleId { get; set; }
public virtual Role Role { get; set; }
public virtual List<Address> Addresses { get; set; }
public DateTime LastActivityDate { get; set; }
public int PasswordRetryCount { get; set; }
}
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.Property(x => x.InsertUserId).IsRequired();
builder.Property(x => x.UpdateUserId).IsRequired().HasDefaultValue(0);
builder.Property(x => x.InsertDate).IsRequired();
builder.Property(x => x.UpdateDate).IsRequired(false);
builder.Property(x => x.IsActive).IsRequired().HasDefaultValue(true);
builder.Property(x => x.Id).IsRequired(true);
builder.Property(x => x.Email).IsRequired(true).HasMaxLength(50);
builder.Property(x => x.Password).IsRequired(true).HasMaxLength(50);
builder.Property(x => x.Name).IsRequired().HasMaxLength(50);
builder.Property(x => x.LastName).IsRequired().HasMaxLength(50);
builder.Property(x => x.UserName).IsRequired(true).HasMaxLength(10);
builder.Property(x => x.RoleId).IsRequired(true);
builder.Property(x => x.LastActivityDate).IsRequired();
builder.Property(x => x.PasswordRetryCount).IsRequired().HasDefaultValue(0);
builder.HasIndex(x => x.Id).IsUnique(true);
builder.HasIndex(x => x.Email).IsUnique(true);
builder.HasIndex(x => x.UserName).IsUnique(true);
builder.HasMany(x => x.Addresses)
.WithOne(x => x.User)
.HasForeignKey(x => x.UserId)
.IsRequired(true);
}
}
[Table("Admin", Schema = "dbo")]
public class Admin : User
{
}
public class AdminConfiguration : IEntityTypeConfiguration<Admin>
{
public void Configure(EntityTypeBuilder<Admin> builder)
{
builder.Property(x => x.InsertUserId).IsRequired();
builder.Property(x => x.UpdateUserId).IsRequired().HasDefaultValue(0);
builder.Property(x => x.InsertDate).IsRequired();
builder.Property(x => x.UpdateDate).IsRequired(false);
builder.Property(x => x.IsActive).IsRequired().HasDefaultValue(true);
builder.Property(x => x.Id).IsRequired(true);
builder.Property(x => x.Name).IsRequired().HasMaxLength(20);
}
}
namespace ECommerce.Data.Domain;
[Table("Retailer", Schema = "dbo")]
public class Retailer : User
{
//retailer may have multiple receipt infos and choose between them in order process.
public virtual List<ReceiptInfo> ReceiptInfos { get; set; } = new List<ReceiptInfo>();
public virtual List<Order> Orders { get; set; } = new List<Order>();
}
public class RetailerConfiguration : IEntityTypeConfiguration<Retailer>
{
public void Configure(EntityTypeBuilder<Retailer> builder)
{
builder.Property(x => x.InsertUserId).IsRequired();
builder.Property(x => x.UpdateUserId).IsRequired().HasDefaultValue(0);
builder.Property(x => x.InsertDate).IsRequired();
builder.Property(x => x.UpdateDate).IsRequired(false);
builder.Property(x => x.IsActive).IsRequired().HasDefaultValue(true);
builder.Property(x => x.Id).IsRequired();
builder.HasMany(x => x.Orders)
.WithOne(x => x.Retailer)
.HasForeignKey(x => x.RetailerId)
.IsRequired(true);
builder.HasMany(x => x.ReceiptInfos)
.WithOne(x => x.Retailer)
.HasForeignKey(x => x.RetailerId)
.IsRequired(true)
.OnDelete(DeleteBehavior.Restrict);
}
}
我的dbcontext配置:
public class ECommerceDbContext : DbContext
{
public ECommerceDbContext(DbContextOptions<ECommerceDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().UseTptMappingStrategy();
modelBuilder.ApplyConfiguration(new AddressConfiguration ());
modelBuilder.ApplyConfiguration(new AdminConfiguration());
modelBuilder.ApplyConfiguration(new RetailerConfiguration());
modelBuilder.ApplyConfiguration(new UserConfiguration());
base.OnModelCreating(modelBuilder);
}
我在互联网上研究了各种示例,没有人在他们的子类中添加额外的 Id 字段。我也没有,因为子类会自动从 User 类继承 Id 属性。我在初始迁移中看到表具有 Id 属性。我之前可以将 id 添加到 Admin 和 Retailer 表中。而不是我必须从头开始创建迁移。
我对这个话题很陌生。告诉我我是否错了,但迁移不应该使用 Id 列自动将表相互链接吗?我在我的孩子班上什么也没看到。
我还添加了我的迁移文件:
migrationBuilder.CreateTable(
name: "User",
schema: "dbo",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
LastName = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
Email = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
Password = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
UserName = table.Column<string>(type: "nvarchar(10)", maxLength: 10, nullable: false),
RoleId = table.Column<int>(type: "int", nullable: false),
LastActivityDate = table.Column<DateTime>(type: "datetime2", nullable: false),
PasswordRetryCount = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
InsertUserId = table.Column<int>(type: "int", nullable: false),
InsertDate = table.Column<DateTime>(type: "datetime2", nullable: false),
UpdateUserId = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
UpdateDate = table.Column<DateTime>(type: "datetime2", nullable: true),
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true)
},
constraints: table =>
{
table.PrimaryKey("PK_User", x => x.Id);
table.ForeignKey(
name: "FK_User_Role_RoleId",
column: x => x.RoleId,
principalSchema: "dbo",
principalTable: "Role",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Admin",
schema: "dbo",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Admin", x => x.Id);
table.ForeignKey(
name: "FK_Admin_User_Id",
column: x => x.Id,
principalSchema: "dbo",
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Retailer",
schema: "dbo",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Retailer", x => x.Id);
table.ForeignKey(
name: "FK_Retailer_User_Id",
column: x => x.Id,
principalSchema: "dbo",
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
我还可以看到我的 Id 属性已创建。
有人可以帮我适当地实施 TPT 吗?谢谢你的帮助。
答: 暂无答案
评论