【问题标题】:Entity Framework Core OwnsOne Creates Separate Tables, Rather than adding properties to the Same Table as ExpectedEntity Framework Core OwnsOne 创建单独的表,而不是像预期的那样将属性添加到同一个表中
【发布时间】: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; }
  • 嘿嘿,所以最后是不寻常的模型实体循环 :) 很高兴您解决了这个问题。

标签: entity-framework-core entity-framework-migrations ef-core-2.1 owned-types


【解决方案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;
           }
       }
    }  
    
    

    【讨论】:

      猜你喜欢
      • 2011-08-08
      • 1970-01-01
      • 1970-01-01
      • 2017-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-29
      • 1970-01-01
      相关资源
      最近更新 更多