@@ -20,6 +20,84 @@ public class TodoItem : Identifiable<int>
20
20
21
21
The left side of this relationship is of type ` TodoItem ` (public name: "todoItems") and the right side is of type ` Person ` (public name: "persons").
22
22
23
+ ### Required one-to-one relationships in Entity Framework Core
24
+
25
+ By default, Entity Framework Core generates an identifying foreign key for a required 1-to-1 relationship.
26
+ This means no foreign key column is generated, instead the primary keys point to each other directly.
27
+
28
+ The next example defines that each car requires an engine, while an engine is optionally linked to a car.
29
+
30
+ ``` c#
31
+ public sealed class Car : Identifiable <int >
32
+ {
33
+ [HasOne ]
34
+ public Engine Engine { get ; set ; }
35
+ }
36
+
37
+ public sealed class Engine : Identifiable <int >
38
+ {
39
+ [HasOne ]
40
+ public Car Car { get ; set ; }
41
+ }
42
+
43
+ public sealed class AppDbContext : DbContext
44
+ {
45
+ protected override void OnModelCreating (ModelBuilder builder )
46
+ {
47
+ builder .Entity <Car >()
48
+ .HasOne (car => car .Engine )
49
+ .WithOne (engine => engine .Car )
50
+ .HasForeignKey <Car >()
51
+ .IsRequired ();
52
+ }
53
+ }
54
+ ```
55
+
56
+ Which results in EF Core generating the next database objects:
57
+ ``` sql
58
+ CREATE TABLE "Engine " (
59
+ " Id" integer GENERATED BY DEFAULT AS IDENTITY,
60
+ CONSTRAINT " PK_Engine" PRIMARY KEY (" Id" )
61
+ );
62
+ CREATE TABLE "Cars " (
63
+ " Id" integer NOT NULL ,
64
+ CONSTRAINT " PK_Cars" PRIMARY KEY (" Id" ),
65
+ CONSTRAINT " FK_Cars_Engine_Id" FOREIGN KEY (" Id" ) REFERENCES " Engine" (" Id" )
66
+ ON DELETE CASCADE
67
+ );
68
+ ```
69
+
70
+ That mechanism does not make sense for JSON: API , because patching a relationship would result in also
71
+ changing the identity of a resource. Naming the foreign key explicitly fixes the problem by forcing to
72
+ create a foreign key column.
73
+
74
+ ``` c#
75
+ protected override void OnModelCreating (ModelBuilder builder )
76
+ {
77
+ builder .Entity <Car >()
78
+ .HasOne (car => car .Engine )
79
+ .WithOne (engine => engine .Car )
80
+ .HasForeignKey <Car >(" EngineId" ) // Explicit foreign key name added
81
+ .IsRequired ();
82
+ }
83
+ ```
84
+
85
+ Which generates the correct database objects:
86
+ ``` sql
87
+ CREATE TABLE "Engine " (
88
+ " Id" integer GENERATED BY DEFAULT AS IDENTITY,
89
+ CONSTRAINT " PK_Engine" PRIMARY KEY (" Id" )
90
+ );
91
+ CREATE TABLE "Cars " (
92
+ " Id" integer GENERATED BY DEFAULT AS IDENTITY,
93
+ " EngineId" integer NOT NULL ,
94
+ CONSTRAINT " PK_Cars" PRIMARY KEY (" Id" ),
95
+ CONSTRAINT " FK_Cars_Engine_EngineId" FOREIGN KEY (" EngineId" ) REFERENCES " Engine" (" Id" )
96
+ ON DELETE CASCADE
97
+ );
98
+ CREATE UNIQUE INDEX "IX_Cars_EngineId " ON " Cars" (" EngineId" );
99
+ ```
100
+
23
101
## HasMany
24
102
25
103
This exposes a to-many relationship.
0 commit comments