Entity Framework Core OwnsOne 创建单独的表,而不是像预期的那样将属性添加到同一个表中
Posted
技术标签:
【中文标题】Entity Framework Core OwnsOne 创建单独的表,而不是像预期的那样将属性添加到同一个表中【英文标题】:Entity Framework Core OwnsOne Creates Separate Tables, Rather than adding properties to the Same Table as Expected 【发布时间】:2019-02-10 21:07:01 【问题描述】:我认为 Entity Framework Core 拥有的类型默认添加到与其所有者相同的表中。但我在迁移中没有看到这一点。
有人能告诉我吗?
有没有办法通过将 Name 属性直接添加到 Person 表来获得所需的迁移?
public class Person
public Name Name get; set;
public class Name
public string FirstName get; set;
public string LastName get; set;
public class PersonConfiguration : IEntityTypeConfiguration<Person>
public void Configure(EntityTypeBuilder<Person> person)
person.OwnsOne(p => p.Name);
dotnet ef migrations add DidNotSeeThatComing
结果
public partial class DidNotSeeThatComing : Migration
protected override void Up(MigrationBuilder migrationBuilder)
migrationBuilder.CreateTable(
name: "Name",
columns: table => new
FirstName = table.Column<string>(type: "varchar", nullable: true),
LastName = table.Column<string>(type: "varchar", nullable: true),
PersonId = table.Column<Guid>(nullable: false)
,
constraints: table =>
table.PrimaryKey("PK_Name", x => x.PersonId);
table.ForeignKey(
name: "FK_Name_Person_PersonId",
column: x => x.PersonId,
principalTable: "Person",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
);
);
【问题讨论】:
您的想法是正确的 - 默认情况下它与所有者位于同一个表中,我无法重现该问题。你有干净的复制项目吗? @IvanStoev 已验证使用干净的 repo 项目按预期工作 发生这种情况的项目中是否有任何异常代码?喜欢模型实体/反射上的循环并调用ToTable
?
Ugg 我用 foreach 对自己做了这个(modelBuilder.Model.GetEntityTypes() 中的var entity) entity.Relational().TableName = entity.Name;
嘿嘿,所以最后是不寻常的模型实体循环 :) 很高兴您解决了这个问题。
【参考方案1】:
我自己在不知不觉中用这个配置代码创建了这个
protected override void OnModelCreating(ModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
foreach (var entity in modelBuilder.Model.GetEntityTypes())
entity.Relational().TableName = entity.Name;
这是我正在使用的解决方法
[Owned] // Microsoft.EntityFrameworkCore
public class Name ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
foreach (var entity in modelBuilder.Model.GetEntityTypes())
if(!entity.ClrType.GetCustomAttributes().OfType<OwnedAttribute>().Any())
entity.Relational().TableName = entity.Name;
【讨论】:
[Owned] 正是我所追求的。【参考方案2】:尝试以下方法:
public class Person
public Guid Id get; set;
public Name Name get; set;
public class Name
public Guid Id get; set;
public Guid PersonId get;set;
public Person Person get; set;
public string FirstName get; set;
public string LastName get; set;
public class PersonConfiguration : IEntityTypeConfiguration<Person>
public void Configure(EntityTypeBuilder<Person> person)
person.OwnsOne(p => p.Name,
nCls =>
nCls.HasOne(n => n.Person);
nCls.HasKey(n => new n.Id, n.PersonId);
nCls.HasForeignKey(m => m.PersonId);
nCls.ToTable(nCls.OwnedEntityType.ClrType.Name);
);
这应该会让你得到类似的东西:
protected override void Up(MigrationBuilder migrationBuilder)
// the table names are lower case because my convention is to generate all names in snake_case
migrationBuilder.CreateTable(
name: "persons",
columns: table => new
id = table.Column<Guid>(nullable: false)
,
constraints: table =>
table.PrimaryKey("pk_persons", x => x.id);
);
migrationBuilder.CreateTable(
name: "name",
columns: table => new
id = table.Column<Guid>(nullable: false),
person_id = table.Column<Guid>(nullable: false),
first_name = table.Column<string>(maxLength: 256, nullable: true),
last_name = table.Column<string>(maxLength: 256, nullable: true)
,
constraints: table =>
table.PrimaryKey("pk_name", x => new x.id, x.person_id );
table.ForeignKey(
name: "fk_name_persons_person_id",
column: x => x.person_id,
principalTable: "persons",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
);
【讨论】:
【参考方案3】:@Davious 我今天遇到了完全相同的问题,感谢您分享您的解决方案。这是我的解决方案,您不需要OwnedAttribute
,因为您也可以使用entity.IsOwned()
。我总是尝试通过 DbContext 进行所有配置。
///[Owned] // Not needed anymore
public class Name ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
base.OnModelCreating(modelBuilder);
modelbuilder.Entity<Person>().OwnsOne(p => p.Name)
foreach (var entity in modelBuilder.Model.GetEntityTypes())
if(!entity.IsOwned())
entity.Relational().TableName = entity.Name;
【讨论】:
以上是关于Entity Framework Core OwnsOne 创建单独的表,而不是像预期的那样将属性添加到同一个表中的主要内容,如果未能解决你的问题,请参考以下文章
EF6 System.Data.Entity.Core.EntityKey 在 Entity Framework Core 中的等价物是啥?
张高兴的 Entity Framework Core 即学即用:创建第一个 EF Core 应用