Skip to content

Commit 735dff7

Browse files
committed
Add auto-compiled models to What's New
1 parent 22c610f commit 735dff7

File tree

9 files changed

+259
-11
lines changed

9 files changed

+259
-11
lines changed

entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,124 @@ protected override void Up(MigrationBuilder migrationBuilder)
562562

563563
## Model building
564564

565+
<a name="auto-compiled-models"></a>
566+
567+
### Auto-compiled models
568+
569+
> [!TIP]
570+
> The code shown here comes from the [NewInEFCore9.CompiledModels](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/) sample.
571+
572+
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:
573+
574+
```dotnetcli
575+
dotnet ef dbcontext optimize
576+
```
577+
578+
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.
579+
580+
Starting with EF9, this `.UseModel` line is no longer needed. 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:
581+
582+
```output
583+
Starting application...
584+
>> EF is building the model...
585+
Model loaded model with 2 entity types.
586+
```
587+
588+
The output from running `dotnet ef dbcontext optimize` on the model project is:
589+
590+
```output
591+
PS D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model> dotnet ef dbcontext optimize
592+
593+
Build succeeded in 0.3s
594+
595+
Build succeeded in 0.3s
596+
Build started...
597+
Build succeeded.
598+
>> EF is building the model...
599+
>> EF is building the model...
600+
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.
601+
PS D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model>
602+
```
603+
604+
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:
605+
606+
```output
607+
Starting application...
608+
Model loaded model with 2 entity types.
609+
```
610+
611+
Notice that the model was not built when starting the application because the compiled model was detected and used automatically.
612+
613+
### MSBuild integration
614+
615+
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:
616+
617+
```dotnetcli
618+
dotnet add package Microsoft.EntityFrameworkCore.Tasks --version 9.0.0-preview.4.24205.3
619+
```
620+
621+
> [!TIP]
622+
> Use the package version in the command above that matches the version of EF Core that you are using.
623+
624+
Then enable the integration by setting the `EFOptimizeContext` property to your `.csproj` file. For example:
625+
626+
```xml
627+
<PropertyGroup>
628+
<EFOptimizeContext>true</EFOptimizeContext>
629+
</PropertyGroup>
630+
```
631+
632+
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:
633+
634+
| MSBuild property | Description |
635+
|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
636+
| EFOptimizeContext | Set to `true` to enable auto-compiled models. |
637+
| 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. |
638+
| EFStartupProject | Relative path to the project folder of the startup project. Default value is the current folder. |
639+
| EFTargetNamespace | The namespace to use for all generated classes. Defaults to generated from the root namespace and the output directory plus CompiledModels. |
640+
641+
In our example, we need to specify the startup project:
642+
643+
```xml
644+
<PropertyGroup>
645+
<EFOptimizeContext>true</EFOptimizeContext>
646+
<EFStartupProject>..\App\App.csproj</EFStartupProject>
647+
</PropertyGroup>
648+
```
649+
650+
Now, if we build the project, we can see logging at build time indicating that the compiled model is being built:
651+
652+
```
653+
Optimizing DbContext...
654+
dotnet exec --depsfile D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\App\bin\Release\net8.0\App.deps.json
655+
--additionalprobingpath G:\packages
656+
--additionalprobingpath "C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages"
657+
--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\
658+
--namespace NewInEfCore9
659+
--suffix .g
660+
--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
661+
--project-dir D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model
662+
--root-namespace NewInEfCore9
663+
--language C#
664+
--nullable
665+
--working-dir D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\App
666+
--verbose
667+
--no-color
668+
--prefix-output
669+
```
670+
671+
And running the application shows that the compiled model has been detected and hence the model is not built again:
672+
673+
```output
674+
Starting application...
675+
Model loaded model with 2 entity types.
676+
```
677+
678+
Now, whenever the model changes, the compiled model will be automatically rebuilt as soon as the project is built.
679+
680+
> [NOTE!]
681+
> 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.
682+
565683
<a name="sequence-caching"></a>
566684

