dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.83k stars 3.2k forks source link

EFOptimizeContext: add support for partial implementations #34988

Open andygjp opened 1 month ago

andygjp commented 1 month ago

I created a repo to demonstrate the problem: https://github.com/andygjp/CompiledModelsInOtherProject

One project is a console app that contains a data context. Another project is a library that contains a data context and it has the <EFStartupProject>..\App\App.csproj</EFStartupProject> property set to a console project. Both data contexts are configured the same.

The compiled model is generated as expected when I use version 9.0.0-preview.4.24205.3, but the compiled model is not generated when I change it to 9.0.0-rc.2.24474.1, regardless if the data context and "app" are in the same project.

I can tell if the auto-compiled model is missing when the console log contains the following message:

CoreEventId.ShadowPropertyCreated[10600] (Microsoft.EntityFrameworkCore.Model.Validation) 
      The property 'Post.BlogId' was created in shadow state because there are no eligible CLR members with a matching name.
andygjp commented 1 month ago

I tried preview 6, preview 7 and RC1 - none of these work.

Preview 5 will generate an auto-compile model, but only if the data context and "app" are in the same project. I tried replacing <EFStartupProject> with IDesignTimeDbContextFactory, but it didn't help.

andygjp commented 1 month ago

Is the compiled model generated only when running dotnet publish?

andygjp commented 1 month ago

I'm happy to close this because this seems to be by design, ie out of the box, the model is generated when publishing an app instead of building. (The documentation is lacking and it took a lot of hacking to understand what I needed to do to make it work.)

There is one question: if the model is generated during publish, how do I do global filters? I was relying upon partial definitions that are no longer there:

Image

AndriySvyryd commented 1 month ago

We removed the support for <EFStartupProject>

The model is now generated by default only during publish, but you change this by setting <EFScaffoldModelStage> to build. We now also generate precompiled queries on publish. To avoid this set <EFPrecompileQueriesStage> to none.

I'll update https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-9.0/whatsnew#msbuild-integration with this soon.

AndriySvyryd commented 1 month ago

I was relying upon partial definitions that are no longer there:

Currently we can't make the partial implementation work reliably with auto-compiled model, I'd recommend using the regular compiled model for this.

andygjp commented 1 month ago

Thank you.

One more question: how do you turn off nativeAOT code generation?

With the project configured like so:

<PropertyGroup>
        <!-- disabled until I can get query filters working -->
        <EFOptimizeContext>true</EFOptimizeContext>
        <!-- valid options are: publish, or, build; never disables it -->
        <EFScaffoldModelStage>build</EFScaffoldModelStage>
        <EFPrecompileQueriesStage>never</EFPrecompileQueriesStage>
        <!-- uncomment this if you want the output part of the project -->
        <EFOutputDir>CompiledModelsX</EFOutputDir> 
        <EFRootNamespace>ManagementSystem.Domain.Data.CompiledModelsX</EFRootNamespace>
</PropertyGroup>

It generates the same code as this command:

dotnet ef dbcontext optimize \
  --project ./ManagementSystem.Domain.Data.EFCore/ManagementSystem.Domain.Data.EFCore.csproj \
  --namespace "ManagementSystem.Domain.Data.CompiledModelsX" \
  --suffix ".g" \
  --nativeaot
AndriySvyryd commented 1 month ago

That's currently not configurable, see https://github.com/dotnet/efcore/issues/34473