EF Core 2.0一对一-这是怎么回事?

时间:2018-12-08 02:05:37

标签: c# entity-framework-core

我不认为我要做的事是疯狂的。我有一个Person实体,将有一个地址。我不想在我的Address实体中将PersonId作为属性。当我尝试保存到数据库时,尽管EF Core不断提示我无法将NULL插入地址表的PersonId列中。

public class Person
{
    public int Id { get; private set;}
    public string Name { get; private set;}
    public Address Address { get; private set;}

    // .. constructor etc
}

public class Address
{
    public int Id { get; private set;}
    public string Street { get; private set;}

    // .. constructor etc
}

数据库表:

人:身份证,姓名

地址:ID,街道,PersonId

还是我需要在两侧都具有参考导航属性,这似乎很愚蠢。

4 个答案:

答案 0 :(得分:2)

如果您有1:1 person:address,则也可以使用Value对象。太棒了。

您在EF的DbContext中注册的主要对象

public DbSet<Person> Persons { get; set; }


public class Person
{
  public int Id { get; private set;}
  public string Name { get; private set;}
  public Address address { get; private set;}

  // .. constructor etc
}

将您的Address对象作为具有属性[Owned]的Value对象

[Owned]    
public class Address
{
   public int Id { get; private set;}
   public string Street { get; private set;}
}

,然后在DbContext OnModelCreating

中设置映射
modelBuilder.Entity<Person>().OwnsOne(o => o.Address);

EF会将您的值对象生成到Person表中,但是在您的应用程序中,您将有两个对象。

owned-entities article

答案 1 :(得分:1)

应该这样做:

public class Person
{
    public int Id { get; private set;}

    public string Name { get; private set;}

    public int AddressId { get; private set; }

    [ForeignKey("AddressId")]
    public virtual Address address { get; private set;}

    // .. constructor etc
}

public class Address
{
    public int Id { get; private set;}

    public string Street { get; private set;}

    // .. constructor etc
}

答案 2 :(得分:1)

  

我不想在我的地址实体中将PersonId作为属性。

那么您将如何将Address实体映射到Person实体?它将如何变成一对一的关系?

如果要保持PersonAddress之间的一对一关系,则必须将PersonId保留在Address表或AddressId中到Person表中作为外键。

由于Person实体是父实体,而Address是从属实体,因此将PersonIdAddress表保留为外键是有好处的。此外,由于Person一次只有一个地址,因此您也可以按照以下方式将PersonId作为Address表的主键,以确保Person会有一个{{ 1}}一次记录:

Address

您还可以使用public class Person { public int Id { get; private set;} public string Name { get; private set;} public Address Address { get; private set;} // .. constructor etc } public class Address { [Key,ForeignKey("Person")] public int PersonId { get; private set;} public string Street { get; private set;} public Person Person {get; set;} // .. constructor etc } 来实现相同的目的,如下所示:

Owned Entity

然后在public class Person { public int Id { get; private set;} public string Name { get; private set;} public Address Address { get; private set;} // .. constructor etc } [Owned] public class Address { public string Street { get; private set;} // .. constructor etc }

DbContext

另一个解决方案是也将public class TestDbContext : DbContext { public TestDbContext(DbContextOptions<TestDbContext> options) : base(options) { } public DbSet<Person> Persons { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { // In case of Owned Entity modelBuilder.Entity<Person>().OwnsOne(p => p.Address, a => { a.ToTable("Address"); a.Property(p => p.Street).HasColumnName("Street"); }); } } 信息保留在人员表中。为此,只需从实体配置中删除Address。因此配置如下:

a.ToTable("Address");

答案 3 :(得分:1)

在EF Core中,用于定义关系的显式FK属性和导航属性都不是必需的。

按照惯例,仅具有参考导航属性的模型被映射到一对多可选关系。因此,如果没有流畅的配置,EF Core就会隐含您模型中的关系

public class Person
{
    public int Id { get; private set;}
    public string Name { get; private set;}
    public Address Address { get; private set;}
}

public class Address
{
    public int Id { get; private set;}
    public string Street { get; private set;}
}

modelBuilder.Entity<Person>()
    .HasOne(e => e.Address)
    .WithMany()
    .HasForeignKey("AddressId")
    .IsRequired(false)
    .OnDelete(DeleteBehavior.ClientSetNull);

您的需求与PersonId表中的Address FK列是一对一的。

由于EF Core常规假设显然对您的情况是错误的,因此您需要使用流畅的配置覆盖它,如下所示:

modelBuilder.Entity<Person>()
    .HasOne(e => e.Address)
    .WithOne()
    .HasForeignKey<Address>("PersonId")
    .IsRequired()
    .OnDelete(DeleteBehavior.Cascade);

请注意HasForeignKey的显式泛型类型参数。它用于指示两个实体中的哪个是从属实体,因此包含FK-这种情况是Address。一对多关系的类似方法不需要这样做,因为“一方”始终是主体,“多方”是从属。对于一对一的HasOne / WithOne来说,尚不足以确定主体和从属关系,因此HasForeignKey / HasPrincipal方法的泛型参数可满足此附加目的。

有关更多信息,请参见Relationships