Skip to content

Commit 2d51bc7

Browse files
committed
Add change tracking and query support for collections of owned types.
Improve detection of the inverse navigation for owned types. Fixes #8172
1 parent 956f339 commit 2d51bc7

25 files changed

+551
-603
lines changed

EFCore.Runtime.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
22
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=Microsoft_002EEntityFrameworkCore_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
3+
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EF/@EntryIndexedValue">EF</s:String>
34
<s:String x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=D44E9AA0167CE64B866A64486B319AB0/RelativePath/@EntryValue">..\EFCore.sln.DotSettings</s:String>
45
<s:Boolean x:Key="/Default/Environment/InjectedLayers/FileInjectedLayer/=D44E9AA0167CE64B866A64486B319AB0/@KeyIndexDefined">True</s:Boolean>
56
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileD44E9AA0167CE64B866A64486B319AB0/@KeyIndexDefined">True</s:Boolean>

src/EFCore.Specification.Tests/Query/ComplexNavigationsWeakQueryFixtureBase.cs

Lines changed: 66 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Linq;
6+
using Microsoft.EntityFrameworkCore.Metadata;
67
using Microsoft.EntityFrameworkCore.Metadata.Builders;
78
using Microsoft.EntityFrameworkCore.Metadata.Internal;
89
using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel;
@@ -33,18 +34,23 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
3334
.Ignore(e => e.OneToMany_Required_Self)
3435
.Ignore(e => e.OneToMany_Required_Self_Inverse)
3536
.Ignore(e => e.OneToMany_Optional_Self)
36-
.Ignore(e => e.OneToMany_Optional_Self_Inverse)
37-
.Ignore(e => e.OneToMany_Required)
38-
.Ignore(e => e.OneToMany_Optional);
37+
.Ignore(e => e.OneToMany_Optional_Self_Inverse);
3938

4039
var level1 = level1Builder.Metadata;
40+
41+
ForeignKey level2Fk;
4142
var level2 = level1.Model.AddEntityType(typeof(Level2), nameof(Level1.OneToOne_Required_PK), level1);
42-
var level2Fk = level2.AddForeignKey(level2.FindProperty(nameof(Level2.Id)), level1.FindPrimaryKey(), level1);
43-
level2Fk.HasPrincipalToDependent(nameof(Level1.OneToOne_Required_PK));
44-
level2Fk.IsUnique = true;
45-
level2Fk.DeleteBehavior = DeleteBehavior.Restrict;
43+
using (var batch = ((Model)modelBuilder.Model).ConventionDispatcher.StartBatch())
44+
{
45+
level2Fk = (ForeignKey)level2.AddForeignKey(level2.FindProperty(nameof(Level2.Id)), level1.FindPrimaryKey(), level1);
46+
level2Fk.HasPrincipalToDependent(nameof(Level1.OneToOne_Required_PK));
47+
level2Fk.HasDependentToPrincipal(nameof(Level2.OneToOne_Required_PK_Inverse));
48+
level2Fk.IsUnique = true;
49+
level2Fk.DeleteBehavior = DeleteBehavior.Restrict;
50+
level2Fk = batch.Run(level2Fk);
51+
}
4652

47-
Configure(new ReferenceOwnershipBuilder<Level1, Level2>((EntityType)level1, (EntityType)level2, ((ForeignKey)level2Fk).Builder));
53+
Configure(new ReferenceOwnershipBuilder<Level1, Level2>((EntityType)level1, level2Fk.DeclaringEntityType, level2Fk.Builder));
4854

