如何在 EF 中创建从两个表到一个源的一对一映射?
Posted
技术标签:
【中文标题】如何在 EF 中创建从两个表到一个源的一对一映射?【英文标题】:How to create one-to-one mapping in EF from two tables to one source? 【发布时间】:2022-01-06 04:02:15 【问题描述】:我想要 2 个模型,例如“人”和“动物”。两者都在 DB (postrge) 中建模,带有 image_binary_id
列。
public class Person
public long Id get; set;
public string Name get; set;
public ImageBinary ImageBinary get; set;
public class Animal
public long Id get; set;
public string Name get; set;
public ImageBinary ImageBinary get; set;
现在,我希望图像数据表使用模型为两个对象“提供”图像:
public class ImageBinary
public long Id get; set;
public string Name get; set;
public byte[] Data get; set;
在数据库中,我有外键连接“person.image_binary_id => image_binary.id”
如何在代码中定义映射,以便在 1 个事务中正确插入,如下所示:
var image = new ImageBinary(...);
var person = new Person()
...,
ImageBinary = image
PersonRepository.AddPerson(person);
我尝试像这样映射person
,但这会导致插入时 image_binary_id 为null
:
entity.HasOne(x => x.ImageBinary)
.WithOne()
.HasForeignKey("ImageBinary", "Id");
我知道如果“ImageBinary”表将包含person
\animal
列,这可能会解决它,因为它将返回“导航”(将参数添加到WithOne()
)-但我不想添加更多列(除非我必须...)。
我曾考虑过添加联结表(person_id、image_binary_id),但这似乎很难维护,因为我还必须为所有未来的模型添加一个。
将 .NET 5 与 EF Core 版本 5 结合使用。
欢迎任何想法和解决方案。
【问题讨论】:
除非我必须这样做 -- 你最好这样做。我一直发现这是解决这种多态关联的最佳方案。甚至为每个实体创建一个图像表。真的没有听起来那么糟糕。 好的,为了澄清,您建议在ImageBinary
表中添加列,其中包含引用对象的类型?在这种情况下,额外的列将是 entity_type
,其值选项为 person \ animal
- 因此来自该表的查询将基于 Id + 类型?
不,我会为每个实体添加一个外键,这样您就有了数据完整性。
【参考方案1】:
这是您尝试做的代码的第一个实现。
public class Person
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id get; set;
public string Name get; set;
public long ImageBinRef get; set;
[ForeignKey("ImageBinRef")]
//or [ForeignKey(nameof(ImageBinRef))] I like this version better
public ImageBinary ImageBinary get; set;
这是我在这里所做的一些解释
Key 属性告诉 Ef Id 是主键
DatabaseGenerated(DatabaseGeneratedOption.Identity) 告诉 ef 它是 自动递增
ForeignKey 属性将 fk 约束和索引添加到 ImageBinRef 我在回答中为您定义的属性,因此您尝试运行的示例现在可以工作
这里的另一件重要的事情是您的 ImageBinary 类的主键是 long 类型,它不能为空并且不接受 null 作为值。 这很重要,因为现在当您删除人员记录时,如果您不希望删除该记录,它还将删除与该记录相关的 ImageBinary 记录(我不知道这是否是您想要的),只需像这样声明属性
public long? ImageBinRef get; set; //Notice the question mark
问号表示它是一个可以为空的类型,所以现在当您删除人员记录时,它不会删除引用的图像记录..
请注意,默认情况下字符串可以为空,因此您无需担心:
假设你有 COUNTRIES 表和 PERSON 表
public class PERSON
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PersonRowid get;set:
public string PersonName get;set:
public string PersonCountryCode get;set;
[ForeignKey("PersonCountryCode")]
public COUNTRIES Country get;set;
public class COUNTRIES
[Key]
public string CountryCode get;set:
public string CountryName get;set:
在此示例中,当您删除人员时,国家/地区记录仍将保留在表中,但是如果您在删除人员记录时将 countrycode 的属性类型从 string 更改为 int,它也会从数据库中删除该国家/地区可能不是您想要的,为了防止这种情况,我们将属性定义为可为空的..
抱歉,如果我打错字了,我在添加代码示例时没有使用编译器。
编辑:
public class Animal
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id get; set;
public string Name get; set;
public long ImageBinRef get; set;
[ForeignKey("ImageBinRef")]
public ImageBinary ImageBinary get; set;
【讨论】:
你错过了问题的本质。Animal
课程在哪里?这是关于指向一个引用的两个类。需要与否都是无关紧要的。
@GertArnold 我已经相应地编辑了答案。我向他展示了如何做指点没关系。他也可以轻松做到这一点
是的,现在你有一些你显然没有测试过的东西。这真的不是你不编译就直接输入的东西,更不用说测试了。以上是关于如何在 EF 中创建从两个表到一个源的一对一映射?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Android 11 中创建从图库中选择图像的意图?
如何在 Python 中创建从 Pub/Sub 到 GCS 的数据流管道