C# 如何防止EF Core将DDD ValueObject创建为表
我使用的是EF Core 5.0.1 我创建了以下ValueObjectC# 如何防止EF Core将DDD ValueObject创建为表,c#,entity-framework-core,.net-5,C#,Entity Framework Core,.net 5,我使用的是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;
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;
}
}
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);
}
}
公共类位置配置:BaseEntityConfiguration
{
公共覆盖无效配置(EntityTypeBuilder)
{
builder.OwnsOne(o=>o.Address,a=>
{
a、 属性(p=>p.Street)。HasMaxLength(600)
.HasDefaultValue(“”);
a、 属性(p=>p.City).HasMaxLength(150)
.HasDefaultValue(“”);
a、 属性(p=>p.State).HasMaxLength(60)
.HasDefaultValue(“”);
a、 属性(p=>p.ZipCode).HasMaxLength(12)
.HasDefaultValue(“”);
});
配置(生成器);
}
}
问题是EF Core迁移仍在将ValueObject创建为数据库中的表。
我做错了什么?
在生成的迁移代码中,我可以看到以下内容:
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);
});
migrationBuilder.CreateTable(
名称:“地点”,
列:表=>new
{
Id=table.Column(类型:“INTEGER”,可为空:false)
.Annotation(“Sqlite:Autoincrement”,true),
Name=table.Column(类型:“TEXT”,最大长度:80,可空值:false),
Timestamp=table.Column(类型:“TEXT”,行版本:true,可空:false,defaultValueSql:“当前_时间戳”)
},
约束:表=>
{
表.PrimaryKey(“PK_位置”,x=>x.Id);
});
migrationBuilder.CreateTable(
姓名:“地址”,
列:表=>new
{
LocationId=table.Column(类型:“INTEGER”,可为空:false),
Street=table.Column(类型:“TEXT”,最大长度:600,可空值:true,默认值:),
ZipCode=table.Column(类型:“TEXT”,maxLength:12,可空:true,defaultValue:),
City=table.Column(类型:“TEXT”,最大长度:150,可空值:true,默认值:),
State=table.Column(类型:“TEXT”,maxLength:60,可空:true,defaultValue:),
Country=表列(类型:“TEXT”,可为空:true)
},
约束:表=>
{
表.PrimaryKey(“PK_地址”,x=>x.LocationId);
表1.外键(
名称:“FK\U地址\U位置\U位置ID”,
列:x=>x.LocationId,
原则:“位置”,
主栏:“Id”,
onDelete:引用。级联);
});
最后是DBContext类
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());
}
}
公共类MyDbContext:DbContext
{
public PlannerDbContext(DbContextOptions选项)
:基本(选项)
{
}
公共数据库集位置{get;set;}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
//表名不要使用复数形式
modelBuilder.Model.GetEntityTypes()
.Configure(e=>e.SetTableName(e.DisplayName());
基于模型创建(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.getExecutionGassembly());
}
}
EF为值对象创建表的原因是代码中更改了表命名约定的部分。我想,我是从一些关于热的问题中复制过来的,以单数形式设置表名
此方法modelBuilder.Model.GetEntityTypes()
将枚举数返回给模型中的所有对象(包括值对象)。针对值对象配置表名属性将导致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()));
我觉得一切都很好。唯一奇怪的是Address实体上的无参数私有构造函数。如果删除它,会得到相同的结果吗?而且,这并不是说它会有什么不同,静态Create方法返回的是一个结果,而不仅仅是地址。在dbcontext中的OnModelCreating中使用fluentapi如何:
modelBuilder.Entity().OwnsOne(c=>c.Address,a=>{/…})
并在您的上下文中,删除code公共数据库集地址{get;set;}
@Yinqiu DbContext类中没有数据库集地址{get;set;}。在dbcontext中的OnModelCreating中设置配置不会改变任何内容
// do not use plural form for table names
modelBuilder.Model.GetEntityTypes()
.Where(x => !x.ClrType.IsSubclassOf(typeof(BaseValueObject)))
.Configure(e => e.SetTableName(e.DisplayName()));