4955
modelBuilder.Entity<InheritanceBase1>().Property(e => e.Id).ValueGeneratedNever();
5056
modelBuilder.Entity<InheritanceBase2>().Property(e => e.Id).ValueGeneratedNever();
@@ -89,10 +95,7 @@ protected virtual void Configure(ReferenceOwnershipBuilder<Level1, Level2> l2)
8995
.Ignore(e => e.OneToMany_Required_Self_Inverse)
9096
.Ignore(e => e.OneToMany_Optional_Self)
9197
.Ignore(e => e.OneToMany_Optional_Self_Inverse)
92-
.Ignore(e => e.OneToMany_Required)
93-
.Ignore(e => e.OneToMany_Required_Inverse)
94-
.Ignore(e => e.OneToMany_Optional)
95-
.Ignore(e => e.OneToMany_Optional_Inverse).OwnedEntityType;
98+
.OwnedEntityType;
9699

97100
l2.Property(e => e.Id).ValueGeneratedNever();
98101

@@ -112,13 +115,28 @@ protected virtual void Configure(ReferenceOwnershipBuilder<Level1, Level2> l2)
112115
.HasForeignKey<Level2>(e => e.Level1_Optional_Id)
113116
.IsRequired(false);
114117

118+
l2.HasOne(e => e.OneToMany_Required_Inverse)
119+
.WithMany(e => e.OneToMany_Required)
120+
.IsRequired()
121+
.OnDelete(DeleteBehavior.Restrict);
122+
123+
l2.HasOne(e => e.OneToMany_Optional_Inverse)
124+
.WithMany(e => e.OneToMany_Optional)
125+
.IsRequired(false);
126+
127+
ForeignKey level3Fk;
115128
var level3 = level2.Model.AddEntityType(typeof(Level3), nameof(Level2.OneToOne_Required_PK), level2);
116-
var level3Fk = level3.AddForeignKey(level3.FindProperty(nameof(Level3.Id)), level2.FindPrimaryKey(), level2);
117-
level3Fk.HasPrincipalToDependent(nameof(Level2.OneToOne_Required_PK));
118-
level3Fk.IsUnique = true;
119-
level3Fk.DeleteBehavior = DeleteBehavior.Restrict;
129+
using (var batch = ((Model)level2.Model).ConventionDispatcher.StartBatch())
130+
{
131+
level3Fk = (ForeignKey)level3.AddForeignKey(level3.FindProperty(nameof(Level3.Id)), level2.FindPrimaryKey(), level2);
132+
level3Fk.HasPrincipalToDependent(nameof(Level2.OneToOne_Required_PK));
133+
level3Fk.HasDependentToPrincipal(nameof(Level3.OneToOne_Required_PK_Inverse));
134+
level3Fk.IsUnique = true;
135+
level3Fk.DeleteBehavior = DeleteBehavior.Restrict;
136+
level3Fk = batch.Run(level3Fk);
137+
}
120138

121-
Configure(new ReferenceOwnershipBuilder<Level2, Level3>((EntityType)level2, (EntityType)level3, ((ForeignKey)level3Fk).Builder));
139+
Configure(new ReferenceOwnershipBuilder<Level2, Level3>((EntityType)level2, level3Fk.DeclaringEntityType, level3Fk.Builder));
122140
}
123141

124142
protected virtual void Configure(ReferenceOwnershipBuilder<Level2, Level3> l3)
@@ -128,10 +146,7 @@ protected virtual void Configure(ReferenceOwnershipBuilder<Level2, Level3> l3)
128146
.Ignore(e => e.OneToMany_Required_Self_Inverse)
129147
.Ignore(e => e.OneToMany_Optional_Self)
130148
.Ignore(e => e.OneToMany_Optional_Self_Inverse)
131-
.Ignore(e => e.OneToMany_Required)
132-
.Ignore(e => e.OneToMany_Required_Inverse)
133-
.Ignore(e => e.OneToMany_Optional)
134-
.Ignore(e => e.OneToMany_Optional_Inverse).OwnedEntityType;
149+
.OwnedEntityType;
135150

136151
l3.Property(e => e.Id).ValueGeneratedNever();
137152

