diff --git a/entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md
index 13b4d68282..0091fd8bc6 100644
--- a/entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md
+++ b/entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md
@@ -562,6 +562,124 @@ protected override void Up(MigrationBuilder migrationBuilder)
## Model building
+
+
+### Auto-compiled models
+
+> [!TIP]
+> The code shown here comes from the [NewInEFCore9.CompiledModels](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/) sample.
+
+Compiled models can improve startup time for applications with large models--that is entity type counts in the 100s or 1000s. In previous versions of EF Core, a compiled model had to be generated manually, using the command line. For example:
+
+```dotnetcli
+dotnet ef dbcontext optimize
+```
+
+After running the command, a line like, `.UseModel(MyCompiledModels.BlogsContextModel.Instance)` must be added to `OnConfiguring` to tell EF Core to use the compiled model.
+
+Starting with EF9, this `.UseModel` line is no longer needed when the application's `DbContext` type is in the same project/assembly as the compiled model. Instead, the compiled model will be detected and used automatically. This can be seen by having EF log whenever it is building the model. Running a simple application then shows EF building the model when the application starts:
+
+```output
+Starting application...
+>> EF is building the model...
+Model loaded with 2 entity types.
+```
+
+The output from running `dotnet ef dbcontext optimize` on the model project is:
+
+```output
+PS D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model> dotnet ef dbcontext optimize
+
+Build succeeded in 0.3s
+
+Build succeeded in 0.3s
+Build started...
+Build succeeded.
+>> EF is building the model...
+>> EF is building the model...
+Successfully generated a compiled model, it will be discovered automatically, but you can also call 'options.UseModel(BlogsContextModel.Instance)'. Run this command again when the model is modified.
+PS D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model>
+```
+
+Notice that the log output indicates that the _model was built when running the command_. If we now run the application again, after rebuilding but without making any code changes, then the output is:
+
+```output
+Starting application...
+Model loaded with 2 entity types.
+```
+
+Notice that the model was not built when starting the application because the compiled model was detected and used automatically.
+
+### MSBuild integration
+
+With the above approach, the compiled model still needs to be regenerated manually when the entity types or `DbContext` configuration is changed. However, EF9 ships with MSBuild and targets package that can automatically update the compiled model when the model project is built! To get started, install the [Microsoft.EntityFrameworkCore.Tasks](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tasks/) NuGet package. For example:
+
+```dotnetcli
+dotnet add package Microsoft.EntityFrameworkCore.Tasks --version 9.0.0-preview.4.24205.3
+```
+
+> [!TIP]
+> Use the package version in the command above that matches the version of EF Core that you are using.
+
+Then enable the integration by setting the `EFOptimizeContext` property to your `.csproj` file. For example:
+
+```xml
+
+ true
+
+```
+
+There are additional, optional, MSBuild properties for controlling how the model is built, equivalent to the options passed on the command line to `dotnet ef dbcontext optimize`. These include:
+
+| MSBuild property | Description |
+|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| EFOptimizeContext | Set to `true` to enable auto-compiled models. |
+| DbContextName | The DbContext class to use. Class name only or fully qualified with namespaces. If this option is omitted, EF Core will find the context class. If there are multiple context classes, this option is required. |
+| EFStartupProject | Relative path to the startup project. Default value is the current folder. |
+| EFTargetNamespace | The namespace to use for all generated classes. Defaults to generated from the root namespace and the output directory plus CompiledModels. |
+
+In our example, we need to specify the startup project:
+
+```xml
+
+ true
+ ..\App\App.csproj
+
+```
+
+Now, if we build the project, we can see logging at build time indicating that the compiled model is being built:
+
+```output
+Optimizing DbContext...
+dotnet exec --depsfile D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\App\bin\Release\net8.0\App.deps.json
+ --additionalprobingpath G:\packages
+ --additionalprobingpath "C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages"
+ --runtimeconfig D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\App\bin\Release\net8.0\App.runtimeconfig.json G:\packages\microsoft.entityframeworkcore.tasks\9.0.0-preview.4.24205.3\tasks\net8.0\..\..\tools\netcoreapp2.0\ef.dll dbcontext optimize --output-dir D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model\obj\Release\net8.0\
+ --namespace NewInEfCore9
+ --suffix .g
+ --assembly D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model\bin\Release\net8.0\Model.dll --startup-assembly D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\App\bin\Release\net8.0\App.dll
+ --project-dir D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model
+ --root-namespace NewInEfCore9
+ --language C#
+ --nullable
+ --working-dir D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\App
+ --verbose
+ --no-color
+ --prefix-output
+```
+
+And running the application shows that the compiled model has been detected and hence the model is not built again:
+
+```output
+Starting application...
+Model loaded with 2 entity types.
+```
+
+Now, whenever the model changes, the compiled model will be automatically rebuilt as soon as the project is built.
+
+> [NOTE!]
+> We are working through some performance issues with changes made to the compiled model in EF8 and EF9. See [Issue 33483#](https://github.com/dotnet/efcore/issues/33483) for more information.
+
### Specify caching for sequences
diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj
new file mode 100644
index 0000000000..20df067599
--- /dev/null
+++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj
@@ -0,0 +1,22 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/Program.cs b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/Program.cs
new file mode 100644
index 0000000000..e951ea4fb4
--- /dev/null
+++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/Program.cs
@@ -0,0 +1,13 @@
+using NewInEfCore9;
+
+public class Program
+{
+ public static void Main()
+ {
+ Console.WriteLine("Starting application...");
+
+ using var context = new BlogsContext();
+
+ Console.WriteLine($"Model loaded with {context.Model.GetEntityTypes().Count()} entity types.");
+ }
+}
diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/BlogsContext.cs b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/BlogsContext.cs
new file mode 100644
index 0000000000..af044eb4a5
--- /dev/null
+++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/BlogsContext.cs
@@ -0,0 +1,14 @@
+using Microsoft.EntityFrameworkCore.Diagnostics;
+
+namespace NewInEfCore9;
+
+public class BlogsContext : DbContext
+{
+ public DbSet Blogs => Set();
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ => optionsBuilder
+ .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EF9CompiledModels;ConnectRetryCount=0")
+ .LogTo(_ => Console.WriteLine(">> EF is building the model..."), [CoreEventId.ShadowPropertyCreated])
+ .EnableSensitiveDataLogging();
+}
diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/EntityTypes.cs b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/EntityTypes.cs
new file mode 100644
index 0000000000..68749a3845
--- /dev/null
+++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/EntityTypes.cs
@@ -0,0 +1,16 @@
+namespace NewInEfCore9;
+
+public class Blog
+{
+ public int Id { get; set; }
+
+ public ICollection Posts { get; } = new List();
+}
+
+public class Post
+{
+ public int Id { get; set; }
+ public string? Title { get; set; }
+
+ public Blog Blog { get; set; } = null!;
+}
diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj
new file mode 100644
index 0000000000..92369134bc
--- /dev/null
+++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj
@@ -0,0 +1,39 @@
+
+
+
+ library
+ net8.0
+ enable
+ enable
+ NewInEfCore9
+ Preview
+
+
+
+ true
+ ..\App\App.csproj
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs b/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs
index 35dc53eedc..6dbbf336e6 100644
--- a/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs
+++ b/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs
@@ -214,10 +214,19 @@ public class CustomerContext(bool useSqlite = false) : DbContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> (UseSqlite
- ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db")
+ ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db",
+ sqliteOptionsBuilder =>
+ {
+ sqliteOptionsBuilder.UseNetTopologySuite();
+ sqliteOptionsBuilder.CommandTimeout(0);
+ })
: optionsBuilder.UseSqlServer(
@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0",
- sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite()))
+ sqlServerOptionsBuilder =>
+ {
+ sqlServerOptionsBuilder.UseNetTopologySuite();
+ sqlServerOptionsBuilder.CommandTimeout(0);
+ }))
.EnableSensitiveDataLogging()
.LogTo(Console.WriteLine, LogLevel.Information);
diff --git a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj
index 29b8b89380..45bacb8f74 100644
--- a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj
+++ b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj
@@ -10,15 +10,15 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/samples/core/Samples.sln b/samples/core/Samples.sln
index 71587ef8bf..13b6ced270 100644
--- a/samples/core/Samples.sln
+++ b/samples/core/Samples.sln
@@ -197,6 +197,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NewInEFCore8", "Miscellaneo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NewInEFCore9", "Miscellaneous\NewInEFCore9\NewInEFCore9.csproj", "{3F17B59C-7D33-4BF0-B386-ACFE76D45697}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NewInEFCore9.CompiledModels", "NewInEFCore9.CompiledModels", "{26184A10-7CF8-4ED2-9F70-E00A55BE063B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "Miscellaneous\NewInEFCore9.CompiledModels\App\App.csproj", "{22548A1B-0833-49E9-A04E-A7E8690EAE03}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Miscellaneous\NewInEFCore9.CompiledModels\Model\Model.csproj", "{8E9DD759-B6D0-4424-BC6C-97ECE559CE02}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -547,6 +553,14 @@ Global
{3F17B59C-7D33-4BF0-B386-ACFE76D45697}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F17B59C-7D33-4BF0-B386-ACFE76D45697}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F17B59C-7D33-4BF0-B386-ACFE76D45697}.Release|Any CPU.Build.0 = Release|Any CPU
+ {22548A1B-0833-49E9-A04E-A7E8690EAE03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {22548A1B-0833-49E9-A04E-A7E8690EAE03}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {22548A1B-0833-49E9-A04E-A7E8690EAE03}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {22548A1B-0833-49E9-A04E-A7E8690EAE03}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8E9DD759-B6D0-4424-BC6C-97ECE559CE02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8E9DD759-B6D0-4424-BC6C-97ECE559CE02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8E9DD759-B6D0-4424-BC6C-97ECE559CE02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8E9DD759-B6D0-4424-BC6C-97ECE559CE02}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -633,6 +647,9 @@ Global
{72C964FF-07C3-4234-B277-D91C3D83BAEC} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
{F9CA30FF-70A9-4EA5-8F12-7B08A695AB8F} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
{3F17B59C-7D33-4BF0-B386-ACFE76D45697} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
+ {26184A10-7CF8-4ED2-9F70-E00A55BE063B} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
+ {22548A1B-0833-49E9-A04E-A7E8690EAE03} = {26184A10-7CF8-4ED2-9F70-E00A55BE063B}
+ {8E9DD759-B6D0-4424-BC6C-97ECE559CE02} = {26184A10-7CF8-4ED2-9F70-E00A55BE063B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {20C98D35-54EF-46A6-8F3B-1855C1AE4F70}
diff --git a/samples/core/Samples.sln.DotSettings b/samples/core/Samples.sln.DotSettings
index 0d90266523..8da6af6279 100644
--- a/samples/core/Samples.sln.DotSettings
+++ b/samples/core/Samples.sln.DotSettings
@@ -115,6 +115,7 @@
$object$_On$event$
<Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" />
<Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Public" Description="Test Methods"><ElementKinds><Kind Name="TEST_MEMBER" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="Aa_bb" /></Policy>
+ <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy>
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
$object$_On$event$
@@ -135,6 +136,7 @@
True
True
True
+ True
True
True
True