实体框架核心OwnsOne创建单独的表,而不是按预期方式向同一表中添加属性

时间:2018-09-05 16:37:40

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

我认为,默认情况下,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迁移添加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);
            });
        );
    }
}

3 个答案:

答案 0 :(得分:2)

我是用此配置代码自己创建的

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;
       }
   }
}    

答案 1 :(得分:0)

尝试以下操作:

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);
        });
}

答案 2 :(得分:0)

@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;
       }
   }
}