@@ -151,13 +166,28 @@ protected virtual void Configure(ReferenceOwnershipBuilder<Level2, Level3> l3)
151166
.HasForeignKey<Level3>(e => e.Level2_Optional_Id)
152167
.IsRequired(false);
153168

169+
l3.HasOne(e => e.OneToMany_Required_Inverse)
170+
.WithMany(e => e.OneToMany_Required)
171+
.IsRequired()
172+
.OnDelete(DeleteBehavior.Restrict);
173+
174+
l3.HasOne(e => e.OneToMany_Optional_Inverse)
175+
.WithMany(e => e.OneToMany_Optional)
176+
.IsRequired(false);
177+
178+
ForeignKey level4Fk;
154179
var level4 = level3.Model.AddEntityType(typeof(Level4), nameof(Level3.OneToOne_Required_PK), level3);
155-
var level4Fk = level4.AddForeignKey(level4.FindProperty(nameof(Level4.Id)), level3.FindPrimaryKey(), level3);
156-
level4Fk.HasPrincipalToDependent(nameof(Level3.OneToOne_Required_PK));
157-
level4Fk.IsUnique = true;
158-
level4Fk.DeleteBehavior = DeleteBehavior.Restrict;
180+
using (var batch = ((Model)level3.Model).ConventionDispatcher.StartBatch())
181+
{
182+
level4Fk = (ForeignKey)level4.AddForeignKey(level4.FindProperty(nameof(Level4.Id)), level3.FindPrimaryKey(), level3);
183+
level4Fk.HasPrincipalToDependent(nameof(Level3.OneToOne_Required_PK));
184+
level4Fk.HasDependentToPrincipal(nameof(Level4.OneToOne_Required_PK_Inverse));
185+
level4Fk.IsUnique = true;
186+
level4Fk.DeleteBehavior = DeleteBehavior.Restrict;
187+
level4Fk = batch.Run(level4Fk);
188+
}
159189

160-
Configure(new ReferenceOwnershipBuilder<Level3, Level4>((EntityType)level3, (EntityType)level4, ((ForeignKey)level4Fk).Builder));
190+
Configure(new ReferenceOwnershipBuilder<Level3, Level4>((EntityType)level3, level4Fk.DeclaringEntityType, level4Fk.Builder));
161191
}
162192

163193
protected virtual void Configure(ReferenceOwnershipBuilder<Level3, Level4> l4)
@@ -166,9 +196,7 @@ protected virtual void Configure(ReferenceOwnershipBuilder<Level3, Level4> l4)
166196
.Ignore(e => e.OneToMany_Required_Self)
167197
.Ignore(e => e.OneToMany_Required_Self_Inverse)
168198
.Ignore(e => e.OneToMany_Optional_Self)
169-
.Ignore(e => e.OneToMany_Optional_Self_Inverse)
170-
.Ignore(e => e.OneToMany_Required_Inverse)
171-
.Ignore(e => e.OneToMany_Optional_Inverse);
199+
.Ignore(e => e.OneToMany_Optional_Self_Inverse);
172200

173201
l4.Property(e => e.Id).ValueGeneratedNever();
174202

@@ -187,6 +215,15 @@ protected virtual void Configure(ReferenceOwnershipBuilder<Level3, Level4> l4)
187215
.WithOne(e => e.OneToOne_Optional_FK)
188216
.HasForeignKey<Level4>(e => e.Level3_Optional_Id)
189217
.IsRequired(false);
218+
219+
l4.HasOne(e => e.OneToMany_Required_Inverse)
220+
.WithMany(e => e.OneToMany_Required)
221+
.IsRequired()
222+
.OnDelete(DeleteBehavior.Restrict);
223+
224+
l4.HasOne(e => e.OneToMany_Optional_Inverse)
225+
.WithMany(e => e.OneToMany_Optional)
226+
.IsRequired(false);
190227
}
191228

192229
protected override void Seed(ComplexNavigationsContext context)

0 commit comments

Comments
 (0)