567685
### Specify caching for sequences
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<RootNamespace/>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-preview.4.24205.3">
13+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
14+
<PrivateAssets>all</PrivateAssets>
15+
</PackageReference>
16+
</ItemGroup>
17+
18+
<ItemGroup>
19+
<ProjectReference Include="..\Model\Model.csproj" />
20+
</ItemGroup>
21+
22+
</Project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using NewInEfCore9;
2+
3+
public class Program
4+
{
5+
public static void Main()
6+
{
7+
Console.WriteLine("Starting application...");
8+
9+
using var context = new BlogsContext();
10+
11+
Console.WriteLine($"Model loaded model with {context.Model.GetEntityTypes().Count()} entity types.");
12+
}
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Microsoft.EntityFrameworkCore.Diagnostics;
2+
3+
namespace NewInEfCore9;
4+
5+
public class BlogsContext : DbContext
6+
{
7+
public DbSet<Blog> Blogs => Set<Blog>();
8+
9+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
10+
=> optionsBuilder
11+
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EF9CompiledModels;ConnectRetryCount=0")
12+
.LogTo(_ => Console.WriteLine(">> EF is building the model..."), [CoreEventId.ShadowPropertyCreated])
13+
.EnableSensitiveDataLogging();
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace NewInEfCore9;
2+
3+
public class Blog
4+
{
5+
public int Id { get; set; }
6+
7+
public ICollection<Post> Posts { get; } = new List<Post>();
8+
}
9+
10+
public class Post
11+
{
12+
public int Id { get; set; }
13+
public string? Title { get; set; }
14+
15+
public Blog Blog { get; set; } = null!;
16+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>library</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<RootNamespace>NewInEfCore9</RootNamespace>
9+
<LangVersion>Preview</LangVersion>
10+
</PropertyGroup>
11+
12+
<PropertyGroup>
13+
<EFOptimizeContext>true</EFOptimizeContext>
14+
<EFStartupProject>..\App\App.csproj</EFStartupProject>
15+
</PropertyGroup>
16+
17+
<ItemGroup>
18+
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-preview.4.24205.3">
19+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
20+
<PrivateAssets>all</PrivateAssets>
21+
</PackageReference>
22+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-preview.4.24205.3" />
23+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-preview.4.24205.3" />
24+
<PackageReference Include="Microsoft.EntityFrameworkCore.Tasks" Version="9.0.0-preview.4.24205.3" />
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<Using Include="System.ComponentModel.DataAnnotations" />
29+
<Using Include="System.ComponentModel.DataAnnotations.Schema" />
30+
<Using Include="System.Data.Common" />
31+
<Using Include="System.Linq.Expressions" />
32+
<Using Include="System.Reflection" />
33+
<Using Include="System.Runtime.CompilerServices" />
34+
<Using Include="Microsoft.EntityFrameworkCore" />
35+
<Using Include="Microsoft.Extensions.Logging" />
36+
<Using Include="Microsoft.Extensions.DependencyInjection" />
37+
</ItemGroup>
38+
39+
</Project>

samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,19 @@ public class CustomerContext(bool useSqlite = false) : DbContext
214214

215215
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
216216
=> (UseSqlite
217-
? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db")
217+
? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db",
218+
sqliteOptionsBuilder =>
219+
{
220+
sqliteOptionsBuilder.UseNetTopologySuite();
221+
sqliteOptionsBuilder.CommandTimeout(0);
222+
})
218223
: optionsBuilder.UseSqlServer(
219224
@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0",
220-
sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite()))
225+
sqlServerOptionsBuilder =>
226+
{
227+
sqlServerOptionsBuilder.UseNetTopologySuite();
228+
sqlServerOptionsBuilder.CommandTimeout(0);
229+
}))
221230
.EnableSensitiveDataLogging()
222231
.LogTo(Console.WriteLine, LogLevel.Information);
223232

samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="Microsoft.EntityFrameworkCore.Cosmos" Version="9.0.0-preview.3.24157.5" />
14-
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-preview.3.24157.5" />
15-
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-preview.3.24157.5" />
16-
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-preview.3.24157.5" />
17-
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite" Version="9.0.0-preview.3.24157.5" />
18-
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.HierarchyId" Version="9.0.0-preview.3.24157.5" />
19-
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite" Version="9.0.0-preview.3.24157.5" />
20-
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0-preview.3.24157.5" />
21-
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.0-preview.3.24157.5" />
13+
<PackageReference Include="Microsoft.EntityFrameworkCore.Cosmos" Version="9.0.0-preview.4.24205.3" />
14+
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0-preview.4.24205.3" />
15+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-preview.4.24205.3" />
16+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0-preview.4.24205.3" />
17+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite" Version="9.0.0-preview.4.24205.3" />
18+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.HierarchyId" Version="9.0.0-preview.4.24205.3" />
19+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite" Version="9.0.0-preview.4.24205.3" />
20+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0-preview.4.24205.3" />
21+
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.0-preview.4.24205.3" />
2222
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
2323
</ItemGroup>
2424

