如何防止 EF Core 将 DDD ValueObjects 创建为表
How to prevent EF Core from creating DDD ValueObjects as tables
我正在使用 EF Core 5.0.1
我创建了以下 ValueObject
public class Address : BaseValueObject
{
public Address(string street, string zipCode, string city, string state, string country)
{
Street = street;
ZipCode = zipCode;
City = city;
State = state;
Country = country;
}
public string Street { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Street;
yield return ZipCode;
yield return City;
yield return State;
yield return Country;
}
}
以及拥有值对象的实体
public class Location : BaseEntity
{
[Required]
public string Name { get; set; }
public Address Address { get; set; }
}
Location对象配置如下
public class LocationConfiguration : BaseEntityConfiguration<Location>
{
public override void Configure(EntityTypeBuilder<Location> builder)
{
builder.OwnsOne(o => o.Address, a =>
{
a.Property(p => p.Street).HasMaxLength(600)
.HasDefaultValue("");
a.Property(p => p.City).HasMaxLength(150)
.HasDefaultValue("");
a.Property(p => p.State).HasMaxLength(60)
.HasDefaultValue("");
a.Property(p => p.ZipCode).HasMaxLength(12)
.HasDefaultValue("");
});
base.Configure(builder);
}
}
问题是 EF Core 迁移仍在将 ValueObjects 创建为数据库中的表。
我究竟做错了什么?
在生成的迁移代码中,我可以看到以下内容:
migrationBuilder.CreateTable(
name: "Location",
columns: table => new
{
Id = table.Column<long>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Name = table.Column<string>(type: "TEXT", maxLength: 80, nullable: false),
Timestamp = table.Column<string>(type: "TEXT", rowVersion: true, nullable: false, defaultValueSql: "CURRENT_TIMESTAMP")
},
constraints: table =>
{
table.PrimaryKey("PK_Location", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Address",
columns: table => new
{
LocationId = table.Column<long>(type: "INTEGER", nullable: false),
Street = table.Column<string>(type: "TEXT", maxLength: 600, nullable: true, defaultValue: ""),
ZipCode = table.Column<string>(type: "TEXT", maxLength: 12, nullable: true, defaultValue: ""),
City = table.Column<string>(type: "TEXT", maxLength: 150, nullable: true, defaultValue: ""),
State = table.Column<string>(type: "TEXT", maxLength: 60, nullable: true, defaultValue: ""),
Country = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Address", x => x.LocationId);
table.ForeignKey(
name: "FK_Address_Location_LocationId",
column: x => x.LocationId,
principalTable: "Location",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
最后是 DBContext class
public class MyDbContext : DbContext
{
public PlannerDbContext(DbContextOptions<PlannerDbContext> options)
: base(options)
{
}
public DbSet<Location> Locations { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// do not use plural form for table names
modelBuilder.Model.GetEntityTypes()
.Configure(e => e.SetTableName(e.DisplayName()));
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
EF 为值对象创建 table 的原因是 table 命名约定发生更改的代码部分。我想,我已经从一些关于 hot to set tables names in singular form 的 SO question 中复制了它。
此方法modelBuilder.Model.GetEntityTypes()
returns 模型中所有对象(包括值对象)的枚举器。针对值对象配置 table 名称 属性 将导致 EF 将此类型视为实体。
这部分
// do not use plural form for table names
modelBuilder.Model.GetEntityTypes()
.Configure(e => e.SetTableName(e.DisplayName()));
应该改为
// do not use plural form for table names
modelBuilder.Model.GetEntityTypes()
.Where(x => !x.ClrType.IsSubclassOf(typeof(BaseValueObject)))
.Configure(e => e.SetTableName(e.DisplayName()));
我正在使用 EF Core 5.0.1
我创建了以下 ValueObject
public class Address : BaseValueObject
{
public Address(string street, string zipCode, string city, string state, string country)
{
Street = street;
ZipCode = zipCode;
City = city;
State = state;
Country = country;
}
public string Street { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Street;
yield return ZipCode;
yield return City;
yield return State;
yield return Country;
}
}
以及拥有值对象的实体
public class Location : BaseEntity
{
[Required]
public string Name { get; set; }
public Address Address { get; set; }
}
Location对象配置如下
public class LocationConfiguration : BaseEntityConfiguration<Location>
{
public override void Configure(EntityTypeBuilder<Location> builder)
{
builder.OwnsOne(o => o.Address, a =>
{
a.Property(p => p.Street).HasMaxLength(600)
.HasDefaultValue("");
a.Property(p => p.City).HasMaxLength(150)
.HasDefaultValue("");
a.Property(p => p.State).HasMaxLength(60)
.HasDefaultValue("");
a.Property(p => p.ZipCode).HasMaxLength(12)
.HasDefaultValue("");
});
base.Configure(builder);
}
}
问题是 EF Core 迁移仍在将 ValueObjects 创建为数据库中的表。 我究竟做错了什么? 在生成的迁移代码中,我可以看到以下内容:
migrationBuilder.CreateTable(
name: "Location",
columns: table => new
{
Id = table.Column<long>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Name = table.Column<string>(type: "TEXT", maxLength: 80, nullable: false),
Timestamp = table.Column<string>(type: "TEXT", rowVersion: true, nullable: false, defaultValueSql: "CURRENT_TIMESTAMP")
},
constraints: table =>
{
table.PrimaryKey("PK_Location", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Address",
columns: table => new
{
LocationId = table.Column<long>(type: "INTEGER", nullable: false),
Street = table.Column<string>(type: "TEXT", maxLength: 600, nullable: true, defaultValue: ""),
ZipCode = table.Column<string>(type: "TEXT", maxLength: 12, nullable: true, defaultValue: ""),
City = table.Column<string>(type: "TEXT", maxLength: 150, nullable: true, defaultValue: ""),
State = table.Column<string>(type: "TEXT", maxLength: 60, nullable: true, defaultValue: ""),
Country = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Address", x => x.LocationId);
table.ForeignKey(
name: "FK_Address_Location_LocationId",
column: x => x.LocationId,
principalTable: "Location",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
最后是 DBContext class
public class MyDbContext : DbContext
{
public PlannerDbContext(DbContextOptions<PlannerDbContext> options)
: base(options)
{
}
public DbSet<Location> Locations { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// do not use plural form for table names
modelBuilder.Model.GetEntityTypes()
.Configure(e => e.SetTableName(e.DisplayName()));
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
EF 为值对象创建 table 的原因是 table 命名约定发生更改的代码部分。我想,我已经从一些关于 hot to set tables names in singular form 的 SO question 中复制了它。
此方法modelBuilder.Model.GetEntityTypes()
returns 模型中所有对象(包括值对象)的枚举器。针对值对象配置 table 名称 属性 将导致 EF 将此类型视为实体。
这部分
// do not use plural form for table names
modelBuilder.Model.GetEntityTypes()
.Configure(e => e.SetTableName(e.DisplayName()));
应该改为
// do not use plural form for table names
modelBuilder.Model.GetEntityTypes()
.Where(x => !x.ClrType.IsSubclassOf(typeof(BaseValueObject)))
.Configure(e => e.SetTableName(e.DisplayName()));