Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Avertissement
Les fonctionnalités NativeAOT et de précompilation des requêtes sont hautement expérimentales et ne sont pas encore adaptées à une utilisation en production. La prise en charge décrite ci-dessous doit être considérée comme une infrastructure vers la fonctionnalité finale, qui sera publiée dans une version ultérieure. Nous vous encourageons à expérimenter avec le support actuel et à faire un rapport sur vos expériences, mais nous vous déconseillons de déployer des applications EF NativeAOT en production. Consultez ci-dessous pour connaître les limitations connues spécifiques.
.NET NativeAOT permet de publier des applications .NET autonomes qui ont été compilées à l’avance (AOT). Cela offre les avantages suivants :
- Temps de démarrage de l’application beaucoup plus rapide
- Petits fichiers binaires autonomes qui ont des empreintes mémoire plus petites et sont plus faciles à déployer
- Exécution d’applications dans des environnements où la compilation à la volée n’est pas prise en charge
Les applications EF publiées avec NativeAOT démarrent beaucoup plus rapidement que les mêmes applications sans celle-ci. Outre les améliorations générales apportées au démarrage de .NET que NativeAOT offre (c’est-à-dire qu’aucune compilation JIT n’est requise à chaque fois), EF précompile également les requêtes LINQ lors de la publication de votre application, de sorte qu’aucun traitement n’est nécessaire lors du démarrage et que sql est déjà disponible pour l’exécution immédiate. Plus une application comporte de requêtes EF LINQ dans son code, plus on peut s'attendre à des gains de démarrage rapides.
Publication d’une application EF NativeAOT
Tout d’abord, activez la publication NativeAOT pour votre projet comme suit :
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
La prise en charge d’EF pour l’exécution des requêtes LINQ sous NativeAOT repose sur la précompilation des requêtes : ce mécanisme identifie statiquement les requêtes EF LINQ et génère des intercepteurs C#, qui contiennent du code pour exécuter chaque requête spécifique. Cela peut réduire considérablement le temps de démarrage de votre application, car le traitement et la compilation de vos requêtes LINQ dans SQL ne se produisent plus chaque fois que votre application démarre. Au lieu de cela, l’intercepteur de chaque requête contient le SQL finalisé pour cette requête, ainsi que le code optimisé pour matérialiser les résultats de la base de données en tant qu’objets .NET.
Les intercepteurs C# sont actuellement une fonctionnalité expérimentale et nécessitent un opt-in spécial dans votre fichier projet :
<PropertyGroup>
<InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.EntityFrameworkCore.GeneratedInterceptors</InterceptorsNamespaces>
</PropertyGroup>
Enfin, le Microsoft.EntityFrameworkCore.Tasks package contient l’intégration MSBuild qui effectue la précompilation de requête (et génère le modèle compilé requis) lorsque vous publiez votre application :
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tasks" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
Vous êtes maintenant prêt à publier votre application EF NativeAOT :
dotnet publish -r linux-arm64 -c Release
Remarque
La commande de publication peut échouer avec l’erreur CS9137. La cause de cette erreur est des références de package transitive obsolètes Microsoft.CodeAnalysis.CSharp.Workspaces et Microsoft.CodeAnalysis.Workspaces.MSBuild. Pour contourner ce problème, ajoutez ces packages explicitement à votre fichier .csproj :
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.13.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.13.0" />
Consultez ce sujet pour plus d'informations.
Ceci montre comment publier une application NativeAOT pour Linux s'exécutant sur ARM64 ; consultez ce catalogue pour trouver votre identificateur d'exécution. Si vous souhaitez générer les intercepteurs sans publication , par exemple pour examiner les sources générées, vous pouvez le faire via la dotnet ef dbcontext optimize --precompile-queries --nativeaot commande.
En raison du fonctionnement des intercepteurs C#, toute modification de la source de l’application les invalide et nécessite la répétition du processus ci-dessus. Par conséquent, la génération d’intercepteur et la publication réelle ne sont pas censées se produire dans la boucle interne, car le développeur travaille sur du code ; Au lieu de cela, les deux dotnet ef dbcontext optimize et dotnet publish peuvent être exécutés dans un flux de travail de publication/déploiement, dans un système CI/CD.
Remarque
La publication signale actuellement un certain nombre d’avertissements de réduction et de NativeAOT, ce qui signifie qu’il n’est pas complètement garanti que votre application s’exécute correctement. Ceci est attendu compte tenu de l’état expérimental actuel de la prise en charge NativeAOT. La version finale, non expérimentale, ne signalera aucun avertissement.
Limites
Les requêtes dynamiques ne sont pas prises en charge
La précompilation des requêtes effectue une analyse statique de votre code source, en identifiant les requêtes EF LINQ et en générant des intercepteurs C# pour eux. LINQ permet d’exprimer des requêtes hautement dynamiques, où les opérateurs LINQ sont composés en fonction de conditions arbitraires ; Ces requêtes ne peuvent malheureusement pas être analysées statiquement et ne sont actuellement pas prises en charge. Prenons l’exemple suivant :
IAsyncEnumerable<Blog> GetBlogs(BlogContext context, bool applyFilter)
{
IQueryable<Blog> query = context.Blogs.OrderBy(b => b.Id);
if (applyFilter)
{
query = query.Where(b => b.Name != "foo");
}
return query.AsAsyncEnumerable();
}
La requête ci-dessus est divisée en plusieurs instructions et compose dynamiquement l’opérateur Where en fonction d’un paramètre externe ; ces requêtes ne peuvent pas être précompilées. Toutefois, il est parfois possible de réécrire des requêtes dynamiques telles que plusieurs requêtes non dynamiques :
IAsyncEnumerable<Blog> GetBlogs(BlogContext context, bool applyFilter)
=> applyFilter
? context.Blogs.OrderBy(b => b.Id).Where(b => b.Name != "foo").AsAsyncEnumerable()
: context.Blogs.OrderBy(b => b.Id).AsAsyncEnumerable();
Étant donné que les deux requêtes peuvent chacune être analysées de manière statique du début à la fin, la précompilation peut les gérer.
Notez que les requêtes dynamiques seront probablement prises en charge ultérieurement lors de l’utilisation de NativeAOT ; toutefois, étant donné qu’ils ne peuvent pas être précompilés, ils continueront à ralentir le démarrage de votre application et seront également généralement moins efficaces par rapport à l’exécution non nativeAOT ; Cela est dû au fait que EF s’appuie en interne sur la génération de code pour matérialiser les résultats de la base de données, mais la génération de code n’est pas prise en charge lors de l’utilisation de NativeAOT.
Autres limitations
- La syntaxe d’expression de requête LINQ (parfois appelée « syntaxe de compréhension ») n’est pas prise en charge.
- Le modèle compilé et les intercepteurs de requête générés peuvent actuellement être assez volumineux en termes de taille de code et prendre un certain temps pour générer. Nous prévoyons d’améliorer cela.
- Les fournisseurs EF peuvent avoir besoin d'intégrer une prise en charge des requêtes précompilées ; consultez la documentation de votre fournisseur pour savoir si elle est compatible avec le support NativeAOT d’EF.
- Les convertisseurs de valeurs qui utilisent l’état capturé ne sont pas pris en charge.
Requêtes précompilées sans NativeAOT
En raison des limitations actuelles de la prise en charge NativeAOT d’EF, il peut ne pas être utilisable pour certaines applications. Toutefois, vous pouvez tirer parti des requêtes précompilées lors de la publication d’applications standard et non NativeAOT ; Cela vous permet au moins d’tirer parti de la réduction du temps de démarrage de l’offre de requêtes précompilées, tout en étant en mesure d’utiliser des requêtes dynamiques et d’autres fonctionnalités non prises en charge actuellement avec NativeAOT.
L’utilisation de requêtes précompilées sans NativeAOT est simplement une question d’exécution des éléments suivants :
dotnet ef dbcontext optimize --precompile-queries
Comme indiqué ci-dessus, cela génère un modèle compilé et des intercepteurs pour les requêtes qui peuvent être précompilées, en supprimant leur surcharge du temps de démarrage de votre application.