Skip to content

Commit acd93f8

Browse files
committed
Re-write cascade delete documentation
Fixes #2906 Fixes #828 Fixes #473
1 parent ae420d9 commit acd93f8

File tree

9 files changed

+1475
-209
lines changed

9 files changed

+1475
-209
lines changed

entity-framework/core/saving/cascade-delete.md

Lines changed: 467 additions & 209 deletions
Large diffs are not rendered by default.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp3.1</TargetFramework>
6+
<RootNamespace />
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.1" />
11+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.1" />
12+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.1" />
13+
</ItemGroup>
14+
15+
</Project>
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Microsoft.EntityFrameworkCore;
5+
using Microsoft.EntityFrameworkCore.Diagnostics;
6+
7+
namespace IntroOptional
8+
{
9+
public static class IntroOptionalSamples
10+
{
11+
public static void Deleting_principal_parent_1b()
12+
{
13+
Console.WriteLine($">>>> Sample: {nameof(Deleting_principal_parent_1b)}");
14+
Console.WriteLine();
15+
16+
Helpers.RecreateCleanDatabase();
17+
Helpers.PopulateDatabase();
18+
19+
#region Deleting_principal_parent_1b()
20+
using var context = new BlogsContext();
21+
22+
var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();
23+
24+
context.Remove(blog);
25+
26+
context.SaveChanges();
27+
#endregion
28+
29+
Console.WriteLine();
30+
}
31+
32+
public static void Severing_a_relationship_1b()
33+
{
34+
Console.WriteLine($">>>> Sample: {nameof(Severing_a_relationship_1b)}");
35+
Console.WriteLine();
36+
37+
Helpers.RecreateCleanDatabase();
38+
Helpers.PopulateDatabase();
39+
40+
#region Severing_a_relationship_1b()
41+
using var context = new BlogsContext();
42+
43+
var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();
44+
45+
foreach (var post in blog.Posts)
46+
{
47+
post.Blog = null;
48+
}
49+
50+
context.SaveChanges();
51+
#endregion
52+
53+
Console.WriteLine();
54+
}
55+
56+
public static void Severing_a_relationship_2b()
57+
{
58+
Console.WriteLine($">>>> Sample: {nameof(Severing_a_relationship_2b)}");
59+
Console.WriteLine();
60+
61+
Helpers.RecreateCleanDatabase();
62+
Helpers.PopulateDatabase();
63+
64+
#region Severing_a_relationship_1b()
65+
using var context = new BlogsContext();
66+
67+
var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();
68+
69+
blog.Posts.Clear();
70+
71+
context.SaveChanges();
72+
#endregion
73+
74+
Console.WriteLine();
75+
}
76+
}
77+
78+
public static class Helpers
79+
{
80+
public static void RecreateCleanDatabase()
81+
{
82+
using var context = new BlogsContext(quiet: true);
83+
84+
context.Database.EnsureDeleted();
85+
context.Database.EnsureCreated();
86+
}
87+
88+
public static void PopulateDatabase()
89+
{
90+
using var context = new BlogsContext(quiet: true);
91+
92+
context.Add(
93+
new Blog
94+
{
95+
Name = ".NET Blog",
96+
Posts =
97+
{
98+
new Post
99+
{
100+
Title = "Announcing the Release of EF Core 5.0",
101+
Content = "Announcing the release of EF Core 5.0, a full featured cross-platform..."
102+
},
103+
new Post
104+
{
105+
Title = "Announcing F# 5",
106+
Content = "F# 5 is the latest version of F#, the functional programming language..."
107+
},
108+
}
109+
});
110+
111+
context.SaveChanges();
112+
}
113+
}
114+
115+
#region Model
116+
public class Blog
117+
{
118+
public int Id { get; set; }
119+
120+
public string Name { get; set; }
121+
122+
public IList<Post> Posts { get; } = new List<Post>();
123+
}
124+
125+
public class Post
126+
{
127+
public int Id { get; set; }
128+
129+
public string Title { get; set; }
130+
public string Content { get; set; }
131+
132+
public int? BlogId { get; set; }
133+
public Blog Blog { get; set; }
134+
}
135+
#endregion
136+
137+
public class BlogsContext : DbContext
138+
{
139+
private readonly bool _quiet;
140+
141+
public BlogsContext(bool quiet = false)
142+
{
143+
_quiet = quiet;
144+
}
145+
146+
public DbSet<Blog> Blogs { get; set; }
147+
public DbSet<Post> Posts { get; set; }
148+
149+
protected override void OnModelCreating(ModelBuilder modelBuilder)
150+
{
151+
modelBuilder
152+
.Entity<Blog>()
153+
.HasMany(e => e.Posts)
154+
.WithOne(e => e.Blog)
155+
.OnDelete(DeleteBehavior.ClientSetNull);
156+
}
157+
158+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
159+
{
160+
optionsBuilder
161+
.EnableSensitiveDataLogging()
162+
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;ConnectRetryCount=0");
163+
//.UseSqlite("DataSource=test.db");
164+
165+
if (!_quiet)
166+
{
167+
optionsBuilder.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted });
168+
}
169+
}
170+
}
171+
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Microsoft.EntityFrameworkCore;
5+
using Microsoft.EntityFrameworkCore.Diagnostics;
6+
7+
namespace IntroRequired
8+
{
9+
public static class IntroRequiredSamples
10+
{
11+
public static void Deleting_principal_parent_1()
12+
{
13+
Console.WriteLine($">>>> Sample: {nameof(Deleting_principal_parent_1)}");
14+
Console.WriteLine();
15+
16+
Helpers.RecreateCleanDatabase();
17+
Helpers.PopulateDatabase();
18+
19+
#region Deleting_principal_parent_1
20+
using var context = new BlogsContext();
21+
22+
var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();
23+
24+
context.Remove(blog);
25+
26+
context.SaveChanges();
27+
#endregion
28+
29+
Console.WriteLine();
30+
}
31+
32+
public static void Severing_a_relationship_1()
33+
{
34+
Console.WriteLine($">>>> Sample: {nameof(Severing_a_relationship_1)}");
35+
Console.WriteLine();
36+
37+
Helpers.RecreateCleanDatabase();
38+
Helpers.PopulateDatabase();
39+
40+
#region Severing_a_relationship_1
41+
using var context = new BlogsContext();
42+
43+
var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();
44+
45+
foreach (var post in blog.Posts)
46+
{
47+
post.Blog = null;
48+
}
49+
50+
context.SaveChanges();
51+
#endregion
52+
53+
Console.WriteLine();
54+
}
55+
56+
public static void Severing_a_relationship_2()
57+
{
58+
Console.WriteLine($">>>> Sample: {nameof(Severing_a_relationship_2)}");
59+
Console.WriteLine();
60+
61+
Helpers.RecreateCleanDatabase();
62+
Helpers.PopulateDatabase();
63+
64+
#region Severing_a_relationship_2
65+
using var context = new BlogsContext();
66+
67+
var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();
68+
69+
blog.Posts.Clear();
70+
71+
context.SaveChanges();
72+
#endregion
73+
74+
Console.WriteLine();
75+
}
76+
77+
public static void Where_cascading_behaviors_happen_1()
78+
{
79+
Console.WriteLine($">>>> Sample: {nameof(Where_cascading_behaviors_happen_1)}");
80+
Console.WriteLine();
81+
82+
Helpers.RecreateCleanDatabase();
83+
Helpers.PopulateDatabase();
84+
85+
#region Where_cascading_behaviors_happen_1
86+
using var context = new BlogsContext();
87+
88+
var blog = context.Blogs.OrderBy(e => e.Name).First();
89+
90+
context.Remove(blog);
91+
92+
context.SaveChanges();
93+
#endregion
94+
95+
Console.WriteLine();
96+
}
97+
}
98+
99+
public static class Helpers
100+
{
101+
public static void RecreateCleanDatabase()
102+
{
103+
using var context = new BlogsContext(quiet: true);
104+
105+
context.Database.EnsureDeleted();
106+
context.Database.EnsureCreated();
107+
}
108+
109+
public static void PopulateDatabase()
110+
{
111+
using var context = new BlogsContext(quiet: true);
112+
113+
context.Add(
114+
new Blog
115+
{
116+
Name = ".NET Blog",
117+
Posts =
118+
{
119+
new Post
120+
{
121+
Title = "Announcing the Release of EF Core 5.0",
122+
Content = "Announcing the release of EF Core 5.0, a full featured cross-platform..."
123+
},
124+
new Post
125+
{
126+
Title = "Announcing F# 5",
127+
Content = "F# 5 is the latest version of F#, the functional programming language..."
128+
},
129+
}
130+
});
131+
132+
context.SaveChanges();
133+
}
134+
}
135+
136+
#region Model
137+
public class Blog
138+
{
139+
public int Id { get; set; }
140+
141+
public string Name { get; set; }
142+
143+
public IList<Post> Posts { get; } = new List<Post>();
144+
}
145+
146+
public class Post
147+
{
148+
public int Id { get; set; }
149+
150+
public string Title { get; set; }
151+
public string Content { get; set; }
152+
153+
public int BlogId { get; set; }
154+
public Blog Blog { get; set; }
155+
}
156+
#endregion
157+
158+
public class BlogsContext : DbContext
159+
{
160+
private readonly bool _quiet;
161+
162+
public BlogsContext(bool quiet = false)
163+
{
164+
_quiet = quiet;
165+
}
166+
167+
public DbSet<Blog> Blogs { get; set; }
168+
public DbSet<Post> Posts { get; set; }
169+
170+
protected override void OnModelCreating(ModelBuilder modelBuilder)
171+
{
172+
modelBuilder.Entity<Blog>().HasMany(e => e.Posts).WithOne(e => e.Blog); //.OnDelete(DeleteBehavior.ClientSetNull);
173+
}
174+
175+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
176+
{
177+
optionsBuilder
178+
.EnableSensitiveDataLogging()
179+
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;ConnectRetryCount=0");
180+
//.UseSqlite("DataSource=test.db");
181+
182+
if (!_quiet)
183+
{
184+
optionsBuilder.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted });
185+
}
186+
}
187+
}
188+
}

0 commit comments

Comments
 (0)