我不认为我要做的事是疯狂的。我有一个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
还是我需要在两侧都具有参考导航属性,这似乎很愚蠢。
答案 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表中,但是在您的应用程序中,您将有两个对象。
答案 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
实体?它将如何变成一对一的关系?
如果要保持Person
和Address
之间的一对一关系,则必须将PersonId
保留在Address
表或AddressId
中到Person
表中作为外键。
由于Person
实体是父实体,而Address
是从属实体,因此将PersonId
到Address
表保留为外键是有好处的。此外,由于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。