samples/core/Samples.sln

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NewInEFCore8", "Miscellaneo
197197
EndProject
198198
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NewInEFCore9", "Miscellaneous\NewInEFCore9\NewInEFCore9.csproj", "{3F17B59C-7D33-4BF0-B386-ACFE76D45697}"
199199
EndProject
200+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NewInEFCore9.CompiledModels", "NewInEFCore9.CompiledModels", "{26184A10-7CF8-4ED2-9F70-E00A55BE063B}"
201+
EndProject
202+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "Miscellaneous\NewInEFCore9.CompiledModels\App\App.csproj", "{22548A1B-0833-49E9-A04E-A7E8690EAE03}"
203+
EndProject
204+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Miscellaneous\NewInEFCore9.CompiledModels\Model\Model.csproj", "{8E9DD759-B6D0-4424-BC6C-97ECE559CE02}"
205+
EndProject
200206
Global
201207
GlobalSection(SolutionConfigurationPlatforms) = preSolution
202208
Debug|Any CPU = Debug|Any CPU
@@ -547,6 +553,14 @@ Global
547553
{3F17B59C-7D33-4BF0-B386-ACFE76D45697}.Debug|Any CPU.Build.0 = Debug|Any CPU
548554
{3F17B59C-7D33-4BF0-B386-ACFE76D45697}.Release|Any CPU.ActiveCfg = Release|Any CPU
549555
{3F17B59C-7D33-4BF0-B386-ACFE76D45697}.Release|Any CPU.Build.0 = Release|Any CPU
556+
{22548A1B-0833-49E9-A04E-A7E8690EAE03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
557+
{22548A1B-0833-49E9-A04E-A7E8690EAE03}.Debug|Any CPU.Build.0 = Debug|Any CPU
558+
{22548A1B-0833-49E9-A04E-A7E8690EAE03}.Release|Any CPU.ActiveCfg = Release|Any CPU
559+
{22548A1B-0833-49E9-A04E-A7E8690EAE03}.Release|Any CPU.Build.0 = Release|Any CPU
560+
{8E9DD759-B6D0-4424-BC6C-97ECE559CE02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
561+
{8E9DD759-B6D0-4424-BC6C-97ECE559CE02}.Debug|Any CPU.Build.0 = Debug|Any CPU
562+
{8E9DD759-B6D0-4424-BC6C-97ECE559CE02}.Release|Any CPU.ActiveCfg = Release|Any CPU
563+
{8E9DD759-B6D0-4424-BC6C-97ECE559CE02}.Release|Any CPU.Build.0 = Release|Any CPU
550564
EndGlobalSection
551565
GlobalSection(SolutionProperties) = preSolution
552566
HideSolutionNode = FALSE
@@ -633,6 +647,9 @@ Global
633647
{72C964FF-07C3-4234-B277-D91C3D83BAEC} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
634648
{F9CA30FF-70A9-4EA5-8F12-7B08A695AB8F} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
635649
{3F17B59C-7D33-4BF0-B386-ACFE76D45697} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
650+
{26184A10-7CF8-4ED2-9F70-E00A55BE063B} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
651+
{22548A1B-0833-49E9-A04E-A7E8690EAE03} = {26184A10-7CF8-4ED2-9F70-E00A55BE063B}
652+
{8E9DD759-B6D0-4424-BC6C-97ECE559CE02} = {26184A10-7CF8-4ED2-9F70-E00A55BE063B}
636653
EndGlobalSection
637654
GlobalSection(ExtensibilityGlobals) = postSolution
638655
SolutionGuid = {20C98D35-54EF-46A6-8F3B-1855C1AE4F70}

0 commit comments

Comments
 (0)