在 EF Core 2.2 中与不同 类 一对一
One-to-one with different classes in EF Core 2.2
我想按照this blog解释如何配置一对一关系。它的想法是,一个实体获得另一个类型的 属性,而另一个实体获得前者类型的 属性 加上它的 ID 以创建外键。
不过,我的问题是,我想像这样断开两个不同 classes 的接触部分。 class SomeThing 已经重构并且与 class Address 一起工作得很好。但是,我不确定如何处理 class SomeThingElse.
public class SomeThing
{
public Guid Id { get; set; }
//public string Street { get; set; }
//public string City { get; set; }
public Address Address { get; set; }
}
public class Address
{
public Guid Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public Guid SomeThingId { get; set; }
public SomeThing SomeThing { get; set; }
}
public class SomeThingElse
{
public Guid Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
//public Address Address { get; set; }
}
我已经尝试添加一个专门的 class 来管理 SomeThingElse 的地址,但是,将其分解是没有意义的。我考虑过添加下面的两个字段,但拒绝了这个想法,因为数据库设计不佳。
public class Address
{
...
public Guid SomeThingElseId { get; set; }
public SomeThingElse SomeThingElse { get; set; }
}
最好是,这是一个关于继承的教科书案例,它引入了基数 class Contactable 并完全跳过了 Address。但我记得以前继承和 EF 不能很好地混合,在这种情况下会出现很多错误和陷阱。
是否有可靠的最佳实践来做到这一点?当我用谷歌搜索时,我没有找到任何值得信赖的东西。
根据评论中的讨论,我将进入详细答案:
您可以使用 EF Core 新引入的 Owned Entity 类型功能,其中 Address
是 Something
的 Owned Entity
类型,并且SomethingElse
而 Something
和 SomethingElse
的所有者如下:
modelBuilder.Entity<SomeThing>().OwnsOne(st => st.Address);
modelBuilder.Entity<SomeThingElse>().OwnsOne(st => st.Address);
按照惯例,EF Core 将按照模式 Navigation_OwnedEntityProperty 为拥有的实体类型的属性命名数据库列。因此 Address
属性将出现在 Something
和 SomethingElse
table 中,名称为 'Address_Street' 和 'Address_City'.
现在,如果您不希望拥有的实体类型列名称类似于 Navigation_OwnedEntityProperty,那么您可以按如下方式提供自定义列名称:
modelBuilder.Entity<SomeThing>().OwnsOne(st => st.Address,
a =>
{
a.Property(p => p.Street).HasColumnName("Street");
a.Property(p => p.City).HasColumnName("City");
});
modelBuilder.Entity<SomeThingElse>().OwnsOne(ste => ste.Address,
a =>
{
a.Property(p => p.Street).HasColumnName("Street");
a.Property(p => p.City).HasColumnName("City");
});
此外,拥有的类型可以存储在与所有者分开的 table 中。为了覆盖将拥有的类型映射到与所有者相同的 table 的约定,您可以简单地调用 ToTable
并提供不同的 table 名称,如下所示:
modelBuilder.Entity<SomeThing>().OwnsOne(st => st.Address,
a =>
{
a.ToTable("SomeThingAddress");
});
modelBuilder.Entity<SomeThingElse>().OwnsOne(ste => ste.Address,
a =>
{
a.ToTable("SomeThingElseAddress");
});
查询拥有的类型
当查询所有者时,默认情况下将包括拥有的类型。没有必要使用 Include 方法,即使拥有的类型存储在单独的 table.
中也是如此
限制
其中一些限制是自有实体类型工作方式的基础,但其他一些限制我们可能会在未来的版本中删除:
设计限制:
- 您不能为拥有的类型创建
DbSet<T>
- 您不能在
ModelBuilder
上使用拥有的类型调用 Entity<T>()
我想按照this blog解释如何配置一对一关系。它的想法是,一个实体获得另一个类型的 属性,而另一个实体获得前者类型的 属性 加上它的 ID 以创建外键。
不过,我的问题是,我想像这样断开两个不同 classes 的接触部分。 class SomeThing 已经重构并且与 class Address 一起工作得很好。但是,我不确定如何处理 class SomeThingElse.
public class SomeThing
{
public Guid Id { get; set; }
//public string Street { get; set; }
//public string City { get; set; }
public Address Address { get; set; }
}
public class Address
{
public Guid Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public Guid SomeThingId { get; set; }
public SomeThing SomeThing { get; set; }
}
public class SomeThingElse
{
public Guid Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
//public Address Address { get; set; }
}
我已经尝试添加一个专门的 class 来管理 SomeThingElse 的地址,但是,将其分解是没有意义的。我考虑过添加下面的两个字段,但拒绝了这个想法,因为数据库设计不佳。
public class Address
{
...
public Guid SomeThingElseId { get; set; }
public SomeThingElse SomeThingElse { get; set; }
}
最好是,这是一个关于继承的教科书案例,它引入了基数 class Contactable 并完全跳过了 Address。但我记得以前继承和 EF 不能很好地混合,在这种情况下会出现很多错误和陷阱。
是否有可靠的最佳实践来做到这一点?当我用谷歌搜索时,我没有找到任何值得信赖的东西。
根据评论中的讨论,我将进入详细答案:
您可以使用 EF Core 新引入的 Owned Entity 类型功能,其中 Address
是 Something
的 Owned Entity
类型,并且SomethingElse
而 Something
和 SomethingElse
的所有者如下:
modelBuilder.Entity<SomeThing>().OwnsOne(st => st.Address);
modelBuilder.Entity<SomeThingElse>().OwnsOne(st => st.Address);
按照惯例,EF Core 将按照模式 Navigation_OwnedEntityProperty 为拥有的实体类型的属性命名数据库列。因此 Address
属性将出现在 Something
和 SomethingElse
table 中,名称为 'Address_Street' 和 'Address_City'.
现在,如果您不希望拥有的实体类型列名称类似于 Navigation_OwnedEntityProperty,那么您可以按如下方式提供自定义列名称:
modelBuilder.Entity<SomeThing>().OwnsOne(st => st.Address,
a =>
{
a.Property(p => p.Street).HasColumnName("Street");
a.Property(p => p.City).HasColumnName("City");
});
modelBuilder.Entity<SomeThingElse>().OwnsOne(ste => ste.Address,
a =>
{
a.Property(p => p.Street).HasColumnName("Street");
a.Property(p => p.City).HasColumnName("City");
});
此外,拥有的类型可以存储在与所有者分开的 table 中。为了覆盖将拥有的类型映射到与所有者相同的 table 的约定,您可以简单地调用 ToTable
并提供不同的 table 名称,如下所示:
modelBuilder.Entity<SomeThing>().OwnsOne(st => st.Address,
a =>
{
a.ToTable("SomeThingAddress");
});
modelBuilder.Entity<SomeThingElse>().OwnsOne(ste => ste.Address,
a =>
{
a.ToTable("SomeThingElseAddress");
});
查询拥有的类型
当查询所有者时,默认情况下将包括拥有的类型。没有必要使用 Include 方法,即使拥有的类型存储在单独的 table.
中也是如此限制
其中一些限制是自有实体类型工作方式的基础,但其他一些限制我们可能会在未来的版本中删除:
设计限制:
- 您不能为拥有的类型创建
DbSet<T>
- 您不能在
ModelBuilder
上使用拥有的类型调用
Entity<T>()