From 7b42f3308f345a8b8a5dc2424ff6ee441bf4430d Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Sat, 20 Apr 2024 09:34:55 +0200 Subject: [PATCH 001/224] fix "Unrecognized escape sequence" in snippet (#4716) --- entity-framework/core/providers/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/providers/index.md b/entity-framework/core/providers/index.md index 01c9492a66..c63a1fc40d 100644 --- a/entity-framework/core/providers/index.md +++ b/entity-framework/core/providers/index.md @@ -82,7 +82,7 @@ For example, the following line configures the SQL Server provider with the pass ```csharp optionsBuilder.UseSqlServer( - "Server=(localdb)\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;"); + @"Server=(localdb)\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;"); ``` Database providers can extend EF Core to enable functionality unique to specific databases. Some concepts are common to most databases, and are included in the primary EF Core components. Such concepts include expressing queries in LINQ, transactions, and tracking changes to objects once they are loaded from the database. From 6c7526f6f6097096307a8217cc67d6ecf9a07afe Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 3 May 2024 11:02:56 +0200 Subject: [PATCH 002/224] Update advanced-performance-topics.md (#4719) Wrong Link to Benchmark source --- .../core/performance/advanced-performance-topics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index 0cf60ec244..5c4370dae2 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -83,7 +83,7 @@ When EF receives a LINQ query tree for execution, it must first "compile" that t However, EF must still perform certain tasks before it can make use of the internal query cache. For example, your query's expression tree must be recursively compared with the expression trees of cached queries, to find the correct cached query. The overhead for this initial processing is negligible in the majority of EF applications, especially when compared to other costs associated with query execution (network I/O, actual query processing and disk I/O at the database...). However, in certain high-performance scenarios it may be desirable to eliminate it. -EF supports *compiled queries*, which allow the explicit compilation of a LINQ query into a .NET delegate. Once this delegate is acquired, it can be invoked directly to execute the query, without providing the LINQ expression tree. This technique bypasses the cache lookup, and provides the most optimized way to execute a query in EF Core. Following are some benchmark results comparing compiled and non-compiled query performance; benchmark on your platform before making any decisions. [The source code is available here](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Benchmarks/ContextPooling.cs), feel free to use it as a basis for your own measurements. +EF supports *compiled queries*, which allow the explicit compilation of a LINQ query into a .NET delegate. Once this delegate is acquired, it can be invoked directly to execute the query, without providing the LINQ expression tree. This technique bypasses the cache lookup, and provides the most optimized way to execute a query in EF Core. Following are some benchmark results comparing compiled and non-compiled query performance; benchmark on your platform before making any decisions. [The source code is available here](https://github.com/dotnet/EntityFramework.Docs/blob/main/samples/core/Benchmarks/CompiledQueries.cs), feel free to use it as a basis for your own measurements. | Method | NumBlogs | Mean | Error | StdDev | Gen 0 | Allocated | |--------------------- |--------- |---------:|---------:|---------:|-------:|----------:| From 32b32ea5779fe9839c77bce6c9ef037b12a580e7 Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Tue, 7 May 2024 09:28:18 -0700 Subject: [PATCH 003/224] What's New for preview 4 (#4718) --- .../core/what-is-new/ef-core-9.0/whatsnew.md | 165 +++++- entity-framework/core/what-is-new/index.md | 2 +- samples/core/Benchmarks/AverageBlogRanking.cs | 2 +- samples/core/Benchmarks/CompiledQueries.cs | 2 +- samples/core/Benchmarks/ContextPooling.cs | 2 +- .../DynamicallyConstructedQueries.cs | 2 +- samples/core/Benchmarks/Inheritance.cs | 2 +- .../core/Benchmarks/QueryTrackingBehavior.cs | 4 +- .../CascadeDeletes/IntroOptionalSamples.cs | 4 +- .../CascadeDeletes/IntroRequiredSamples.cs | 4 +- .../OptionalDependentsSamples.cs | 4 +- .../RequiredDependentsSamples.cs | 4 +- .../WithDatabaseCycleSamples.cs | 4 +- samples/core/DbContextPooling/Program.cs | 4 +- samples/core/Intro/Model.cs | 4 +- samples/core/Miscellaneous/Async/Program.cs | 4 +- .../AsyncWithSystemInteractive/Program.cs | 4 +- .../core/Miscellaneous/Collations/Program.cs | 4 +- .../ApplicationDbContext.cs | 4 +- .../WebApp/UseNewForWebApp.cs | 4 +- .../FactoryServicesExample.cs | 4 +- .../WithNew/ApplicationDbContext.cs | 4 +- .../ConnectionInterception/BlogsContext.cs | 2 +- .../ConnectionResiliency/Program.cs | 2 +- .../Logging/Logging/BloggingContext.cs | 4 +- .../Logging/BloggingContextWithFiltering.cs | 4 +- .../NewInEFCore6/ArrayParametersSample.cs | 2 +- .../BoolToStringTranslationSample.cs | 2 +- .../NewInEFCore6/ColumnOrderSample.cs | 2 +- .../NewInEFCore6/CommandSourceSample.cs | 4 +- .../NewInEFCore6/ContainsFreeTextSample.cs | 2 +- .../NewInEFCore6/ConvertNullsSample.cs | 4 +- .../NewInEFCore6/DbContextFactorySample.cs | 8 +- .../EntityTypeConfigurationAttributeSample.cs | 2 +- .../NewInEFCore6/GroupBySample.cs | 2 +- .../NewInEFCore6/HasConversionSample.cs | 2 +- .../NewInEFCore6/IsNullOrWhitespaceSample.cs | 2 +- .../ManyToManyConfigurationSample.cs | 8 +- .../NewInEFCore6/MathFTranslationSample.cs | 2 +- .../NewInEFCore6/MinimalApiSample.cs | 6 +- .../NewInEFCore6/OptionalDependentsSample.cs | 2 +- .../PreConventionModelConfigurationSample.cs | 2 +- .../NewInEFCore6/PrecisionAttributeSample.cs | 2 +- .../PublicPooledDbContextFactorySample.cs | 2 +- .../NewInEFCore6/RandomFunctionSample.cs | 2 +- .../NewInEFCore6/SparseColumnsSample.cs | 2 +- .../NewInEFCore6/SplitQuerySample.cs | 2 +- .../NewInEFCore6/StringConcatSample.cs | 2 +- .../SubstringTranslationSample.cs | 2 +- .../NewInEFCore6/TagWithFileAndLineSample.cs | 2 +- .../NewInEFCore6/TemporalTablesSample.cs | 2 +- .../NewInEFCore6/TemporaryValuesSample.cs | 2 +- .../NewInEFCore6/TrailingUnderscoresSample.cs | 2 +- .../NewInEFCore6/UnicodeAttributeSample.cs | 2 +- .../NewInEFCore7/BlogsContext.cs | 2 +- .../NewInEFCore7/DocumentsContext.cs | 2 +- .../NewInEFCore7/GroupByEntityTypeSample.cs | 2 +- .../GroupByFinalOperatorSample.cs | 2 +- .../GroupJoinFinalOperatorSample.cs | 2 +- .../ModelBuildingConventionsSample.cs | 4 +- .../NewInEFCore7/ModelBuildingSample.cs | 8 +- .../QueryStatisticsLoggerSample.cs | 2 +- .../NewInEFCore7/ReadOnlySetQuerySample.cs | 2 +- .../SaveChangesPerformanceSample.cs | 2 +- .../StatisticalAggregateFunctionsSample.cs | 2 +- .../NewInEFCore7/TpcInheritanceSample.cs | 2 +- .../UngroupedColumnsQuerySample.cs | 2 +- .../NewInEFCore7/ValueGenerationSample.cs | 2 +- .../NewInEFCore8/BlogsContext.cs | 2 +- .../NewInEFCore8/ComplexTypesSample.cs | 2 +- .../NewInEFCore8/DateOnlyTimeOnlySample.cs | 2 +- .../NewInEFCore8/DefaultConstraintSample.cs | 2 +- .../NewInEFCore8/DocumentsContext.cs | 2 +- .../NewInEFCore8/ExecuteUpdateDeleteSample.cs | 2 +- .../NewInEFCore8/HierarchyIdSample.cs | 2 +- .../ImmutableComplexTypesSample.cs | 2 +- .../ImmutableStructComplexTypesSample.cs | 2 +- .../NewInEFCore8/NestedComplexTypesSample.cs | 2 +- .../PrimitiveCollectionToTableSample.cs | 2 +- .../PrimitiveCollectionsInJsonSample.cs | 2 +- .../PrimitiveCollectionsSample.cs | 2 +- .../NewInEFCore8/RecordComplexTypesSample.cs | 4 +- .../NewInEFCore8/StructComplexTypesSample.cs | 2 +- .../App/App.csproj | 2 +- .../Model/Model.csproj | 8 +- .../CosmosPrimitiveTypesSample.cs | 116 ++++ .../CosmosSyncApisSample.cs | 105 ++++ .../NewInEFCore9.Cosmos.csproj | 13 + .../NewInEFCore9.Cosmos/Program.cs | 11 + .../NewInEFCore9/ComplexTypesSample.cs | 148 +++++ .../NewInEFCore9/NewInEFCore9.csproj | 18 +- .../PrimitiveCollectionsSample.cs | 509 ++++++++++++++++++ .../Miscellaneous/NewInEFCore9/Program.cs | 43 +- .../NullableReferenceTypesContext.cs | 2 +- .../BulkConfiguration/BlogsContext.cs | 2 +- .../BulkConfiguration/CurrencyContext.cs | 4 +- .../BulkConfiguration/MetadataAPIContext.cs | 4 +- .../ModelBuildingConventionsSample.cs | 2 +- .../BulkConfiguration/PreConventionContext.cs | 4 +- .../DataSeeding/DataSeedingContext.cs | 4 +- .../core/Modeling/EntityTypes/EntityTypes.cs | 4 +- .../Modeling/KeylessEntityTypes/Program.cs | 2 +- .../OwnedEntities/OwnedEntityContext.cs | 4 +- .../TableSplitting/TableSplittingContext.cs | 2 +- .../CaseInsensitiveStrings.cs | 2 +- .../ValueConversions/EncryptPropertyValues.cs | 4 +- .../EnumToStringConversions.cs | 4 +- .../ValueConversions/FixedLengthStrings.cs | 6 +- .../ValueConversions/PreserveDateTimeKind.cs | 4 +- .../ValueConversions/ULongConcurrency.cs | 4 +- .../ValueConversions/WithMappingHints.cs | 4 +- .../core/Performance/Other/BloggingContext.cs | 2 +- .../core/Performance/Other/EmployeeContext.cs | 4 +- .../Other/ExtensionsLoggingContext.cs | 4 +- .../Other/LazyLoading/LazyBloggingContext.cs | 4 +- samples/core/Performance/Other/Program.cs | 6 +- .../ClientEvaluation/BloggingContext.cs | 4 +- .../Querying/ComplexQuery/BloggingContext.cs | 4 +- .../NullSemantics/NullSemanticsContext.cs | 4 +- .../core/Querying/Overview/BloggingContext.cs | 4 +- .../Querying/Pagination/BloggingContext.cs | 4 +- .../Querying/QueryFilters/AnimalContext.cs | 4 +- .../Querying/QueryFilters/BloggingContext.cs | 4 +- .../FilteredBloggingContextRequired.cs | 4 +- .../Querying/RelatedData/BloggingContext.cs | 4 +- .../SplitQueriesBloggingContext.cs | 4 +- .../Querying/SqlQueries/BloggingContext.cs | 4 +- samples/core/Querying/Tags/SpatialContext.cs | 4 +- .../core/Querying/Tracking/BloggingContext.cs | 4 +- .../Tracking/NonTrackingBloggingContext.cs | 4 +- .../UserDefinedFunctionMapping/Model.cs | 4 +- samples/core/Samples.sln | 7 + samples/core/Saving/Basics/BloggingContext.cs | 4 +- .../Saving/CascadeDelete/BloggingContext.cs | 4 +- .../core/Saving/Concurrency/BasicSample.cs | 2 +- .../Concurrency/ConflictResolutionSample.cs | 2 +- .../Saving/Disconnected/BloggingContext.cs | 4 +- samples/core/Saving/RelatedData/Sample.cs | 4 +- .../Saving/Transactions/AmbientTransaction.cs | 4 +- .../Transactions/CommitableTransaction.cs | 4 +- .../Transactions/ControllingTransaction.cs | 4 +- .../Transactions/ExternalDbTransaction.cs | 4 +- .../Saving/Transactions/ManagingSavepoints.cs | 4 +- .../Saving/Transactions/SharingTransaction.cs | 4 +- .../Schemas/Migrations/CustomOperation.cs | 2 +- .../Migrations/MigrationTableNameContext.cs | 4 +- .../Schemas/Migrations/MyHistoryRepository.cs | 4 +- .../Models/WideWorldImportersContext.cs | 4 +- .../core/Testing/BloggingWebApi/Startup.cs | 4 +- .../Testing/BusinessLogic/BloggingContext.cs | 4 +- .../TestDatabaseFixture.cs | 4 +- .../TransactionalTestDatabaseFixture.cs | 4 +- 152 files changed, 1329 insertions(+), 260 deletions(-) create mode 100644 samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosPrimitiveTypesSample.cs create mode 100644 samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs create mode 100644 samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj create mode 100644 samples/core/Miscellaneous/NewInEFCore9.Cosmos/Program.cs create mode 100644 samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs create mode 100644 samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs 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 0091fd8bc6..dcc6d1d574 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 @@ -2,7 +2,7 @@ title: What's New in EF Core 9 description: Overview of new features in EF Core 9 author: ajcvickers -ms.date: 03/07/2024 +ms.date: 05/02/2024 uid: core/what-is-new/ef-core-9.0/whatsnew --- @@ -15,15 +15,113 @@ EF9 is available as [daily builds](https://github.com/dotnet/efcore/blob/main/do > [!TIP] > You can run and debug into the samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs). Each section below links to the source code specific to that section. -EF9 targets .NET 8, and can therefore be used with either [.NET 8 (LTS)](https://dotnet.microsoft.com/download/dotnet/8.0) or a .NET 9 preview. +EF9 targets .NET 8, and can therefore be used with either [.NET 8 (LTS)](https://dotnet.microsoft.com/download/dotnet/8.0) or a [.NET 9 preview](https://dotnet.microsoft.com/download/dotnet/9.0). > [!TIP] > The _What's New_ docs are updated for each preview. All the samples are set up to use the [EF9 daily builds](https://github.com/dotnet/efcore/blob/main/docs/DailyBuilds.md), which usually have several additional weeks of completed work compared to the latest preview. We strongly encourage use of the daily builds when testing new features so that you're not doing your testing against stale bits. + + +## Azure Cosmos DB for NoSQL + +We are working on significant updates in EF9 to the EF Core database provider for Azure Cosmos DB for NoSQL. + +### Role-based access + +Azure Cosmos DB for NoSQL includes a [built-in role-based access control (RBAC) system](/azure/cosmos-db/role-based-access-control). This is now supported by EF9 for both management and use of containers. No changes are required to application code. See [Issue #32197](https://github.com/dotnet/efcore/issues/32197) for more information. + +### Synchronous access blocked by default + +> [!TIP] +> The code shown here comes from [CosmosSyncApisSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs). + +Azure Cosmos DB for NoSQL does not support synchronous (blocking) access from application code. Previously, EF masked this by default by blocking for you on async calls. However, this both encourages sync use, which is bad practice, and [may cause deadlocks](https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). Therefore, starting with EF9, an exception is thrown when synchronous access is attempted. For example: + +```output +System.InvalidOperationException: An error was generated for warning 'Microsoft.EntityFrameworkCore.Database.SyncNotSupported': + Azure Cosmos DB does not support synchronous I/O. Make sure to use and correctly await only async methods when using + Entity Framework Core to access Azure Cosmos DB. See https://aka.ms/ef-cosmos-nosync for more information. + This exception can be suppressed or logged by passing event ID 'CosmosEventId.SyncNotSupported' to the 'ConfigureWarnings' + method in 'DbContext.OnConfiguring' or 'AddDbContext'. + at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition.Log[TLoggerCategory](IDiagnosticsLogger`1 logger, Exception exception) + at Microsoft.EntityFrameworkCore.Cosmos.Diagnostics.Internal.CosmosLoggerExtensions.SyncNotSupported(IDiagnosticsLogger`1 diagnostics) + at Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal.CosmosClientWrapper.DeleteDatabase() + at Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal.CosmosDatabaseCreator.EnsureDeleted() + at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted() +``` + +As the exception says, sync access can still be used for now by configuring the warning level appropriately. For example, in `OnConfiguring` on your `DbContext` type: + +```csharp +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.ConfigureWarnings(b => b.Ignore(CosmosEventId.SyncNotSupported)); +``` + +Note, however, that we plan to fully remove sync support in EF11, so start updating to use async methods like `ToListAsync` and `SaveChangesAsync` as soon as possible! + +### Enhanced primitive collections + +> [!TIP] +> The code shown here comes from [CosmosPrimitiveTypesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosPrimitiveTypesSample.cs). + +The Cosmos DB provider has supported primitive collections in a limited form since EF Core 6. This is support is being enhanced in EF9, starting with consolidation of the metadata and API surfaces for primitive collections in document databases to align with primitive collections in relational databases. This means that primitive collections can now be explicitly mapped using the model building API, allowing for facets of the element type to be configured. For example, to map a list of required (i.e. non-null) strings: + + +[!code-csharp[ConfigureCollection](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosPrimitiveTypesSample.cs?name=ConfigureCollection)] + +See [What's new in EF8: primitive collections](xref:core/what-is-new/ef-core-8.0/whatsnew#primitive-collections) for more information on the model building API. + +## AOT and pre-compiled queries + +As mentioned in the introduction, there is a lot of work going on behind the scenes to allow EF Core to run without just-in-time (JIT) compilation. Instead, EF compile ahead-of-time (AOT) everything needed to run queries in the application. This AOT compilation and related processing will happen as part of building and publishing the application. At this point in the EF9 release, there is not much available that can be used by you, the app developer. However, for those interested, the completed issues in EF9 that support AOT and pre-compiled queries are: + +- [Compiled model: Use static binding instead of reflection for properties and fields](https://github.com/dotnet/efcore/issues/24900) +- [Compiled model: Generate lambdas used in change tracking](https://github.com/dotnet/efcore/issues/24904) +- [Make change tracking and the update pipeline compatible with AOT/trimming](https://github.com/dotnet/efcore/issues/29761) +- [Use interceptors to redirect the query to precompiled code](https://github.com/dotnet/efcore/issues/31331) +- [Make all SQL expression nodes quotable](https://github.com/dotnet/efcore/issues/33008) +- [Generate the compiled model during build](https://github.com/dotnet/efcore/issues/24894) +- [Discover the compiled model automatically](https://github.com/dotnet/efcore/issues/24893) +- [Make ParameterExtractingExpressionVisitor capable of extracting paths to evaluatable fragments in the tree](https://github.com/dotnet/efcore/issues/32999) +- [Generate expression trees in compiled models (query filters, value converters)](https://github.com/dotnet/efcore/issues/29924) +- [Make LinqToCSharpSyntaxTranslator more resilient to multiple declaration of the same variable in nested scopes](https://github.com/dotnet/efcore/issues/32716) +- [Optimize ParameterExtractingExpressionVisitor](https://github.com/dotnet/efcore/issues/32698) + +Check back here for examples of how to use pre-compiled queries as the experience comes together. + ## LINQ and SQL translation The team is working on some significant architecture changes to the query pipeline in EF Core 9 as part of our continued improvements to JSON mapping and document databases. This means we need to get **people like you** to run your code on these new internals. (If you're reading a "What's New" doc at this point in the release, then you're a really engaged part of the community; thank you!) We have over 120,000 tests, but it's not enough! We need you, people running real code on our bits, in order to find issues and ship a solid release! + + +### GroupBy complex types + +> [!TIP] +> The code shown here comes from [ComplexTypesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs). + +EF9 supports grouping by a complex type instance. For example: + + +[!code-csharp[GroupByComplexType](../../../../samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs?name=GroupByComplexType)] + +EF translates this as grouping by each member of the complex type, which aligns with the semantics of complex types as value objects. For example, on Azure SQL: + +```sql +SELECT [s].[StoreAddress_City], [s].[StoreAddress_Country], [s].[StoreAddress_Line1], [s].[StoreAddress_Line2], [s].[StoreAddress_PostCode], COUNT(*) AS [Count] +FROM [Stores] AS [s] +GROUP BY [s].[StoreAddress_City], [s].[StoreAddress_Country], [s].[StoreAddress_Line1], [s].[StoreAddress_Line2], [s].[StoreAddress_PostCode] +``` + ### Prune columns passed to OPENJSON's WITH clause @@ -680,6 +778,66 @@ Now, whenever the model changes, the compiled model will be automatically rebuil > [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. + + +### Read-only primitive collections + +> [!TIP] +> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs). + +EF8 introduced support for [mapping arrays and mutable lists of primitive types](xref:core/what-is-new/ef-core-8.0/whatsnew#primitive-collections). This has been expanded in EF9 to include read-only collections/lists. Specifically, EF9 supports collections typed as `IReadOnlyList`, `IReadOnlyCollection`, or `ReadOnlyCollection`. For example, in the following code, `DaysVisited` will be mapped by convention as a primitive collection of dates: + +```csharp +public class DogWalk +{ + public int Id { get; set; } + public string Name { get; set; } + public ReadOnlyCollection DaysVisited { get; set; } +} +``` + +The read-only collection can be backed by a normal, mutable collection if desired. For example, in the following code, `DaysVisited` can be mapped as a primitive collection of dates, while still allowing code in the class to manipulate the underlying list. + +```csharp + public class Pub + { + public int Id { get; set; } + public string Name { get; set; } + public IReadOnlyCollection Beers { get; set; } + + private List _daysVisited = new(); + public IReadOnlyList DaysVisited => _daysVisited; + } +``` + +These collections can then be used in queries in the normal way. For example, this LINQ query: + + +[!code-csharp[WalksWithADrink](../../../../samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs?name=WalksWithADrink)] + +Which translates to the following SQL on SQLite: + +```sql +SELECT "w"."Name" AS "WalkName", "p"."Name" AS "PubName", ( + SELECT COUNT(*) + FROM json_each("w"."DaysVisited") AS "d" + WHERE "d"."value" IN ( + SELECT "d0"."value" + FROM json_each("p"."DaysVisited") AS "d0" + )) AS "Count", json_array_length("w"."DaysVisited") AS "TotalCount" +FROM "Walks" AS "w" +INNER JOIN "Pubs" AS "p" ON "w"."ClosestPubId" = "p"."Id" +``` + ### Specify caching for sequences @@ -770,9 +928,6 @@ CREATE INDEX [IX_User_Name] ON [User] ([Name]) WITH (FILLFACTOR = 80); CREATE INDEX [IX_User_Region_Tag] ON [User] ([Region], [Tag]) WITH (FILLFACTOR = 80); ``` -> [!NOTE] -> There is currently a bug in preview 2 where the fill-factors are not included when the table is created for the first time. This is tracked by [Issue #33269](https://github.com/dotnet/efcore/issues/33269) - This enhancement was contributed by [@deano-hunter](https://github.com/deano-hunter). Many thanks! diff --git a/entity-framework/core/what-is-new/index.md b/entity-framework/core/what-is-new/index.md index cfda4bddf7..913eab0c7c 100644 --- a/entity-framework/core/what-is-new/index.md +++ b/entity-framework/core/what-is-new/index.md @@ -48,4 +48,4 @@ See the [release planning process](xref:core/what-is-new/release-planning) for m The next planned stable release is **EF Core 9.0**, or just **EF9**, scheduled for **November 2024**. -See the [high-level plan for EF9](xref:core/what-is-new/ef-core-9.0/plan) for more information. +See the [What's New in EF9](xref:core/what-is-new/ef-core-9.0/whatsnew) for more information. diff --git a/samples/core/Benchmarks/AverageBlogRanking.cs b/samples/core/Benchmarks/AverageBlogRanking.cs index 670eaf614f..19dc70bf8b 100644 --- a/samples/core/Benchmarks/AverageBlogRanking.cs +++ b/samples/core/Benchmarks/AverageBlogRanking.cs @@ -83,7 +83,7 @@ public class BloggingContext : DbContext public DbSet Blogs { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True"); + => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0"); public void SeedData(int numblogs) { diff --git a/samples/core/Benchmarks/CompiledQueries.cs b/samples/core/Benchmarks/CompiledQueries.cs index 587f1fe98b..aa10ed1a29 100644 --- a/samples/core/Benchmarks/CompiledQueries.cs +++ b/samples/core/Benchmarks/CompiledQueries.cs @@ -62,7 +62,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); public async Task SeedDataAsync(int numBlogs) diff --git a/samples/core/Benchmarks/ContextPooling.cs b/samples/core/Benchmarks/ContextPooling.cs index fa0899e445..68ae552a12 100644 --- a/samples/core/Benchmarks/ContextPooling.cs +++ b/samples/core/Benchmarks/ContextPooling.cs @@ -17,7 +17,7 @@ public class ContextPooling public void Setup() { _options = new DbContextOptionsBuilder() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .Options; using var context = new BloggingContext(_options); diff --git a/samples/core/Benchmarks/DynamicallyConstructedQueries.cs b/samples/core/Benchmarks/DynamicallyConstructedQueries.cs index cbd81594d7..a6cfa4dde9 100644 --- a/samples/core/Benchmarks/DynamicallyConstructedQueries.cs +++ b/samples/core/Benchmarks/DynamicallyConstructedQueries.cs @@ -109,7 +109,7 @@ public class BloggingContext : DbContext public DbSet Posts { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True"); + => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0"); } public class Blog diff --git a/samples/core/Benchmarks/Inheritance.cs b/samples/core/Benchmarks/Inheritance.cs index dbc45195b6..40f864bf57 100644 --- a/samples/core/Benchmarks/Inheritance.cs +++ b/samples/core/Benchmarks/Inheritance.cs @@ -72,7 +72,7 @@ public abstract class InheritanceContext : DbContext public DbSet Roots { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True"); + => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0"); protected override void OnModelCreating(ModelBuilder modelBuilder) { diff --git a/samples/core/Benchmarks/QueryTrackingBehavior.cs b/samples/core/Benchmarks/QueryTrackingBehavior.cs index c2f70372b4..32eaad6422 100644 --- a/samples/core/Benchmarks/QueryTrackingBehavior.cs +++ b/samples/core/Benchmarks/QueryTrackingBehavior.cs @@ -48,7 +48,7 @@ public class BloggingContext : DbContext public DbSet Posts { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True"); + => optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0"); public static void SeedData(int numBlogs, int numPostsPerBlog) { @@ -77,4 +77,4 @@ public class Post public int BlogId { get; set; } public Blog Blog { get; set; } } -} \ No newline at end of file +} diff --git a/samples/core/CascadeDeletes/IntroOptionalSamples.cs b/samples/core/CascadeDeletes/IntroOptionalSamples.cs index 5dd1879cc6..302c0c0bb0 100644 --- a/samples/core/CascadeDeletes/IntroOptionalSamples.cs +++ b/samples/core/CascadeDeletes/IntroOptionalSamples.cs @@ -159,7 +159,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True;ConnectRetryCount=0"); //.UseSqlite("DataSource=test.db"); if (!_quiet) @@ -167,4 +167,4 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) optionsBuilder.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }); } } -} \ No newline at end of file +} diff --git a/samples/core/CascadeDeletes/IntroRequiredSamples.cs b/samples/core/CascadeDeletes/IntroRequiredSamples.cs index cc318d1142..73a1873da5 100644 --- a/samples/core/CascadeDeletes/IntroRequiredSamples.cs +++ b/samples/core/CascadeDeletes/IntroRequiredSamples.cs @@ -176,7 +176,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True;ConnectRetryCount=0"); //.UseSqlite("DataSource=test.db"); if (!_quiet) @@ -184,4 +184,4 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) optionsBuilder.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }); } } -} \ No newline at end of file +} diff --git a/samples/core/CascadeDeletes/OptionalDependentsSamples.cs b/samples/core/CascadeDeletes/OptionalDependentsSamples.cs index 0585730316..b6ee4c779b 100644 --- a/samples/core/CascadeDeletes/OptionalDependentsSamples.cs +++ b/samples/core/CascadeDeletes/OptionalDependentsSamples.cs @@ -187,7 +187,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) optionsBuilder .EnableServiceProviderCaching(false) .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True;ConnectRetryCount=0"); //.UseSqlite("DataSource=test.db"); if (!_quiet) @@ -196,4 +196,4 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) } } } -} \ No newline at end of file +} diff --git a/samples/core/CascadeDeletes/RequiredDependentsSamples.cs b/samples/core/CascadeDeletes/RequiredDependentsSamples.cs index eda55142a8..2ec40840bb 100644 --- a/samples/core/CascadeDeletes/RequiredDependentsSamples.cs +++ b/samples/core/CascadeDeletes/RequiredDependentsSamples.cs @@ -192,7 +192,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) optionsBuilder .EnableServiceProviderCaching(false) .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True;ConnectRetryCount=0"); //.UseSqlite("DataSource=test.db"); if (!_quiet) @@ -201,4 +201,4 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) } } } -} \ No newline at end of file +} diff --git a/samples/core/CascadeDeletes/WithDatabaseCycleSamples.cs b/samples/core/CascadeDeletes/WithDatabaseCycleSamples.cs index 90e7659bae..70c4d39f88 100644 --- a/samples/core/CascadeDeletes/WithDatabaseCycleSamples.cs +++ b/samples/core/CascadeDeletes/WithDatabaseCycleSamples.cs @@ -169,7 +169,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Scratch;Trusted_Connection=True;ConnectRetryCount=0"); //.UseSqlite("DataSource=test.db"); if (!_quiet) @@ -177,4 +177,4 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) optionsBuilder.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }); } } -} \ No newline at end of file +} diff --git a/samples/core/DbContextPooling/Program.cs b/samples/core/DbContextPooling/Program.cs index 78f14a0002..b46fb23195 100644 --- a/samples/core/DbContextPooling/Program.cs +++ b/samples/core/DbContextPooling/Program.cs @@ -38,7 +38,7 @@ public class BlogController public class Startup { private const string ConnectionString - = @"Server=(localdb)\mssqllocaldb;Database=Demo.ContextPooling;Trusted_Connection=True"; + = @"Server=(localdb)\mssqllocaldb;Database=Demo.ContextPooling;Trusted_Connection=True;ConnectRetryCount=0"; public void ConfigureServices(IServiceCollection services) { @@ -136,4 +136,4 @@ private static async Task MonitorResults(TimeSpan duration, Stopwatch stopwatch) stopwatch.Stop(); } -} \ No newline at end of file +} diff --git a/samples/core/Intro/Model.cs b/samples/core/Intro/Model.cs index 5f912c47aa..00b0c9250a 100644 --- a/samples/core/Intro/Model.cs +++ b/samples/core/Intro/Model.cs @@ -11,7 +11,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0"); } } @@ -31,4 +31,4 @@ public class Post public int BlogId { get; set; } public Blog Blog { get; set; } -} \ No newline at end of file +} diff --git a/samples/core/Miscellaneous/Async/Program.cs b/samples/core/Miscellaneous/Async/Program.cs index 8f4d268453..5b6c5a847c 100644 --- a/samples/core/Miscellaneous/Async/Program.cs +++ b/samples/core/Miscellaneous/Async/Program.cs @@ -30,7 +30,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFAsync;Trusted_Connection=True"); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFAsync;Trusted_Connection=True;ConnectRetryCount=0"); } } @@ -39,4 +39,4 @@ public class Blog public int BlogId { get; set; } public string Url { get; set; } public int Rating { get; set; } -} \ No newline at end of file +} diff --git a/samples/core/Miscellaneous/AsyncWithSystemInteractive/Program.cs b/samples/core/Miscellaneous/AsyncWithSystemInteractive/Program.cs index 5cac9008c0..4d76d32e21 100644 --- a/samples/core/Miscellaneous/AsyncWithSystemInteractive/Program.cs +++ b/samples/core/Miscellaneous/AsyncWithSystemInteractive/Program.cs @@ -29,7 +29,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFAsync;Trusted_Connection=True"); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFAsync;Trusted_Connection=True;ConnectRetryCount=0"); } } @@ -38,4 +38,4 @@ public class Blog public int BlogId { get; set; } public string Url { get; set; } public int Rating { get; set; } -} \ No newline at end of file +} diff --git a/samples/core/Miscellaneous/Collations/Program.cs b/samples/core/Miscellaneous/Collations/Program.cs index 04657c5023..e045cfaf40 100644 --- a/samples/core/Miscellaneous/Collations/Program.cs +++ b/samples/core/Miscellaneous/Collations/Program.cs @@ -30,7 +30,7 @@ public class CustomerContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCollations;Trusted_Connection=True"); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCollations;Trusted_Connection=True;ConnectRetryCount=0"); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -50,4 +50,4 @@ public class Customer { public int Id { get; set; } public string Name { get; set; } -} \ No newline at end of file +} diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/AdditionalConfiguration/ApplicationDbContext.cs b/samples/core/Miscellaneous/ConfiguringDbContext/AdditionalConfiguration/ApplicationDbContext.cs index cac31036b8..52136616b7 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/AdditionalConfiguration/ApplicationDbContext.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/AdditionalConfiguration/ApplicationDbContext.cs @@ -9,7 +9,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0"); } } -#endregion \ No newline at end of file +#endregion diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/UseNewForWebApp.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/UseNewForWebApp.cs index a106307a90..27a4aa1f3e 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/UseNewForWebApp.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/UseNewForWebApp.cs @@ -8,10 +8,10 @@ public static void Example() { #region UseNewForWebApp var contextOptions = new DbContextOptionsBuilder() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0") .Options; using var context = new ApplicationDbContext(contextOptions); #endregion } -} \ No newline at end of file +} diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WithContextFactory/FactoryServicesExample.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WithContextFactory/FactoryServicesExample.cs index f7222c3385..034058717a 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/WithContextFactory/FactoryServicesExample.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WithContextFactory/FactoryServicesExample.cs @@ -11,7 +11,7 @@ public void ConfigureServices(IServiceCollection services) { services.AddDbContextFactory( options => - options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test")); + options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0")); } #endregion -} \ No newline at end of file +} diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WithNew/ApplicationDbContext.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WithNew/ApplicationDbContext.cs index 4c719ac005..70df3560a3 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/WithNew/ApplicationDbContext.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WithNew/ApplicationDbContext.cs @@ -7,7 +7,7 @@ public class ApplicationDbContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test"); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0"); } } -#endregion \ No newline at end of file +#endregion diff --git a/samples/core/Miscellaneous/ConnectionInterception/BlogsContext.cs b/samples/core/Miscellaneous/ConnectionInterception/BlogsContext.cs index a1f0650967..1fce0ff8a5 100644 --- a/samples/core/Miscellaneous/ConnectionInterception/BlogsContext.cs +++ b/samples/core/Miscellaneous/ConnectionInterception/BlogsContext.cs @@ -4,7 +4,7 @@ public class BlogsContext : DbContext { - private const string ConnectionString = @"Server=(localdb)\mssqllocaldb;Database=InterceptionTest;Trusted_Connection=True"; + private const string ConnectionString = @"Server=(localdb)\mssqllocaldb;Database=InterceptionTest;Trusted_Connection=True;ConnectRetryCount=0"; private static readonly AadAuthenticationInterceptor _interceptor = new AadAuthenticationInterceptor(); diff --git a/samples/core/Miscellaneous/ConnectionResiliency/Program.cs b/samples/core/Miscellaneous/ConnectionResiliency/Program.cs index de75f7fc6b..67eeb28cf5 100644 --- a/samples/core/Miscellaneous/ConnectionResiliency/Program.cs +++ b/samples/core/Miscellaneous/ConnectionResiliency/Program.cs @@ -130,7 +130,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFMiscellanous.ConnectionResiliency;Trusted_Connection=True", + @"Server=(localdb)\mssqllocaldb;Database=EFMiscellanous.ConnectionResiliency;Trusted_Connection=True;ConnectRetryCount=0", options => options.EnableRetryOnFailure()); } #endregion diff --git a/samples/core/Miscellaneous/Logging/Logging/BloggingContext.cs b/samples/core/Miscellaneous/Logging/Logging/BloggingContext.cs index 216b54b04e..16283d63f9 100644 --- a/samples/core/Miscellaneous/Logging/Logging/BloggingContext.cs +++ b/samples/core/Miscellaneous/Logging/Logging/BloggingContext.cs @@ -17,7 +17,7 @@ public static readonly ILoggerFactory MyLoggerFactory protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseLoggerFactory(MyLoggerFactory) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True;ConnectRetryCount=0"); #endregion } @@ -65,4 +65,4 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .ConfigureWarnings(b => b.Throw(RelationalEventId.QueryPossibleUnintendedUseOfEqualsWarning)); #endregion -} \ No newline at end of file +} diff --git a/samples/core/Miscellaneous/Logging/Logging/BloggingContextWithFiltering.cs b/samples/core/Miscellaneous/Logging/Logging/BloggingContextWithFiltering.cs index 2f5a7daf0b..164b647265 100644 --- a/samples/core/Miscellaneous/Logging/Logging/BloggingContextWithFiltering.cs +++ b/samples/core/Miscellaneous/Logging/Logging/BloggingContextWithFiltering.cs @@ -26,6 +26,6 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseLoggerFactory(MyLoggerFactory) // Warning: Do not create a new ILoggerFactory instance each time .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFLogging;Trusted_Connection=True;ConnectRetryCount=0"); #endregion -} \ No newline at end of file +} diff --git a/samples/core/Miscellaneous/NewInEFCore6/ArrayParametersSample.cs b/samples/core/Miscellaneous/NewInEFCore6/ArrayParametersSample.cs index 959883e652..75d33e224e 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/ArrayParametersSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/ArrayParametersSample.cs @@ -61,7 +61,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/BoolToStringTranslationSample.cs b/samples/core/Miscellaneous/NewInEFCore6/BoolToStringTranslationSample.cs index 889a3cf209..685c2748fd 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/BoolToStringTranslationSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/BoolToStringTranslationSample.cs @@ -95,7 +95,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/ColumnOrderSample.cs b/samples/core/Miscellaneous/NewInEFCore6/ColumnOrderSample.cs index 87c0814783..011161d1bc 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/ColumnOrderSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/ColumnOrderSample.cs @@ -153,7 +153,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/CommandSourceSample.cs b/samples/core/Miscellaneous/NewInEFCore6/CommandSourceSample.cs index af4c4a551a..f2b29eb3f4 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/CommandSourceSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/CommandSourceSample.cs @@ -23,7 +23,7 @@ public static void Interceptors_get_the_source_of_the_command() }); context.SaveChanges(); - + context.ChangeTracker.Clear(); var customers = context.Customers.ToList(); @@ -64,7 +64,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) optionsBuilder .EnableSensitiveDataLogging() .AddInterceptors(new CommandSourceInterceptor()) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); } } } diff --git a/samples/core/Miscellaneous/NewInEFCore6/ContainsFreeTextSample.cs b/samples/core/Miscellaneous/NewInEFCore6/ContainsFreeTextSample.cs index a2f0c3df7b..72abcbc68c 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/ContainsFreeTextSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/ContainsFreeTextSample.cs @@ -124,7 +124,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/ConvertNullsSample.cs b/samples/core/Miscellaneous/NewInEFCore6/ConvertNullsSample.cs index c889ed0d85..e78a9c2d23 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/ConvertNullsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/ConvertNullsSample.cs @@ -151,7 +151,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { @@ -214,7 +214,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/DbContextFactorySample.cs b/samples/core/Miscellaneous/NewInEFCore6/DbContextFactorySample.cs index 3f0b23bf7d..cf4a12d919 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/DbContextFactorySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/DbContextFactorySample.cs @@ -12,7 +12,7 @@ public static void Ignore_parameterless_constructor_when_creating_DbContext_from var services = new ServiceCollection() .AddDbContextFactory( - builder => builder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample")) + builder => builder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0")) .BuildServiceProvider(); var factory = services.GetService>(); @@ -32,7 +32,7 @@ public static void AddDbContextFactory_also_registers_scoped_DbContext_instance( #region Registration var container = services .AddDbContextFactory( - builder => builder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample")) + builder => builder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0")) .BuildServiceProvider(); #endregion @@ -93,7 +93,7 @@ public void DoSomething() var results1 = context1.Blogs.ToList(); var results2 = context2.Blogs.ToList(); - + // Contexts obtained from the factory must be explicitly disposed } } @@ -115,7 +115,7 @@ public SomeDbContext(DbContextOptions options) : base(options) { } - + public DbSet Blogs { get; set; } } #endregion diff --git a/samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs b/samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs index c0d1e6d30d..00863f4302 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs @@ -84,7 +84,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/GroupBySample.cs b/samples/core/Miscellaneous/NewInEFCore6/GroupBySample.cs index 8825686d6b..554dca5e8f 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/GroupBySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/GroupBySample.cs @@ -547,7 +547,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/HasConversionSample.cs b/samples/core/Miscellaneous/NewInEFCore6/HasConversionSample.cs index d674780a98..6de0b391d6 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/HasConversionSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/HasConversionSample.cs @@ -124,7 +124,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/IsNullOrWhitespaceSample.cs b/samples/core/Miscellaneous/NewInEFCore6/IsNullOrWhitespaceSample.cs index 28e65299fa..c70a067906 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/IsNullOrWhitespaceSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/IsNullOrWhitespaceSample.cs @@ -98,7 +98,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/ManyToManyConfigurationSample.cs b/samples/core/Miscellaneous/NewInEFCore6/ManyToManyConfigurationSample.cs index d865977e40..0019756eac 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/ManyToManyConfigurationSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/ManyToManyConfigurationSample.cs @@ -31,7 +31,7 @@ public static void ManyToManyTest() Console.WriteLine(context.Model.ToDebugString()); Console.WriteLine(); - + context.Log = true; context.Database.EnsureCreated(); context.Log = false; @@ -50,7 +50,7 @@ public static void ManyToManyTest() context.SaveChanges(); } - + Console.WriteLine(); using (var context = new TContext()) @@ -77,7 +77,7 @@ public class Human public string Name { get; set; } public ICollection Cats { get; } = new List(); } - + public class CatHuman { public int CatsId { get; set; } @@ -168,7 +168,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); optionsBuilder.LogTo( s => diff --git a/samples/core/Miscellaneous/NewInEFCore6/MathFTranslationSample.cs b/samples/core/Miscellaneous/NewInEFCore6/MathFTranslationSample.cs index d758826e78..2431e88399 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/MathFTranslationSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/MathFTranslationSample.cs @@ -91,7 +91,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/MinimalApiSample.cs b/samples/core/Miscellaneous/NewInEFCore6/MinimalApiSample.cs index 792de7a29e..8d6729ceee 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/MinimalApiSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/MinimalApiSample.cs @@ -7,10 +7,10 @@ public static class MinimalApiSample public static void Add_a_DbContext_and_provider() { Console.WriteLine($">>>> Sample: {nameof(Add_a_DbContext_and_provider)}"); - + SqliteMinimal(null); SqliteNormal(null); - + SqlServerMinimal(null); SqlServerNormal(null); } @@ -49,7 +49,7 @@ private static void SqlServerNormal(string[] args) var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext( - options => options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=MyDatabase")); + options => options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=MyDatabase;ConnectRetryCount=0")); #endregion } diff --git a/samples/core/Miscellaneous/NewInEFCore6/OptionalDependentsSample.cs b/samples/core/Miscellaneous/NewInEFCore6/OptionalDependentsSample.cs index 17efe88e49..9e7f11f958 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/OptionalDependentsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/OptionalDependentsSample.cs @@ -580,7 +580,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/PreConventionModelConfigurationSample.cs b/samples/core/Miscellaneous/NewInEFCore6/PreConventionModelConfigurationSample.cs index 7cc8837703..c3171b9833 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/PreConventionModelConfigurationSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/PreConventionModelConfigurationSample.cs @@ -144,7 +144,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); //if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/PrecisionAttributeSample.cs b/samples/core/Miscellaneous/NewInEFCore6/PrecisionAttributeSample.cs index 2d9e953987..96dcc663c6 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/PrecisionAttributeSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/PrecisionAttributeSample.cs @@ -65,7 +65,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/PublicPooledDbContextFactorySample.cs b/samples/core/Miscellaneous/NewInEFCore6/PublicPooledDbContextFactorySample.cs index 62ab79d87f..2ffad55c0f 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/PublicPooledDbContextFactorySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/PublicPooledDbContextFactorySample.cs @@ -12,7 +12,7 @@ public static void Can_create_pooled_DbContext_factory() #region CreatePool var options = new DbContextOptionsBuilder() .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0") .Options; var factory = new PooledDbContextFactory(options); diff --git a/samples/core/Miscellaneous/NewInEFCore6/RandomFunctionSample.cs b/samples/core/Miscellaneous/NewInEFCore6/RandomFunctionSample.cs index 5720b7e4bf..3ae68e3281 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/RandomFunctionSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/RandomFunctionSample.cs @@ -79,7 +79,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/SparseColumnsSample.cs b/samples/core/Miscellaneous/NewInEFCore6/SparseColumnsSample.cs index 31947e78ce..d3ceeb7bef 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/SparseColumnsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/SparseColumnsSample.cs @@ -78,7 +78,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/SplitQuerySample.cs b/samples/core/Miscellaneous/NewInEFCore6/SplitQuerySample.cs index 2f8584379e..6ae9ffd1cd 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/SplitQuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/SplitQuerySample.cs @@ -176,7 +176,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/StringConcatSample.cs b/samples/core/Miscellaneous/NewInEFCore6/StringConcatSample.cs index 0997acd2fa..a4d083d26e 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/StringConcatSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/StringConcatSample.cs @@ -116,7 +116,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/SubstringTranslationSample.cs b/samples/core/Miscellaneous/NewInEFCore6/SubstringTranslationSample.cs index 00d3fbe39b..09f2c54a22 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/SubstringTranslationSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/SubstringTranslationSample.cs @@ -79,7 +79,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/TagWithFileAndLineSample.cs b/samples/core/Miscellaneous/NewInEFCore6/TagWithFileAndLineSample.cs index e2a0e4ea38..6d17211929 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/TagWithFileAndLineSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/TagWithFileAndLineSample.cs @@ -88,7 +88,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/TemporalTablesSample.cs b/samples/core/Miscellaneous/NewInEFCore6/TemporalTablesSample.cs index cb531ffdfa..fef92f1eb1 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/TemporalTablesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/TemporalTablesSample.cs @@ -290,7 +290,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/TemporaryValuesSample.cs b/samples/core/Miscellaneous/NewInEFCore6/TemporaryValuesSample.cs index d59bd7e204..fc120a4a01 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/TemporaryValuesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/TemporaryValuesSample.cs @@ -140,7 +140,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/TrailingUnderscoresSample.cs b/samples/core/Miscellaneous/NewInEFCore6/TrailingUnderscoresSample.cs index 6ab07bc8d7..ed730ca078 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/TrailingUnderscoresSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/TrailingUnderscoresSample.cs @@ -74,7 +74,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore6/UnicodeAttributeSample.cs b/samples/core/Miscellaneous/NewInEFCore6/UnicodeAttributeSample.cs index 41658176fd..a3648f8acb 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/UnicodeAttributeSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6/UnicodeAttributeSample.cs @@ -69,7 +69,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreSample;ConnectRetryCount=0"); if (!_quiet) { diff --git a/samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs b/samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs index a8baa0c521..64e04e5a06 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs @@ -185,7 +185,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}", + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0", sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore7/DocumentsContext.cs b/samples/core/Miscellaneous/NewInEFCore7/DocumentsContext.cs index 5fda832e45..4b0127bffa 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/DocumentsContext.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/DocumentsContext.cs @@ -81,7 +81,7 @@ public abstract class DocumentsContext : DbContext public DbSet People => Set(); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}") + => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0") .EnableSensitiveDataLogging() .LogTo( s => diff --git a/samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs b/samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs index 31f9b4c48e..3b22c4ae7f 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs @@ -90,7 +90,7 @@ public class BookContextSqlServer : BookContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => base.OnConfiguring( - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Books")); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Books;ConnectRetryCount=0")); } public class BookContextSqlite : BookContext diff --git a/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs b/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs index 9afd5c7016..dafe9ba50e 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs @@ -75,7 +75,7 @@ public class BookContextSqlServer : BookContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => base.OnConfiguring( - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Books")); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Books;ConnectRetryCount=0")); } public class BookContextSqlite : BookContext diff --git a/samples/core/Miscellaneous/NewInEFCore7/GroupJoinFinalOperatorSample.cs b/samples/core/Miscellaneous/NewInEFCore7/GroupJoinFinalOperatorSample.cs index e81526c6a9..56bb973af2 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/GroupJoinFinalOperatorSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/GroupJoinFinalOperatorSample.cs @@ -104,7 +104,7 @@ public class GroupJoinContextSqlServer : GroupJoinContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => base.OnConfiguring( - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Customers")); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Customers;ConnectRetryCount=0")); } public class GroupJoinContextSqlite : GroupJoinContext diff --git a/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingConventionsSample.cs b/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingConventionsSample.cs index acf4fcf933..06a2a23681 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingConventionsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingConventionsSample.cs @@ -259,7 +259,7 @@ public class LaundryContext : DbContext public DbSet LaundryBaskets => Set(); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}"); + => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0"); #region ReplaceConvention protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) @@ -386,7 +386,7 @@ public class TenantIdValidatingContext : DbContext public DbSet LaundryBaskets => Set(); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}"); + => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0"); protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { diff --git a/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs b/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs index 979d833dcb..073b6420fc 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs @@ -305,7 +305,7 @@ public class BlogsContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=Blogs") + .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=Blogs;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging(); @@ -401,7 +401,7 @@ public class AnimalsTptContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=AnimalsTpt") + .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=AnimalsTpt;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging(); @@ -427,7 +427,7 @@ public class AnimalsTpcContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=AnimalsTpc") + .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=AnimalsTpc;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging(); @@ -485,7 +485,7 @@ public DbSet Employees protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=Images") + .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=Images;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging(); diff --git a/samples/core/Miscellaneous/NewInEFCore7/QueryStatisticsLoggerSample.cs b/samples/core/Miscellaneous/NewInEFCore7/QueryStatisticsLoggerSample.cs index 0f31bb5839..d01287061a 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/QueryStatisticsLoggerSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/QueryStatisticsLoggerSample.cs @@ -15,7 +15,7 @@ public static async Task Executing_commands_after_consuming_a_result_set() var serviceProvider = new ServiceCollection() .AddDbContext( b => b.UseLoggerFactory(loggerFactory) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ConsumedDataReaderSample")) + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ConsumedDataReaderSample;ConnectRetryCount=0")) .BuildServiceProvider(); using (var scope = serviceProvider.CreateScope()) diff --git a/samples/core/Miscellaneous/NewInEFCore7/ReadOnlySetQuerySample.cs b/samples/core/Miscellaneous/NewInEFCore7/ReadOnlySetQuerySample.cs index 1fba3603c7..7423cce829 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/ReadOnlySetQuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/ReadOnlySetQuerySample.cs @@ -114,7 +114,7 @@ public class ReadOnlySetContextSqlServer : ReadOnlySetContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => base.OnConfiguring( - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Customers")); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Customers;ConnectRetryCount=0")); } public class ReadOnlySetContextSqlite : ReadOnlySetContext diff --git a/samples/core/Miscellaneous/NewInEFCore7/SaveChangesPerformanceSample.cs b/samples/core/Miscellaneous/NewInEFCore7/SaveChangesPerformanceSample.cs index 467a0ce693..2daca432ff 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/SaveChangesPerformanceSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/SaveChangesPerformanceSample.cs @@ -147,7 +147,7 @@ public class PerfContextSqlServer : PerfContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => base.OnConfiguring( - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=SaveChangesPerf")); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=SaveChangesPerf;ConnectRetryCount=0")); } public class PerfContextSqlite : PerfContext diff --git a/samples/core/Miscellaneous/NewInEFCore7/StatisticalAggregateFunctionsSample.cs b/samples/core/Miscellaneous/NewInEFCore7/StatisticalAggregateFunctionsSample.cs index 4ff3b2139c..9bd247f1b7 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/StatisticalAggregateFunctionsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/StatisticalAggregateFunctionsSample.cs @@ -60,7 +60,7 @@ public class StatisticsContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Downloads") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Downloads;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging(); } diff --git a/samples/core/Miscellaneous/NewInEFCore7/TpcInheritanceSample.cs b/samples/core/Miscellaneous/NewInEFCore7/TpcInheritanceSample.cs index e1e9288d39..ecebf60bd7 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/TpcInheritanceSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/TpcInheritanceSample.cs @@ -397,7 +397,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .EnableSensitiveDataLogging() - .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}"); + .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0"); optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information); } diff --git a/samples/core/Miscellaneous/NewInEFCore7/UngroupedColumnsQuerySample.cs b/samples/core/Miscellaneous/NewInEFCore7/UngroupedColumnsQuerySample.cs index f5996fdb23..d81ff01d85 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/UngroupedColumnsQuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/UngroupedColumnsQuerySample.cs @@ -72,7 +72,7 @@ public class InvoiceContextSqlServer : InvoiceContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => base.OnConfiguring( - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Invoices")); + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Invoices;ConnectRetryCount=0")); } public class InvoiceContextSqlite : InvoiceContext diff --git a/samples/core/Miscellaneous/NewInEFCore7/ValueGenerationSample.cs b/samples/core/Miscellaneous/NewInEFCore7/ValueGenerationSample.cs index b8afb2905d..64380bee68 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/ValueGenerationSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/ValueGenerationSample.cs @@ -47,7 +47,7 @@ public class ProductsContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=Products") + .UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database=Products;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging(); diff --git a/samples/core/Miscellaneous/NewInEFCore8/BlogsContext.cs b/samples/core/Miscellaneous/NewInEFCore8/BlogsContext.cs index c8a72ccc41..ebf2ce026d 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/BlogsContext.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/BlogsContext.cs @@ -210,7 +210,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}", + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0", sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore8/ComplexTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore8/ComplexTypesSample.cs index 885e532457..7f53c731b2 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/ComplexTypesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/ComplexTypesSample.cs @@ -110,7 +110,7 @@ public abstract class CustomerContextBase(bool useSqlite = false) : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") - : optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + : optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) .EnableSensitiveDataLogging() .LogTo( s => diff --git a/samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs b/samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs index d7a1b3edc0..8e5eae9baa 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs @@ -156,7 +156,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}", + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0", sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs b/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs index f070317aa8..ca37df95f7 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs @@ -173,7 +173,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}", + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0", sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) .EnableSensitiveDataLogging() .LogTo(Console.WriteLine, LogLevel.Information); diff --git a/samples/core/Miscellaneous/NewInEFCore8/DocumentsContext.cs b/samples/core/Miscellaneous/NewInEFCore8/DocumentsContext.cs index 629f951356..80e72eefb3 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/DocumentsContext.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/DocumentsContext.cs @@ -80,7 +80,7 @@ public abstract class DocumentsContext : DbContext public DbSet People => Set(); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}") + => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0") .EnableSensitiveDataLogging() .LogTo( s => diff --git a/samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs b/samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs index 8957425a1f..b668184b6a 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs @@ -157,7 +157,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}", + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0", sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) .EnableSensitiveDataLogging() .LogTo(Console.WriteLine, LogLevel.Information); diff --git a/samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs b/samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs index 2769b9f85a..f319ce386e 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs @@ -230,7 +230,7 @@ public class FamilyTreeContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}", + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0", sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseHierarchyId()) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore8/ImmutableComplexTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore8/ImmutableComplexTypesSample.cs index 2f113f4fa6..2b43a775dc 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/ImmutableComplexTypesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/ImmutableComplexTypesSample.cs @@ -100,7 +100,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) //sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseCompatibilityLevel(120))) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore8/ImmutableStructComplexTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore8/ImmutableStructComplexTypesSample.cs index b5987b86da..8bfb3ed97b 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/ImmutableStructComplexTypesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/ImmutableStructComplexTypesSample.cs @@ -106,7 +106,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) //sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseCompatibilityLevel(120))) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore8/NestedComplexTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore8/NestedComplexTypesSample.cs index 5b71bafe06..ed49aadd21 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/NestedComplexTypesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/NestedComplexTypesSample.cs @@ -206,7 +206,7 @@ public abstract class CustomerContextBase(bool useSqlite = false) : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") - : optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + : optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) .EnableSensitiveDataLogging() .LogTo( s => diff --git a/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionToTableSample.cs b/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionToTableSample.cs index 29d4eb3ea2..ede3b7e5d1 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionToTableSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionToTableSample.cs @@ -108,7 +108,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) .EnableSensitiveDataLogging() .LogTo( s => diff --git a/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs b/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs index 986785287c..042ac034b8 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs @@ -190,7 +190,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) //sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseCompatibilityLevel(120))) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs b/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs index 61dbac5a5e..ffdd96204b 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs @@ -248,7 +248,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) //sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseCompatibilityLevel(120))) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore8/RecordComplexTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore8/RecordComplexTypesSample.cs index a779f32d92..d495f148dc 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/RecordComplexTypesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/RecordComplexTypesSample.cs @@ -93,7 +93,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) //sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseCompatibilityLevel(120))) .EnableSensitiveDataLogging() .LogTo( @@ -245,7 +245,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) //sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseCompatibilityLevel(120))) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore8/StructComplexTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore8/StructComplexTypesSample.cs index c117f56d4b..8380456fcb 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/StructComplexTypesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/StructComplexTypesSample.cs @@ -107,7 +107,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (UseSqlite ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") : optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) //sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseCompatibilityLevel(120))) .EnableSensitiveDataLogging() .LogTo( diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj index 20df067599..fe513d3fc4 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj @@ -9,7 +9,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj index 92369134bc..2af439d9d3 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj @@ -15,13 +15,13 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosPrimitiveTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosPrimitiveTypesSample.cs new file mode 100644 index 0000000000..37c3a4bd7d --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosPrimitiveTypesSample.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; + +public static class CosmosPrimitiveTypesSample +{ + public static async Task Collections_and_dictionaries_of_primitive_types() + { + Console.WriteLine($">>>> Sample: {nameof(Collections_and_dictionaries_of_primitive_types)}"); + Console.WriteLine(); + + await Helpers.RecreateCleanDatabase(); + + using var context = new BooksContext(); + + var book = new Book + { + Title = "How It Works: Incredible History", + Quotes = new List + { + "Thomas (Tommy) Flowers was the British engineer behind the design of the Colossus computer.", + "Invented originally for Guinness, plastic widgets are nitrogen-filled spheres.", + "For 20 years after its introduction in 1979, the Walkman dominated the personal stereo market." + }, + Notes = new Dictionary + { + { "121", "Fridges" }, + { "144", "Peter Higgs" }, + { "48", "Saint Mark's Basilica" }, + { "36", "The Terracotta Army" } + } + }; + + context.Add(book); + await context.SaveChangesAsync(); + + book.Quotes.Add("Pressing the emergency button lowered the rods again."); + book.Notes["48"] = "Chiesa d'Oro"; + + await context.SaveChangesAsync(); + + Console.WriteLine(); + } + + public static class Helpers + { + public static async Task RecreateCleanDatabase() + { + await using var context = new BooksContext(quiet: true); + + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); + } + } + + public class Book + { + public Guid Id { get; set; } + public string Title { get; set; } + public IList Quotes { get; set; } + public IDictionary Notes { get; set; } + } + + public class BooksContext : DbContext + { + public DbSet Books { get; set; } + + private readonly bool _quiet; + + public BooksContext(bool quiet = false) + { + _quiet = quiet; + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().ToContainer("Shapes"); + + #region ConfigureCollection + modelBuilder.Entity() + .PrimitiveCollection(e => e.Quotes) + .ElementType(b => b.IsRequired()); + #endregion + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder + .EnableSensitiveDataLogging() + .UseCosmos( + "https://localhost:8081/", + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", + "PrimitiveCollections", + cosmosOptionsBuilder => + { + cosmosOptionsBuilder.HttpClientFactory( + () => new HttpClient( + new HttpClientHandler + { + ServerCertificateCustomValidationCallback = + HttpClientHandler.DangerousAcceptAnyServerCertificateValidator + })); + }); + + if (!_quiet) + { + optionsBuilder.LogTo( + Console.WriteLine, + new[] { CosmosEventId.ExecutedCreateItem, CosmosEventId.ExecutingSqlQuery, CoreEventId.SaveChangesCompleted }); + } + } + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs new file mode 100644 index 0000000000..0c90397a22 --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.Logging; + +public static class CosmosSyncApisSample +{ + public static void Cosmos_provider_blocks_sync_APIs() + { + Console.WriteLine($">>>> Sample: {nameof(Cosmos_provider_blocks_sync_APIs)}"); + Console.WriteLine(); + + Helpers.RecreateCleanDatabase(); + Helpers.PopulateDatabase(); + + using var context = new ShapesContext(); + + var triangle = new Triangle + { + Name = "Impossible", + PartitionKey = "TrianglesPartition", + Angle1 = 90, + Angle2 = 90, + InsertedOn = DateTime.UtcNow + }; + context.Add(triangle); + context.SaveChanges(); + + var equilateral = context.Triangles.Single(e => e.Name == "Equilateral"); + var isosceles = context.Triangles.Find("Isosceles", "TrianglesPartition"); + + triangle.Angle2 = 89; + context.SaveChanges(); + + context.Remove(triangle); + context.SaveChanges(); + } + + public static class Helpers + { + public static void RecreateCleanDatabase() + { + using var context = new ShapesContext(quiet: true); + + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + } + + public static void PopulateDatabase() + { + using var context = new ShapesContext(quiet: true); + + var triangles = new List + { + new() { Name = "Acute", PartitionKey = "TrianglesPartition", Angle1 = 75, Angle2 = 85, InsertedOn = DateTime.UtcNow }, + new() { Name = " Obtuse ", PartitionKey = "TrianglesPartition", Angle1 = 110, Angle2 = 35, InsertedOn = DateTime.UtcNow }, + new() { Name = "Right", PartitionKey = "TrianglesPartition", Angle1 = 90, Angle2 = 45, InsertedOn = DateTime.UtcNow }, + new() { Name = "Isosceles", PartitionKey = "TrianglesPartition", Angle1 = 75, Angle2 = 75, InsertedOn = DateTime.UtcNow }, + new() { Name = "Equilateral", PartitionKey = "TrianglesPartition", Angle1 = 60, Angle2 = 60, InsertedOn = DateTime.UtcNow } + }; + + context.AddRange(triangles); + context.SaveChanges(); + } + } + + public class Triangle + { + public string PartitionKey { get; set; } + public string Name { get; set; } + public double Angle1 { get; set; } + public double Angle2 { get; set; } + public DateTime InsertedOn { get; set; } + } + + public class ShapesContext(bool quiet = false) : DbContext + { + public DbSet Triangles { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity( + b => + { + b.ToContainer("Shapes"); + b.HasPartitionKey(e => e.PartitionKey); + b.HasKey(e => new { e.Name, e.PartitionKey }); + b.Property(c => c.Name).ToJsonProperty("id"); + b.Property(c => c.PartitionKey).ToJsonProperty("pk"); + }); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder + .ConfigureWarnings(b => b.Log(CosmosEventId.SyncNotSupported)) + .LogTo(Console.WriteLine, LogLevel.Information) + .EnableSensitiveDataLogging() + .UseCosmos( + "https://localhost:8081/", + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", + "Triangles"); + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj new file mode 100644 index 0000000000..ba4fe7e8f0 --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj @@ -0,0 +1,13 @@ + + + + Exe + net8.0 + + + + + + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/Program.cs b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/Program.cs new file mode 100644 index 0000000000..dacbe2028a --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/Program.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +public class Program +{ + public static async Task Main() + { + // Note: These samples requires the Cosmos DB emulator to be installed and running + CosmosSyncApisSample.Cosmos_provider_blocks_sync_APIs(); + await CosmosPrimitiveTypesSample.Collections_and_dictionaries_of_primitive_types(); + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs new file mode 100644 index 0000000000..3ced347a37 --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs @@ -0,0 +1,148 @@ +namespace NewInEfCore9; + +public static class ComplexTypesSample +{ + public static Task GropupBy_complex_type_instances() + => ExecuteQueries(sqlite: false); + + public static Task GropupBy_complex_type_instances_on_SQLite() + => ExecuteQueries(sqlite: true); + + public static async Task ExecuteQueries(bool sqlite) + { + PrintSampleName(); + + await using var context = new CustomerContext(useSqlite: sqlite); + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); + + context.AddRange( + new Store + { + Customers = { new CustomerWithStores { Name = "Smokey", Region = "Germany" } }, + Region = "Germany", + StoreAddress = new("L1", null, "Ci1", "Co1", "P1") + }, + new Customer + { + Name = "Smokey", + CustomerInfo = new("EF") + { + HomeAddress = new("L2", null, "Ci2", "Co2", "P2"), WorkAddress = new("L3", null, "Ci3", "Co3", "P3") + }, + }, + new CustomerTpt + { + Name = "Willow", + CustomerInfo = new("EF") + { + HomeAddress = new("L5", null, "Ci5", "Co5", "P5"), WorkAddress = new("L6", null, "Ci6", "Co6", "P6") + }, + }, + new SpecialCustomerTpt + { + Name = "Olive", + CustomerInfo = new("EF") + { + HomeAddress = new("L7", null, "Ci7", "Co7", "P7"), WorkAddress = new("L8", null, "Ci8", "Co8", "P8") + } + }); + + await context.SaveChangesAsync(); + context.ChangeTracker.Clear(); + + Console.WriteLine(); + Console.WriteLine("GroupBy complex type:"); + Console.WriteLine(); + + #region GroupByComplexType + var groupedAddresses = await context.Stores + .GroupBy(b => b.StoreAddress) + .Select(g => new { g.Key, Count = g.Count() }) + .ToListAsync(); + #endregion + + foreach (var groupedAddress in groupedAddresses) + { + Console.WriteLine($"{groupedAddress.Key.PostCode}: {groupedAddress.Count}"); + } + } + + private static void PrintSampleName([CallerMemberName] string? methodName = null) + { + Console.WriteLine($">>>> Sample: {methodName}"); + Console.WriteLine(); + } + + [Table("TptSpecialCustomers")] + public class SpecialCustomerTpt : CustomerTpt + { + public string? Note { get; set; } + } + + [Table("TptCustomers")] + public class CustomerTpt + { + public int Id { get; set; } + public required string Name { get; set; } + public required CustomerInfo CustomerInfo { get; set; } + } + + public class Customer + { + public int Id { get; set; } + public required string Name { get; set; } + public required CustomerInfo CustomerInfo { get; set; } + } + + public record struct CustomerInfo(string? Tag) + { + public required Address HomeAddress { get; init; } + public required Address WorkAddress { get; init; } + } + + [ComplexType] + public record class Address(string Line1, string? Line2, string City, string Country, string PostCode); + + public class CustomerWithStores + { + public int Id { get; set; } + public required string Name { get; set; } + public string? Region { get; set; } + public string? Tag { get; set; } + } + + public class Store + { + public int Id { get; set; } + public List Customers { get; } = new(); + public string? Region { get; set; } + public required Address StoreAddress { get; set; } + } + + public class CustomerContext(bool useSqlite = false) : DbContext + { + public bool UseSqlite { get; } = useSqlite; + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => (UseSqlite + ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db", + sqliteOptionsBuilder => sqliteOptionsBuilder.UseNetTopologySuite()) + : optionsBuilder.UseSqlServer( + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0", + sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) + .EnableSensitiveDataLogging() + .LogTo(Console.WriteLine, LogLevel.Information); + + protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) + { + configurationBuilder.ComplexProperties(); + } + + public DbSet Customers => Set(); + public DbSet CustomersWithStores => Set(); + public DbSet Stores => Set(); + public DbSet TptCustomers => Set(); + public DbSet TptSpecialCustomers => Set(); + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj index 45bacb8f74..1f4c24d2a1 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj @@ -10,15 +10,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs b/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs new file mode 100644 index 0000000000..c050e002e3 --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs @@ -0,0 +1,509 @@ +using System.Collections; +using System.Collections.ObjectModel; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace NewInEfCore9; + +public static class PrimitiveCollectionsSample +{ + public static Task Queries_using_readonly_primitive_collections() + { + PrintSampleName(); + return ContainsTest(); + } + + public static Task Queries_using_readonly_primitive_collections_SQLite() + { + PrintSampleName(); + return ContainsTest(); + } + + private static async Task ContainsTest() + where TContext : PubsAndWalksContextBase, new() + { + await using var context = new TContext(); + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); + await context.Seed(); + + context.LoggingEnabled = true; + context.ChangeTracker.Clear(); + + var terrains = new[] { Terrain.River, Terrain.Beach, Terrain.Park }; + var walksWithTerrain = await context.Walks + .Where(e => terrains.Contains(e.Terrain)) + .Select(e => e.Name) + .ToListAsync(); + + Console.WriteLine($"\nWalks with given terrain are {string.Join(", ", walksWithTerrain.Select(w => $"\"{w}\""))}"); + + var beer = "Heineken"; + var pubsWithHeineken = await context.Pubs + .Where(e => e.Beers.Contains(beer)) + .Select(e => e.Name) + .ToListAsync(); + + Console.WriteLine($"\nPubs with {beer} are {string.Join(", ", pubsWithHeineken)}"); + + var beers = new[] { "Carling", "Heineken", "Stella Artois", "Carlsberg" }; + var pubsWithLager = await context.Pubs + .Where(e => beers.Any(b => e.Beers.Contains(b))) + .Select(e => e.Name) + .ToListAsync(); + + Console.WriteLine($"\nPubs with lager are {string.Join(", ", pubsWithLager)}"); + + var thisYear = DateTime.Now.Year; + var pubsVisitedThisYear = await context.Pubs + .Where(e => e.DaysVisited.Any(v => v.Year == thisYear)) + .Select(e => e.Name) + .ToListAsync(); + + Console.WriteLine($"\nPubs visited this year are {string.Join(", ", pubsVisitedThisYear)}"); + + var pubsVisitedInOrder = await context.Pubs + .Select( + e => new + { + e.Name, + FirstVisited = e.DaysVisited.OrderBy(v => v).First(), + LastVisited = e.DaysVisited.OrderByDescending(v => v).First(), + }) + .OrderBy(p => p.FirstVisited) + .ToListAsync(); + + foreach (var pub in pubsVisitedInOrder) + { + Console.WriteLine($"{pub.Name} first visited on {pub.FirstVisited} and last visited on {pub.LastVisited}"); + } + + #region WalksWithADrink + var walksWithADrink = await context.Walks.Select( + w => new + { + WalkName = w.Name, + PubName = w.ClosestPub.Name, + Count = w.DaysVisited.Count(v => w.ClosestPub.DaysVisited.Contains(v)), + TotalCount = w.DaysVisited.Count + }).ToListAsync(); + #endregion + + Console.WriteLine(); + foreach (var walk in walksWithADrink) + { + Console.WriteLine($"{walk.PubName} was visited {walk.Count} times in {walk.TotalCount} \"{walk.WalkName}\" walks."); + } + } + + private static void PrintSampleName([CallerMemberName] string? methodName = null) + { + Console.WriteLine($">>>> Sample: {methodName}"); + Console.WriteLine(); + } + + public class MyCollection : IList + { + private readonly List _list = new(); + public IEnumerator GetEnumerator() => _list.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public void Add(int item) => _list.Add(item); + public void Clear() => _list.Clear(); + public bool Contains(int item) => _list.Contains(item); + public void CopyTo(int[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex); + public bool Remove(int item) => _list.Remove(item); + public int Count => _list.Count; + public bool IsReadOnly => ((ICollection)_list).IsReadOnly; + public int IndexOf(int item) => _list.IndexOf(item); + public void Insert(int index, int item) => _list.Insert(index, item); + public void RemoveAt(int index) => _list.RemoveAt(index); + + public int this[int index] + { + get => _list[index]; + set => _list[index] = value; + } + } + + public class PrimitiveCollections + { + public int Id { get; set; } + public IReadOnlyList Ints { get; set; } = null!; + public IReadOnlyCollection Strings { get; set; } = null!; + public ReadOnlyCollection DateTimes { get; set; } = null!; + public IList Dates { get; set; } = null!; + + [MaxLength(2500)] + [Unicode(false)] + public uint[] UnsignedInts { get; set; } = null!; + + public ObservableCollection Guids { get; set; } = null!; + public List Booleans { get; set; } = null!; + public List Urls { get; set; } = null!; + public MyCollection SomeInts { get; set; } = null!; + public List GetOnlyInts { get; } = new(); + + // ReSharper disable once CollectionNeverUpdated.Local + private readonly List _intsField = new(); + + public List DddIds { get; set; } = null!; + } + + public readonly struct DddId + { + public DddId(int value) + { + Value = value; + } + + public int Value { get; } + } + + public class DddIdConverter : ValueConverter + { + public DddIdConverter() + : base(v => v.Value, v => new DddId()) + { + } + } + + public class DogWalk + { + public DogWalk(string name) + { + Name = name; + } + + public int Id { get; set; } + public string Name { get; set; } + public Terrain Terrain { get; set; } + public ReadOnlyCollection DaysVisited { get; set; } + public Pub ClosestPub { get; set; } = null!; + } + + public enum Terrain + { + Forest, + River, + Hills, + Village, + Park, + Beach, + } + + public class Pub + { + public Pub(string name, IReadOnlyCollection beers) + { + Name = name; + Beers = beers; + } + + public int Id { get; set; } + public string Name { get; set; } + public IReadOnlyCollection Beers { get; set; } + + private List _daysVisited = new(); + public IReadOnlyList DaysVisited => _daysVisited; + } + + public class PubsAndWalksContext : PubsAndWalksContextBase + { + } + + public class PubsAndWalksContextSqlite : PubsAndWalksContextBase + { + public PubsAndWalksContextSqlite() + : base(useSqlite: true) + { + } + } + + public abstract class PubsAndWalksContextBase : DbContext + { + protected PubsAndWalksContextBase(bool useSqlite = false) + { + UseSqlite = useSqlite; + } + + public bool UseSqlite { get; } + public bool LoggingEnabled { get; set; } + + public DbSet Walks => Set(); + public DbSet Pubs => Set(); + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => (UseSqlite + ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") + : optionsBuilder.UseSqlServer( + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) + //sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseCompatibilityLevel(120))) + .EnableSensitiveDataLogging() + .LogTo( + s => + { + if (LoggingEnabled) + { + Console.WriteLine(s); + } + }, LogLevel.Information); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder + .Entity() + .PrimitiveCollection(e => e.Booleans) + .HasMaxLength(1024) + .IsUnicode(false); + + modelBuilder + .Entity() + .PrimitiveCollection(e => e.Guids) + .HasColumnType("nvarchar(2000)"); + + modelBuilder + .Entity() + .PrimitiveCollection(e => e.GetOnlyInts); + + modelBuilder + .Entity() + .PrimitiveCollection(e => e.DddIds) + .ElementType(b => b.HasConversion()); + + modelBuilder + .Entity() + .Property>("_intsField"); + + modelBuilder.Entity().Property(e => e.Terrain).HasConversion(); + modelBuilder.Entity().PrimitiveCollection(e => e.DaysVisited); + } + + protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) + { + configurationBuilder + .Properties>() + .AreUnicode(false) + .HaveMaxLength(4000); + + configurationBuilder + .Properties() + .HaveMaxLength(2000); + + configurationBuilder + .DefaultTypeMapping() + .HasConversion(); + } + + public async Task Seed() + { + Add( + new PrimitiveCollections + { + Ints = new[] { 1, 2, 3 }, + Strings = new List { "One", "Two", "Three" }, + DateTimes = + new ReadOnlyCollection([new(2023, 1, 1, 1, 1, 1), new(2023, 2, 2, 2, 2, 2), new(2023, 3, 3, 3, 3, 3)]), + Dates = new List { new(2023, 1, 1), new(2023, 2, 2), new(2023, 3, 3) }, + UnsignedInts = new uint[] { 1, 2, 3 }, + Guids = new() { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }, + Booleans = new() { true, false, true }, + Urls = new() { new("https://127.0.0.1/"), new("http://192.168.0.1/"), new("https://devblogs.microsoft.com/dotnet/") }, + SomeInts = new() { 1, 2, 3 }, + DddIds = new() { new(1), new(2), new(3) } + }); + + var oak = new Pub("The Royal Oak", new[] { "Oakham", "Carling", "Guinness", "John Smiths", "Bathams", "Tennents" }); + ((List)oak.DaysVisited).AddRange( + [ + new(2021, 1, 2), + new(2021, 8, 7), + new(2023, 3, 22), + new(2022, 4, 22), + new(2022, 7, 21), + new(2022, 6, 21), + ]); + + var feathers = new Pub("The Prince of Wales Feathers", new[] { "Heineken", "John Smiths", "Stella Artois", "Carlsberg" }); + ((List)feathers.DaysVisited).AddRange( + [ + new(2022, 11, 17), + new(2021, 9, 25), + new(2022, 12, 21), + new(2022, 11, 7), + new(2022, 8, 9), + new(2022, 3, 10), + new(2021, 12, 1), + new(2022, 3, 8), + new(2022, 2, 28), + new(2021, 5, 10), + new(2021, 6, 25), + ]); + + var swan = new Pub( + "The White Swan", new[] { "Oakham", "Carling", "Guinness", "Heineken", "Stella Artois", "Carlsberg", "Bathams" }); + ((List)swan.DaysVisited).AddRange( + [ + new(2021, 2, 24), + new(2022, 8, 3), + new(2022, 9, 14), + new(2022, 5, 5), + new(2022, 7, 13), + new(2021, 7, 18), + new(2021, 7, 23), + ]); + + var fbi = new Pub("Farr Bay Inn", new[] { "Guinness", "Heineken", "Carlsberg", "Bathams", "Tennents" }); + ((List)fbi.DaysVisited).AddRange( + [ + new(2022, 11, 30), + new(2022, 2, 15), + new(2021, 12, 9), + new(2022, 8, 5), + new(2021, 11, 19), + new(2022, 12, 20), + new(2021, 6, 5), + new(2021, 2, 27), + new(2021, 6, 17), + new(2023, 3, 1), + new(2021, 2, 23), + new(2021, 9, 6), + new(2023, 2, 22), + new(2022, 1, 25), + ]); + + var eltisley = new Pub( + "The Eltisley", + new[] { "Oakham", "Carling", "Guinness", "Heineken", "John Smiths", "Stella Artois", "Carlsberg", "Bathams", "Tennents" }); + ((List)eltisley.DaysVisited).AddRange( + [ + new(2022, 6, 19), + new(2021, 1, 15), + new(2022, 3, 24), + new(2023, 2, 26), + new(2021, 1, 11), + new(2022, 3, 19), + ]); + + await AddRangeAsync( + new DogWalk("Ailsworth to Nene") + { + ClosestPub = feathers, + Terrain = Terrain.River, + DaysVisited = new ReadOnlyCollection( + [ + new(2022, 11, 17), + new(2021, 9, 25), + new(2022, 12, 21), + new(2022, 11, 7), + new(2022, 8, 9), + new(2021, 7, 21), + new(2022, 1, 15), + new(2022, 9, 29), + ]) + }, + new DogWalk("Caster Hanglands") + { + ClosestPub = feathers, + Terrain = Terrain.Forest, + DaysVisited = new ReadOnlyCollection( + [ + new(2022, 3, 10), + new(2021, 6, 5), + new(2021, 12, 1), + new(2022, 3, 8), + new(2022, 6, 10), + new(2022, 11, 13), + new(2022, 2, 28), + new(2021, 5, 10), + new(2021, 6, 25), + ]) + }, + new DogWalk("Ferry Meadows") + { + ClosestPub = oak, + Terrain = Terrain.Park, + DaysVisited = new ReadOnlyCollection( + [ + new(2021, 1, 2), + new(2021, 8, 7), + new(2023, 3, 22), + new(2021, 4, 25), + new(2022, 6, 9), + new(2022, 4, 22), + new(2022, 7, 21), + new(2022, 6, 21), + ]) + }, + new DogWalk("Woodnewton") + { + ClosestPub = swan, + Terrain = Terrain.Village, + DaysVisited = new ReadOnlyCollection( + [ + new(2021, 2, 24), + new(2023, 4, 4), + new(2021, 2, 19), + new(2022, 8, 3), + new(2022, 9, 14), + new(2022, 5, 5), + new(2022, 7, 13), + new(2021, 7, 18), + new(2021, 7, 23), + ]) + }, + new DogWalk("Eltisley") + { + ClosestPub = eltisley, + Terrain = Terrain.Village, + DaysVisited = new ReadOnlyCollection( + [ + new(2022, 6, 19), + new(2021, 1, 15), + new(2021, 9, 29), + new(2022, 3, 24), + new(2023, 3, 2), + new(2023, 2, 26), + new(2021, 1, 11), + new(2022, 3, 19), + ]) + }, + new DogWalk("Farr Beach") + { + ClosestPub = fbi, + Terrain = Terrain.Beach, + DaysVisited = new ReadOnlyCollection( + [ + new(2022, 11, 30), + new(2021, 10, 28), + new(2022, 2, 15), + new(2021, 12, 9), + new(2022, 5, 22), + new(2022, 8, 5), + new(2021, 11, 19), + new(2022, 7, 29), + new(2022, 12, 20), + new(2021, 6, 5), + new(2021, 6, 25), + ]) + }, + new DogWalk("Newlands") + { + ClosestPub = fbi, + Terrain = Terrain.Hills, + DaysVisited = new ReadOnlyCollection( + [ + new(2021, 2, 27), + new(2021, 6, 17), + new(2021, 8, 6), + new(2023, 3, 1), + new(2021, 2, 23), + new(2022, 3, 17), + new(2021, 9, 6), + new(2023, 2, 22), + new(2022, 1, 25), + ]) + }); + + await SaveChangesAsync(); + } + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore9/Program.cs b/samples/core/Miscellaneous/NewInEFCore9/Program.cs index 8fa1f3c3da..9f63b9e133 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/Program.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/Program.cs @@ -4,24 +4,29 @@ public class Program { public static async Task Main() { - await QuerySample.Query_improvements_in_EF9(); - await QuerySample.Query_improvements_in_EF9_on_SQLite(); - - // Note that SQL Server 2022 is required for Greater and Least queries. - // await LeastGreatestSample.Queries_using_Least_and_Greatest(); - await LeastGreatestSample.Queries_using_Least_and_Greatest_on_SQLite(); - - await CustomConventionsSample.Conventions_enhancements_in_EF9(); - - await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed(); - await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed_on_SQLite(); - - await ExecuteUpdateSample.ExecuteUpdate_for_complex_type_instances(); - await ExecuteUpdateSample.ExecuteUpdate_for_complex_type_instances_on_SQLite(); - - await HierarchyIdSample.SQL_Server_HierarchyId(); - - await ModelBuildingSample.Model_building_improvements_in_EF9(); - + await PrimitiveCollectionsSample.Queries_using_readonly_primitive_collections(); + await PrimitiveCollectionsSample.Queries_using_readonly_primitive_collections_SQLite(); + + // await ComplexTypesSample.GropupBy_complex_type_instances(); + // await ComplexTypesSample.GropupBy_complex_type_instances_on_SQLite(); + // + // await QuerySample.Query_improvements_in_EF9(); + // await QuerySample.Query_improvements_in_EF9_on_SQLite(); + // + // // Note that SQL Server 2022 is required for Greater and Least queries. + // // await LeastGreatestSample.Queries_using_Least_and_Greatest(); + // await LeastGreatestSample.Queries_using_Least_and_Greatest_on_SQLite(); + // + // await CustomConventionsSample.Conventions_enhancements_in_EF9(); + // + // await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed(); + // await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed_on_SQLite(); + // + // await ExecuteUpdateSample.ExecuteUpdate_for_complex_type_instances(); + // await ExecuteUpdateSample.ExecuteUpdate_for_complex_type_instances_on_SQLite(); + // + // await HierarchyIdSample.SQL_Server_HierarchyId(); + // + // await ModelBuildingSample.Model_building_improvements_in_EF9(); } } diff --git a/samples/core/Miscellaneous/NullableReferenceTypes/NullableReferenceTypesContext.cs b/samples/core/Miscellaneous/NullableReferenceTypes/NullableReferenceTypesContext.cs index b65950a184..d38a0e7461 100644 --- a/samples/core/Miscellaneous/NullableReferenceTypes/NullableReferenceTypesContext.cs +++ b/samples/core/Miscellaneous/NullableReferenceTypes/NullableReferenceTypesContext.cs @@ -11,7 +11,7 @@ public class NullableReferenceTypesContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFNullableReferenceTypes;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFNullableReferenceTypes;Trusted_Connection=True;ConnectRetryCount=0"); } #endregion } diff --git a/samples/core/Modeling/BulkConfiguration/BlogsContext.cs b/samples/core/Modeling/BulkConfiguration/BlogsContext.cs index f64cf6f82c..85a831cf7c 100644 --- a/samples/core/Modeling/BulkConfiguration/BlogsContext.cs +++ b/samples/core/Modeling/BulkConfiguration/BlogsContext.cs @@ -183,7 +183,7 @@ public abstract class BlogsContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => (optionsBuilder.UseSqlServer( - @$"Server=(localdb)\mssqllocaldb;Database=EFModeling.BulkConfiguration.{GetType().Name}")) + @$"Server=(localdb)\mssqllocaldb;Database=EFModeling.BulkConfiguration.{GetType().Name};ConnectRetryCount=0")) .EnableSensitiveDataLogging() .LogTo( s => diff --git a/samples/core/Modeling/BulkConfiguration/CurrencyContext.cs b/samples/core/Modeling/BulkConfiguration/CurrencyContext.cs index c8ed0ed99a..97fe4f3dcb 100644 --- a/samples/core/Modeling/BulkConfiguration/CurrencyContext.cs +++ b/samples/core/Modeling/BulkConfiguration/CurrencyContext.cs @@ -19,7 +19,7 @@ protected override void ConfigureConventions(ModelConfigurationBuilder configura protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFModeling.BulkConfiguration.Currency;Trusted_Connection=True") + @"Server=(localdb)\mssqllocaldb;Database=EFModeling.BulkConfiguration.Currency;Trusted_Connection=True;ConnectRetryCount=0") .LogTo(Console.WriteLine, minimumLevel: Microsoft.Extensions.Logging.LogLevel.Information) .EnableSensitiveDataLogging(); -} \ No newline at end of file +} diff --git a/samples/core/Modeling/BulkConfiguration/MetadataAPIContext.cs b/samples/core/Modeling/BulkConfiguration/MetadataAPIContext.cs index ff09e48e2d..c8f2b87fe2 100644 --- a/samples/core/Modeling/BulkConfiguration/MetadataAPIContext.cs +++ b/samples/core/Modeling/BulkConfiguration/MetadataAPIContext.cs @@ -26,7 +26,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFModeling.BulkConfiguration;Trusted_Connection=True") + @"Server=(localdb)\mssqllocaldb;Database=EFModeling.BulkConfiguration;Trusted_Connection=True;ConnectRetryCount=0") .LogTo(Console.WriteLine, minimumLevel: Microsoft.Extensions.Logging.LogLevel.Information) .EnableSensitiveDataLogging(); -} \ No newline at end of file +} diff --git a/samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs b/samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs index f6ab99d7c0..de9d809485 100644 --- a/samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs +++ b/samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs @@ -273,7 +273,7 @@ public class LaundryContext : DbContext public DbSet LaundryBaskets => Set(); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}"); + => optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0"); #region ReplaceConvention protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) diff --git a/samples/core/Modeling/BulkConfiguration/PreConventionContext.cs b/samples/core/Modeling/BulkConfiguration/PreConventionContext.cs index 96f45459e3..79e6c944da 100644 --- a/samples/core/Modeling/BulkConfiguration/PreConventionContext.cs +++ b/samples/core/Modeling/BulkConfiguration/PreConventionContext.cs @@ -37,7 +37,7 @@ protected override void ConfigureConventions(ModelConfigurationBuilder configura protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFModeling.BulkConfiguration;Trusted_Connection=True") + @"Server=(localdb)\mssqllocaldb;Database=EFModeling.BulkConfiguration;Trusted_Connection=True;ConnectRetryCount=0") .LogTo(Console.WriteLine, minimumLevel: Microsoft.Extensions.Logging.LogLevel.Information) .EnableSensitiveDataLogging(); -} \ No newline at end of file +} diff --git a/samples/core/Modeling/DataSeeding/DataSeedingContext.cs b/samples/core/Modeling/DataSeeding/DataSeedingContext.cs index a8d9104f14..33624e27e0 100644 --- a/samples/core/Modeling/DataSeeding/DataSeedingContext.cs +++ b/samples/core/Modeling/DataSeeding/DataSeedingContext.cs @@ -9,7 +9,7 @@ public class DataSeedingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFDataSeeding;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFDataSeeding;Trusted_Connection=True;ConnectRetryCount=0"); protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -43,4 +43,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) new { PostId = 2, First = "Diego", Last = "Vega" }); #endregion } -} \ No newline at end of file +} diff --git a/samples/core/Modeling/EntityTypes/EntityTypes.cs b/samples/core/Modeling/EntityTypes/EntityTypes.cs index 32d676e9b0..88b8beb154 100644 --- a/samples/core/Modeling/EntityTypes/EntityTypes.cs +++ b/samples/core/Modeling/EntityTypes/EntityTypes.cs @@ -62,6 +62,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFModeling.EntityTypeToFunctionMapping;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFModeling.EntityTypeToFunctionMapping;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Modeling/KeylessEntityTypes/Program.cs b/samples/core/Modeling/KeylessEntityTypes/Program.cs index 8563d0eea2..6a13a2937b 100644 --- a/samples/core/Modeling/KeylessEntityTypes/Program.cs +++ b/samples/core/Modeling/KeylessEntityTypes/Program.cs @@ -101,7 +101,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=Sample.KeylessEntityTypes;Trusted_Connection=True") + @"Server=(localdb)\mssqllocaldb;Database=Sample.KeylessEntityTypes;Trusted_Connection=True;ConnectRetryCount=0") .UseLoggerFactory(_loggerFactory); } diff --git a/samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs b/samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs index de75d9472f..1654f8bee4 100644 --- a/samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs +++ b/samples/core/Modeling/OwnedEntities/OwnedEntityContext.cs @@ -9,7 +9,7 @@ public class OwnedEntityContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFOwnedEntity;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFOwnedEntity;Trusted_Connection=True;ConnectRetryCount=0"); protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -73,4 +73,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) }); #endregion } -} \ No newline at end of file +} diff --git a/samples/core/Modeling/TableSplitting/TableSplittingContext.cs b/samples/core/Modeling/TableSplitting/TableSplittingContext.cs index ec891e91fc..23b2810454 100644 --- a/samples/core/Modeling/TableSplitting/TableSplittingContext.cs +++ b/samples/core/Modeling/TableSplitting/TableSplittingContext.cs @@ -9,7 +9,7 @@ public class TableSplittingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFTableSplitting;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFTableSplitting;Trusted_Connection=True;ConnectRetryCount=0"); protected override void OnModelCreating(ModelBuilder modelBuilder) { diff --git a/samples/core/Modeling/ValueConversions/CaseInsensitiveStrings.cs b/samples/core/Modeling/ValueConversions/CaseInsensitiveStrings.cs index 96a463d786..cd97d29933 100644 --- a/samples/core/Modeling/ValueConversions/CaseInsensitiveStrings.cs +++ b/samples/core/Modeling/ValueConversions/CaseInsensitiveStrings.cs @@ -81,7 +81,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=CaseInsensitiveStrings;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=CaseInsensitiveStrings;Trusted_Connection=True;ConnectRetryCount=0") .EnableSensitiveDataLogging(); } diff --git a/samples/core/Modeling/ValueConversions/EncryptPropertyValues.cs b/samples/core/Modeling/ValueConversions/EncryptPropertyValues.cs index d4874e422a..45eedc1266 100644 --- a/samples/core/Modeling/ValueConversions/EncryptPropertyValues.cs +++ b/samples/core/Modeling/ValueConversions/EncryptPropertyValues.cs @@ -50,7 +50,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EncryptPropertyValues;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EncryptPropertyValues;Trusted_Connection=True;ConnectRetryCount=0") .EnableSensitiveDataLogging(); } @@ -62,4 +62,4 @@ public class User public string Password { get; set; } } #endregion -} \ No newline at end of file +} diff --git a/samples/core/Modeling/ValueConversions/EnumToStringConversions.cs b/samples/core/Modeling/ValueConversions/EnumToStringConversions.cs index 791868a445..efc314f06b 100644 --- a/samples/core/Modeling/ValueConversions/EnumToStringConversions.cs +++ b/samples/core/Modeling/ValueConversions/EnumToStringConversions.cs @@ -296,7 +296,7 @@ public class SampleDbContextBase : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EnumConversions;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EnumConversions;Trusted_Connection=True;ConnectRetryCount=0") .EnableSensitiveDataLogging(); } @@ -331,4 +331,4 @@ public class User public int Id { get; set; } public bool IsActive { get; set; } } -} \ No newline at end of file +} diff --git a/samples/core/Modeling/ValueConversions/FixedLengthStrings.cs b/samples/core/Modeling/ValueConversions/FixedLengthStrings.cs index 19977acfa2..9ec9db2493 100644 --- a/samples/core/Modeling/ValueConversions/FixedLengthStrings.cs +++ b/samples/core/Modeling/ValueConversions/FixedLengthStrings.cs @@ -64,7 +64,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) var converter = new ValueConverter( v => v, v => v.Trim()); - + var comparer = new ValueComparer( (l, r) => string.Equals(l, r, StringComparison.OrdinalIgnoreCase), v => v.ToUpper().GetHashCode(), @@ -87,7 +87,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=FixedLengthStrings;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=FixedLengthStrings;Trusted_Connection=True;ConnectRetryCount=0") .EnableSensitiveDataLogging(); } @@ -110,4 +110,4 @@ public class Post public Blog Blog { get; set; } } #endregion -} \ No newline at end of file +} diff --git a/samples/core/Modeling/ValueConversions/PreserveDateTimeKind.cs b/samples/core/Modeling/ValueConversions/PreserveDateTimeKind.cs index 1902a789f6..9edc93aab4 100644 --- a/samples/core/Modeling/ValueConversions/PreserveDateTimeKind.cs +++ b/samples/core/Modeling/ValueConversions/PreserveDateTimeKind.cs @@ -84,7 +84,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=PreserveDateTimeKind;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=PreserveDateTimeKind;Trusted_Connection=True;ConnectRetryCount=0") .EnableSensitiveDataLogging(); } @@ -101,4 +101,4 @@ public class Post public DateTime DeletedOn { get; set; } } #endregion -} \ No newline at end of file +} diff --git a/samples/core/Modeling/ValueConversions/ULongConcurrency.cs b/samples/core/Modeling/ValueConversions/ULongConcurrency.cs index 83feb2e84e..2eb5717d60 100644 --- a/samples/core/Modeling/ValueConversions/ULongConcurrency.cs +++ b/samples/core/Modeling/ValueConversions/ULongConcurrency.cs @@ -80,7 +80,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ULongConcurrency;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ULongConcurrency;Trusted_Connection=True;ConnectRetryCount=0") .EnableSensitiveDataLogging(); } @@ -92,4 +92,4 @@ public class Blog public ulong Version { get; set; } } #endregion -} \ No newline at end of file +} diff --git a/samples/core/Modeling/ValueConversions/WithMappingHints.cs b/samples/core/Modeling/ValueConversions/WithMappingHints.cs index f10245e97e..9610227ab7 100644 --- a/samples/core/Modeling/ValueConversions/WithMappingHints.cs +++ b/samples/core/Modeling/ValueConversions/WithMappingHints.cs @@ -63,7 +63,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted }) - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=WithMappingHints;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=WithMappingHints;Trusted_Connection=True;ConnectRetryCount=0") .EnableSensitiveDataLogging(); } @@ -86,4 +86,4 @@ public readonly struct Dollars public Dollars(decimal amount) => Amount = amount; public decimal Amount { get; } } -} \ No newline at end of file +} diff --git a/samples/core/Performance/Other/BloggingContext.cs b/samples/core/Performance/Other/BloggingContext.cs index 4543205969..c2318d6276 100644 --- a/samples/core/Performance/Other/BloggingContext.cs +++ b/samples/core/Performance/Other/BloggingContext.cs @@ -14,7 +14,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information); } #endregion diff --git a/samples/core/Performance/Other/EmployeeContext.cs b/samples/core/Performance/Other/EmployeeContext.cs index 15213f6590..caa2e481eb 100644 --- a/samples/core/Performance/Other/EmployeeContext.cs +++ b/samples/core/Performance/Other/EmployeeContext.cs @@ -11,7 +11,7 @@ public class EmployeeContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information); } } @@ -21,4 +21,4 @@ public class Employee public int Id { get; set; } public string Name { get; set; } public int Salary { get; set; } -} \ No newline at end of file +} diff --git a/samples/core/Performance/Other/ExtensionsLoggingContext.cs b/samples/core/Performance/Other/ExtensionsLoggingContext.cs index 82348470b0..60f6e2602f 100644 --- a/samples/core/Performance/Other/ExtensionsLoggingContext.cs +++ b/samples/core/Performance/Other/ExtensionsLoggingContext.cs @@ -12,8 +12,8 @@ private static ILoggerFactory ContextLoggerFactory protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .UseLoggerFactory(ContextLoggerFactory); } #endregion -} \ No newline at end of file +} diff --git a/samples/core/Performance/Other/LazyLoading/LazyBloggingContext.cs b/samples/core/Performance/Other/LazyLoading/LazyBloggingContext.cs index 2feb273536..3514e0cc9b 100644 --- a/samples/core/Performance/Other/LazyLoading/LazyBloggingContext.cs +++ b/samples/core/Performance/Other/LazyLoading/LazyBloggingContext.cs @@ -12,7 +12,7 @@ public class LazyBloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information) .UseLazyLoadingProxies(); } @@ -33,4 +33,4 @@ public class Post public int BlogId { get; set; } public virtual Blog Blog { get; set; } -} \ No newline at end of file +} diff --git a/samples/core/Performance/Other/Program.cs b/samples/core/Performance/Other/Program.cs index f5097b6be7..f53ed94b44 100644 --- a/samples/core/Performance/Other/Program.cs +++ b/samples/core/Performance/Other/Program.cs @@ -214,7 +214,7 @@ private static async Task Main(string[] args) using (var context = new PooledBloggingContext( new DbContextOptionsBuilder() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .Options)) { context.Database.EnsureDeleted(); @@ -223,7 +223,7 @@ private static async Task Main(string[] args) #region DbContextPoolingWithoutDI var options = new DbContextOptionsBuilder() - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .Options; var factory = new PooledDbContextFactory(options); @@ -244,4 +244,4 @@ private static async Task Main(string[] args) #endregion } } -} \ No newline at end of file +} diff --git a/samples/core/Querying/ClientEvaluation/BloggingContext.cs b/samples/core/Querying/ClientEvaluation/BloggingContext.cs index e8bbaf6f75..a30e355c17 100644 --- a/samples/core/Querying/ClientEvaluation/BloggingContext.cs +++ b/samples/core/Querying/ClientEvaluation/BloggingContext.cs @@ -17,6 +17,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.ClientEvaluation;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.ClientEvaluation;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/ComplexQuery/BloggingContext.cs b/samples/core/Querying/ComplexQuery/BloggingContext.cs index 397e861967..9637383ef3 100644 --- a/samples/core/Querying/ComplexQuery/BloggingContext.cs +++ b/samples/core/Querying/ComplexQuery/BloggingContext.cs @@ -103,6 +103,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.ComplexQuery;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.ComplexQuery;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/NullSemantics/NullSemanticsContext.cs b/samples/core/Querying/NullSemantics/NullSemanticsContext.cs index e2fc5ad25c..76c04fc54e 100644 --- a/samples/core/Querying/NullSemantics/NullSemanticsContext.cs +++ b/samples/core/Querying/NullSemantics/NullSemanticsContext.cs @@ -18,7 +18,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) } optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=NullSemanticsSample;Trusted_Connection=True;MultipleActiveResultSets=true"); + @"Server=(localdb)\mssqllocaldb;Database=NullSemanticsSample;Trusted_Connection=True;MultipleActiveResultSets=true;ConnectRetryCount=0"); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -65,4 +65,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) String2 = null }); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/Overview/BloggingContext.cs b/samples/core/Querying/Overview/BloggingContext.cs index 28e257912c..849e8b9e3f 100644 --- a/samples/core/Querying/Overview/BloggingContext.cs +++ b/samples/core/Querying/Overview/BloggingContext.cs @@ -17,6 +17,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Overview;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Overview;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/Pagination/BloggingContext.cs b/samples/core/Querying/Pagination/BloggingContext.cs index cf7a2c86d0..b154ede4e8 100644 --- a/samples/core/Querying/Pagination/BloggingContext.cs +++ b/samples/core/Querying/Pagination/BloggingContext.cs @@ -14,7 +14,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;ConnectRetryCount=0") .LogTo(Console.WriteLine, LogLevel.Information); } #endregion @@ -42,4 +42,4 @@ public class Post public int BlogId { get; set; } public Blog Blog { get; set; } -} \ No newline at end of file +} diff --git a/samples/core/Querying/QueryFilters/AnimalContext.cs b/samples/core/Querying/QueryFilters/AnimalContext.cs index f5b6f0fb07..7612ba09fc 100644 --- a/samples/core/Querying/QueryFilters/AnimalContext.cs +++ b/samples/core/Querying/QueryFilters/AnimalContext.cs @@ -12,7 +12,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=Querying.QueryFilters.Animals;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=Querying.QueryFilters.Animals;Trusted_Connection=True;ConnectRetryCount=0"); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -27,4 +27,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) // Invalid query filter configuration as it causes cycles in query filters //modelBuilder.Entity().HasQueryFilter(a => a.Owner.Name != "John"); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/QueryFilters/BloggingContext.cs b/samples/core/Querying/QueryFilters/BloggingContext.cs index ca54251483..60d8ed7121 100644 --- a/samples/core/Querying/QueryFilters/BloggingContext.cs +++ b/samples/core/Querying/QueryFilters/BloggingContext.cs @@ -19,7 +19,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=Querying.QueryFilters.Blogging;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=Querying.QueryFilters.Blogging;Trusted_Connection=True;ConnectRetryCount=0"); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -52,4 +52,4 @@ public override int SaveChanges() return base.SaveChanges(); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/QueryFilters/FilteredBloggingContextRequired.cs b/samples/core/Querying/QueryFilters/FilteredBloggingContextRequired.cs index 2cac7cc0fe..d9a4ad1a64 100644 --- a/samples/core/Querying/QueryFilters/FilteredBloggingContextRequired.cs +++ b/samples/core/Querying/QueryFilters/FilteredBloggingContextRequired.cs @@ -11,7 +11,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=Querying.QueryFilters.BloggingRequired;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=Querying.QueryFilters.BloggingRequired;Trusted_Connection=True;ConnectRetryCount=0"); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -53,4 +53,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) #endregion } } -} \ No newline at end of file +} diff --git a/samples/core/Querying/RelatedData/BloggingContext.cs b/samples/core/Querying/RelatedData/BloggingContext.cs index 9eb800f7e0..5644a1a007 100644 --- a/samples/core/Querying/RelatedData/BloggingContext.cs +++ b/samples/core/Querying/RelatedData/BloggingContext.cs @@ -122,6 +122,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.ComplexQuery;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.ComplexQuery;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/RelatedData/SplitQueriesBloggingContext.cs b/samples/core/Querying/RelatedData/SplitQueriesBloggingContext.cs index b1c55acafe..769d83edf4 100644 --- a/samples/core/Querying/RelatedData/SplitQueriesBloggingContext.cs +++ b/samples/core/Querying/RelatedData/SplitQueriesBloggingContext.cs @@ -9,8 +9,8 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True", + @"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;ConnectRetryCount=0", o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)); } #endregion -} \ No newline at end of file +} diff --git a/samples/core/Querying/SqlQueries/BloggingContext.cs b/samples/core/Querying/SqlQueries/BloggingContext.cs index fc3ed832cb..0251c3525d 100644 --- a/samples/core/Querying/SqlQueries/BloggingContext.cs +++ b/samples/core/Querying/SqlQueries/BloggingContext.cs @@ -52,6 +52,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.RawSQL;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.RawSQL;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/Tags/SpatialContext.cs b/samples/core/Querying/Tags/SpatialContext.cs index 65f4085f94..89b4128915 100644 --- a/samples/core/Querying/Tags/SpatialContext.cs +++ b/samples/core/Querying/Tags/SpatialContext.cs @@ -24,7 +24,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tags;Trusted_Connection=True", + @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tags;Trusted_Connection=True;ConnectRetryCount=0", b => b.UseNetTopologySuite()); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/Tracking/BloggingContext.cs b/samples/core/Querying/Tracking/BloggingContext.cs index 7355fc9e65..a3234e42b7 100644 --- a/samples/core/Querying/Tracking/BloggingContext.cs +++ b/samples/core/Querying/Tracking/BloggingContext.cs @@ -17,6 +17,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tracking;Trusted_Connection=True"); + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tracking;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Querying/Tracking/NonTrackingBloggingContext.cs b/samples/core/Querying/Tracking/NonTrackingBloggingContext.cs index 27cb4b9e36..2690db12e5 100644 --- a/samples/core/Querying/Tracking/NonTrackingBloggingContext.cs +++ b/samples/core/Querying/Tracking/NonTrackingBloggingContext.cs @@ -18,8 +18,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder - .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tracking;Trusted_Connection=True") + .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying.Tracking;Trusted_Connection=True;ConnectRetryCount=0") .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); } #endregion -} \ No newline at end of file +} diff --git a/samples/core/Querying/UserDefinedFunctionMapping/Model.cs b/samples/core/Querying/UserDefinedFunctionMapping/Model.cs index 245c7d782d..188df7d56a 100644 --- a/samples/core/Querying/UserDefinedFunctionMapping/Model.cs +++ b/samples/core/Querying/UserDefinedFunctionMapping/Model.cs @@ -214,6 +214,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.UserDefinedFunctionMapping;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFQuerying.UserDefinedFunctionMapping;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Samples.sln b/samples/core/Samples.sln index 13b6ced270..3bbd6d00f9 100644 --- a/samples/core/Samples.sln +++ b/samples/core/Samples.sln @@ -203,6 +203,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "Miscellaneous\NewInE EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Miscellaneous\NewInEFCore9.CompiledModels\Model\Model.csproj", "{8E9DD759-B6D0-4424-BC6C-97ECE559CE02}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NewInEFCore9.Cosmos", "Miscellaneous\NewInEFCore9.Cosmos\NewInEFCore9.Cosmos.csproj", "{C636065F-C124-4051-90DA-3EA2A0817471}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -561,6 +563,10 @@ Global {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 + {C636065F-C124-4051-90DA-3EA2A0817471}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C636065F-C124-4051-90DA-3EA2A0817471}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C636065F-C124-4051-90DA-3EA2A0817471}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C636065F-C124-4051-90DA-3EA2A0817471}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -650,6 +656,7 @@ Global {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} + {C636065F-C124-4051-90DA-3EA2A0817471} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {20C98D35-54EF-46A6-8F3B-1855C1AE4F70} diff --git a/samples/core/Saving/Basics/BloggingContext.cs b/samples/core/Saving/Basics/BloggingContext.cs index 535855059c..d2d005449a 100644 --- a/samples/core/Saving/Basics/BloggingContext.cs +++ b/samples/core/Saving/Basics/BloggingContext.cs @@ -10,6 +10,6 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Basics;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Basics;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Saving/CascadeDelete/BloggingContext.cs b/samples/core/Saving/CascadeDelete/BloggingContext.cs index 94256d62dc..2c128250e9 100644 --- a/samples/core/Saving/CascadeDelete/BloggingContext.cs +++ b/samples/core/Saving/CascadeDelete/BloggingContext.cs @@ -32,7 +32,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) .ReplaceService() .EnableSensitiveDataLogging() .UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.CascadeDelete;Trusted_Connection=True", + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.CascadeDelete;Trusted_Connection=True;ConnectRetryCount=0", b => b.MaxBatchSize(1)); protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -110,4 +110,4 @@ public void Log( public IDisposable BeginScope(TState state) => null; } } -} \ No newline at end of file +} diff --git a/samples/core/Saving/Concurrency/BasicSample.cs b/samples/core/Saving/Concurrency/BasicSample.cs index 12574e3d08..933530b175 100644 --- a/samples/core/Saving/Concurrency/BasicSample.cs +++ b/samples/core/Saving/Concurrency/BasicSample.cs @@ -67,7 +67,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // Requires NuGet package Microsoft.EntityFrameworkCore.SqlServer optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True;ConnectRetryCount=0"); } } diff --git a/samples/core/Saving/Concurrency/ConflictResolutionSample.cs b/samples/core/Saving/Concurrency/ConflictResolutionSample.cs index b78870e2e9..4e6b1c8850 100644 --- a/samples/core/Saving/Concurrency/ConflictResolutionSample.cs +++ b/samples/core/Saving/Concurrency/ConflictResolutionSample.cs @@ -79,7 +79,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // Requires NuGet package Microsoft.EntityFrameworkCore.SqlServer optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True;ConnectRetryCount=0"); } } diff --git a/samples/core/Saving/Disconnected/BloggingContext.cs b/samples/core/Saving/Disconnected/BloggingContext.cs index d61f01d111..41f30b9b59 100644 --- a/samples/core/Saving/Disconnected/BloggingContext.cs +++ b/samples/core/Saving/Disconnected/BloggingContext.cs @@ -10,6 +10,6 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Disconnected;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Disconnected;Trusted_Connection=True;ConnectRetryCount=0"); } -} \ No newline at end of file +} diff --git a/samples/core/Saving/RelatedData/Sample.cs b/samples/core/Saving/RelatedData/Sample.cs index 820f74e82d..1ad2df56b1 100644 --- a/samples/core/Saving/RelatedData/Sample.cs +++ b/samples/core/Saving/RelatedData/Sample.cs @@ -75,7 +75,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.RelatedData;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.RelatedData;Trusted_Connection=True;ConnectRetryCount=0"); } } @@ -96,4 +96,4 @@ public class Post public int BlogId { get; set; } public Blog Blog { get; set; } } -} \ No newline at end of file +} diff --git a/samples/core/Saving/Transactions/AmbientTransaction.cs b/samples/core/Saving/Transactions/AmbientTransaction.cs index 4ff410c99a..b5ef4100be 100644 --- a/samples/core/Saving/Transactions/AmbientTransaction.cs +++ b/samples/core/Saving/Transactions/AmbientTransaction.cs @@ -10,7 +10,7 @@ public class AmbientTransaction public static void Run() { var connectionString = - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True"; + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True;ConnectRetryCount=0"; using (var context = new BloggingContext( new DbContextOptionsBuilder() @@ -74,4 +74,4 @@ public class Blog public int BlogId { get; set; } public string Url { get; set; } } -} \ No newline at end of file +} diff --git a/samples/core/Saving/Transactions/CommitableTransaction.cs b/samples/core/Saving/Transactions/CommitableTransaction.cs index 9cd2e39ef1..d68e285fd8 100644 --- a/samples/core/Saving/Transactions/CommitableTransaction.cs +++ b/samples/core/Saving/Transactions/CommitableTransaction.cs @@ -10,7 +10,7 @@ public class CommitableTransaction public static void Run() { var connectionString = - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True"; + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True;ConnectRetryCount=0"; using (var context = new BloggingContext( new DbContextOptionsBuilder() @@ -76,4 +76,4 @@ public class Blog public int BlogId { get; set; } public string Url { get; set; } } -} \ No newline at end of file +} diff --git a/samples/core/Saving/Transactions/ControllingTransaction.cs b/samples/core/Saving/Transactions/ControllingTransaction.cs index 267fb9bd11..363c66346d 100644 --- a/samples/core/Saving/Transactions/ControllingTransaction.cs +++ b/samples/core/Saving/Transactions/ControllingTransaction.cs @@ -48,7 +48,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True;ConnectRetryCount=0"); } } @@ -57,4 +57,4 @@ public class Blog public int BlogId { get; set; } public string Url { get; set; } } -} \ No newline at end of file +} diff --git a/samples/core/Saving/Transactions/ExternalDbTransaction.cs b/samples/core/Saving/Transactions/ExternalDbTransaction.cs index df7da8a663..62fe8a4aa2 100644 --- a/samples/core/Saving/Transactions/ExternalDbTransaction.cs +++ b/samples/core/Saving/Transactions/ExternalDbTransaction.cs @@ -9,7 +9,7 @@ public class ExternalDbTransaction public static void Run() { var connectionString = - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True"; + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True;ConnectRetryCount=0"; using (var context = new BloggingContext( new DbContextOptionsBuilder() @@ -71,4 +71,4 @@ public class Blog public int BlogId { get; set; } public string Url { get; set; } } -} \ No newline at end of file +} diff --git a/samples/core/Saving/Transactions/ManagingSavepoints.cs b/samples/core/Saving/Transactions/ManagingSavepoints.cs index 38df73d7ba..20d8e47974 100644 --- a/samples/core/Saving/Transactions/ManagingSavepoints.cs +++ b/samples/core/Saving/Transactions/ManagingSavepoints.cs @@ -47,7 +47,7 @@ public class BloggingContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True;ConnectRetryCount=0"); } } @@ -56,4 +56,4 @@ public class Blog public int BlogId { get; set; } public string Url { get; set; } } -} \ No newline at end of file +} diff --git a/samples/core/Saving/Transactions/SharingTransaction.cs b/samples/core/Saving/Transactions/SharingTransaction.cs index d841b106c4..ae680054e4 100644 --- a/samples/core/Saving/Transactions/SharingTransaction.cs +++ b/samples/core/Saving/Transactions/SharingTransaction.cs @@ -11,7 +11,7 @@ public class SharingTransaction public static void Run() { var connectionString = - @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True"; + @"Server=(localdb)\mssqllocaldb;Database=EFSaving.Transactions;Trusted_Connection=True;ConnectRetryCount=0"; using (var context = new BloggingContext( new DbContextOptionsBuilder() @@ -42,7 +42,7 @@ public static void Run() var blogs = context2.Blogs .OrderBy(b => b.Url) .ToList(); - + context2.Blogs.Add(new Blog { Url = "http://dot.net/" }); context2.SaveChanges(); } diff --git a/samples/core/Schemas/Migrations/CustomOperation.cs b/samples/core/Schemas/Migrations/CustomOperation.cs index 4e5a6b4517..afa709dea2 100644 --- a/samples/core/Schemas/Migrations/CustomOperation.cs +++ b/samples/core/Schemas/Migrations/CustomOperation.cs @@ -74,7 +74,7 @@ private void Generate( internal class CustomOperationContext : DbContext { - private readonly string _connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Sample"; + private readonly string _connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Sample;ConnectRetryCount=0"; #region snippet_OnConfiguring protected override void OnConfiguring(DbContextOptionsBuilder options) diff --git a/samples/core/Schemas/Migrations/MigrationTableNameContext.cs b/samples/core/Schemas/Migrations/MigrationTableNameContext.cs index 1124346a58..8d0d343d78 100644 --- a/samples/core/Schemas/Migrations/MigrationTableNameContext.cs +++ b/samples/core/Schemas/Migrations/MigrationTableNameContext.cs @@ -4,7 +4,7 @@ namespace Migrations; public class MigrationTableNameContext : DbContext { - private readonly string _connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Sample"; + private readonly string _connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Sample;ConnectRetryCount=0"; #region TableNameContext protected override void OnConfiguring(DbContextOptionsBuilder options) @@ -12,4 +12,4 @@ protected override void OnConfiguring(DbContextOptionsBuilder options) _connectionString, x => x.MigrationsHistoryTable("__MyMigrationsHistory", "mySchema")); #endregion -} \ No newline at end of file +} diff --git a/samples/core/Schemas/Migrations/MyHistoryRepository.cs b/samples/core/Schemas/Migrations/MyHistoryRepository.cs index 55f3e1c7f7..a5b7413115 100644 --- a/samples/core/Schemas/Migrations/MyHistoryRepository.cs +++ b/samples/core/Schemas/Migrations/MyHistoryRepository.cs @@ -9,7 +9,7 @@ namespace Migrations; public class MyHistoryRepositoryContext : DbContext { - private readonly string _connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Sample"; + private readonly string _connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Sample;ConnectRetryCount=0"; #region HistoryRepositoryContext protected override void OnConfiguring(DbContextOptionsBuilder options) @@ -34,4 +34,4 @@ protected override void ConfigureTable(EntityTypeBuilder history) history.Property(h => h.MigrationId).HasColumnName("Id"); } } -#endregion \ No newline at end of file +#endregion diff --git a/samples/core/Spatial/SqlServer/Models/WideWorldImportersContext.cs b/samples/core/Spatial/SqlServer/Models/WideWorldImportersContext.cs index 6180a81ac6..ece5a8ddfd 100644 --- a/samples/core/Spatial/SqlServer/Models/WideWorldImportersContext.cs +++ b/samples/core/Spatial/SqlServer/Models/WideWorldImportersContext.cs @@ -13,7 +13,7 @@ internal class WideWorldImportersContext : DbContext protected override void OnConfiguring(DbContextOptionsBuilder options) => #region snippet_UseNetTopologySuite options.UseSqlServer( - @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=WideWorldImporters", + @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=WideWorldImporters;ConnectRetryCount=0", x => x.UseNetTopologySuite()); #endregion -} \ No newline at end of file +} diff --git a/samples/core/Testing/BloggingWebApi/Startup.cs b/samples/core/Testing/BloggingWebApi/Startup.cs index 617faedb9f..85dd5fd101 100644 --- a/samples/core/Testing/BloggingWebApi/Startup.cs +++ b/samples/core/Testing/BloggingWebApi/Startup.cs @@ -23,7 +23,7 @@ public void ConfigureServices(IServiceCollection services) services.AddDbContext( b => b.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFTestSample;Trusted_Connection=True")); + @"Server=(localdb)\mssqllocaldb;Database=EFTestSample;Trusted_Connection=True;ConnectRetryCount=0")); #region RegisterRepositoryInDI services.AddScoped(); @@ -42,4 +42,4 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } -} \ No newline at end of file +} diff --git a/samples/core/Testing/BusinessLogic/BloggingContext.cs b/samples/core/Testing/BusinessLogic/BloggingContext.cs index 71649a16e6..be93d0a4cc 100644 --- a/samples/core/Testing/BusinessLogic/BloggingContext.cs +++ b/samples/core/Testing/BusinessLogic/BloggingContext.cs @@ -28,7 +28,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) if (!optionsBuilder.IsConfigured) { optionsBuilder.UseSqlServer( - @"Server=(localdb)\mssqllocaldb;Database=EFProviders.InMemory;Trusted_Connection=True"); + @"Server=(localdb)\mssqllocaldb;Database=EFProviders.InMemory;Trusted_Connection=True;ConnectRetryCount=0"); } } #endregion @@ -43,4 +43,4 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) _modelCustomizer(this, modelBuilder); } } -} \ No newline at end of file +} diff --git a/samples/core/Testing/TestingWithTheDatabase/TestDatabaseFixture.cs b/samples/core/Testing/TestingWithTheDatabase/TestDatabaseFixture.cs index 843c6700d7..7b396bc1f8 100644 --- a/samples/core/Testing/TestingWithTheDatabase/TestDatabaseFixture.cs +++ b/samples/core/Testing/TestingWithTheDatabase/TestDatabaseFixture.cs @@ -6,7 +6,7 @@ namespace EF.Testing.IntegrationTests; #region TestDatabaseFixture public class TestDatabaseFixture { - private const string ConnectionString = @"Server=(localdb)\mssqllocaldb;Database=EFTestSample;Trusted_Connection=True"; + private const string ConnectionString = @"Server=(localdb)\mssqllocaldb;Database=EFTestSample;Trusted_Connection=True;ConnectRetryCount=0"; private static readonly object _lock = new(); private static bool _databaseInitialized; @@ -39,4 +39,4 @@ public BloggingContext CreateContext() .UseSqlServer(ConnectionString) .Options); } -#endregion \ No newline at end of file +#endregion diff --git a/samples/core/Testing/TestingWithTheDatabase/TransactionalTestDatabaseFixture.cs b/samples/core/Testing/TestingWithTheDatabase/TransactionalTestDatabaseFixture.cs index 2f26f78d4f..0dba2699a7 100644 --- a/samples/core/Testing/TestingWithTheDatabase/TransactionalTestDatabaseFixture.cs +++ b/samples/core/Testing/TestingWithTheDatabase/TransactionalTestDatabaseFixture.cs @@ -7,7 +7,7 @@ namespace EF.Testing.IntegrationTests; #region TransactionalTestDatabaseFixture public class TransactionalTestDatabaseFixture { - private const string ConnectionString = @"Server=(localdb)\mssqllocaldb;Database=EFTransactionalTestSample;Trusted_Connection=True"; + private const string ConnectionString = @"Server=(localdb)\mssqllocaldb;Database=EFTransactionalTestSample;Trusted_Connection=True;ConnectRetryCount=0"; public BloggingContext CreateContext() => new BloggingContext( @@ -45,4 +45,4 @@ public void Cleanup() public class TransactionalTestsCollection : ICollectionFixture { } -#endregion \ No newline at end of file +#endregion From 09e47ec9d2c160c9ee4f1fdc10754f2ab3665fbf Mon Sep 17 00:00:00 2001 From: BillyCool Date: Tue, 14 May 2024 00:54:47 +1000 Subject: [PATCH 004/224] Fixed typo in whatsnew.md (#4722) --- entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 dcc6d1d574..e6926d5cec 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 @@ -207,7 +207,7 @@ WHERE ( Several new translations have been introduced that use the `GREATEST` and `LEAST` SQL functions. > [!IMPORTANT] -> The `GREATEST` and `LEAST` functions wre [introduced to SQL Server/Azure SQL databases in the 2022 version](https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-the-greatest-and-least-t-sql-functions/ba-p/2281726). Visual Studio 2022 installs SQL Server 2019 by default. We recommend installing [SQL Server Developer Edition 2022](https://www.microsoft.com/sql-server/sql-server-downloads) to try out these new translations in EF9. +> The `GREATEST` and `LEAST` functions were [introduced to SQL Server/Azure SQL databases in the 2022 version](https://techcommunity.microsoft.com/t5/azure-sql-blog/introducing-the-greatest-and-least-t-sql-functions/ba-p/2281726). Visual Studio 2022 installs SQL Server 2019 by default. We recommend installing [SQL Server Developer Edition 2022](https://www.microsoft.com/sql-server/sql-server-downloads) to try out these new translations in EF9. For example, queries using `Math.Max` or `Math.Min` are now translated for Azure SQL using `GREATEST` and `LEAST` respectively. For example: From d4ccf3a8eac019bc2196638adfee56bbfb2b6d1e Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Tue, 14 May 2024 05:19:40 -0700 Subject: [PATCH 005/224] Community standup and mark EF7 as out-of-support (#4723) --- .../core/learn-more/community-standups.md | 25 +++++++++++++++++++ entity-framework/core/what-is-new/index.md | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/entity-framework/core/learn-more/community-standups.md b/entity-framework/core/learn-more/community-standups.md index ae8126945b..15ddb0517c 100644 --- a/entity-framework/core/learn-more/community-standups.md +++ b/entity-framework/core/learn-more/community-standups.md @@ -16,6 +16,7 @@ The .NET Data Community Standups are live-streamed every other Wednesday to Twit | Date | Area | Title | |--------------|-----------------------|----------------------------------------------------------------------------------------| +| May 15, 2024 | Firebird | [Harnessing the Power of Firebird in .NET](#May15_2024) | | Apr 17, 2024 | EF Core mapping | [All about EF Core property mapping](#Apr17_2024) | | Mar 20, 2024 | GraphQL | [Distributed Applications with Hot Chocolate 14, Aspire, and EF Core](#Mar20_2024) | | Mar 6, 2024 | Value generation | [EF Core keys and value generation](#value-generation) | @@ -96,6 +97,30 @@ The .NET Data Community Standups are live-streamed every other Wednesday to Twit ## 2024 + + +### May 15: [Harnessing the Power of Firebird in .NET](https://www.youtube.com/live/ouGIWUtzxRQ?si=qtZ1xqKjKe_E1MhI) + +In this community talk, we delve into the integration of Firebird, an open-source SQL relational database management system, with .NET, a free, cross-platform, open-source developer platform. This session aims to provide an understanding of how these two powerful technologies can be combined to create robust, scalable, and efficient applications. + +This talk is designed for developers of all levels interested in expanding their knowledge on database management and .NET development. Whether you're a seasoned developer or a beginner looking to broaden your skill set, this talk will provide valuable insights into the effective use of Firebird with .NET. + +Join us for this enlightening session and discover how you can harness the power of Firebird in .NET to take your applications to the next level. + +Featuring: + +- [Jiri Cincura](https://github.com/cincuranet) (Host) +- [Arthur Vickers](https://github.com/ajcvickers) (Host) +- [Shay Rojansky](https://github.com/roji) (Host) + +Links: + +- Product: [Firebird](https://firebirdsql.org/) +- NuGet: [FirebirdSql.Data.FirebirdClient](https://www.nuget.org/packages/FirebirdSql.Data.FirebirdClient) +- Blog: [FbNetExternalEngine](https://www.tabsoverspaces.com/tools/fb-net-external-engine) +- Docs: [What's new in EF9, with runnable samples](https://aka.ms/ef9-new) +- Docs: [EF Core daily builds](https://aka.ms/ef-daily-builds) + ### Apr 17: [All about EF Core property mapping](https://www.youtube.com/live/ouGIWUtzxRQ?si=qtZ1xqKjKe_E1MhI) diff --git a/entity-framework/core/what-is-new/index.md b/entity-framework/core/what-is-new/index.md index 913eab0c7c..1230ee5b85 100644 --- a/entity-framework/core/what-is-new/index.md +++ b/entity-framework/core/what-is-new/index.md @@ -13,7 +13,7 @@ uid: core/what-is-new/index | Release | Target framework | Supported until | Links | |----------------------------------------------------------------------------------------|-------------------|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [EF Core 8.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) | .NET 8 | November 10, 2026 | [What's new](xref:core/what-is-new/ef-core-8.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-8.0/breaking-changes) | -| [EF Core 7.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/7.0.0) | .NET 6 | May 14, 2024 | [What's new](xref:core/what-is-new/ef-core-7.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-7.0/breaking-changes) | +| ~~[EF Core 7.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/7.0.0)~~ | .NET 6 | Expired May 14, 2024 | [What's new](xref:core/what-is-new/ef-core-7.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-7.0/breaking-changes) | | [EF Core 6.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/6.0.0) | .NET 6 | November 12, 2024 (LTS) | [What's new](xref:core/what-is-new/ef-core-6.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-6.0/breaking-changes) | | ~~[EF Core 5.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/5.0.17)~~ | .NET Standard 2.1 | Expired May 10, 2022 | [Announcement](https://devblogs.microsoft.com/dotnet/announcing-the-release-of-ef-core-5-0/) / [Breaking changes](xref:core/what-is-new/ef-core-5.0/breaking-changes) | | ~~[EF Core 3.1](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/3.1.31)~~ | .NET Standard 2.0 | Expired December 13, 2022 | [Announcement](https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-3-1-and-entity-framework-6-4/) | From c12040fbc965800f7ed2282ba34d6255e56a6b90 Mon Sep 17 00:00:00 2001 From: Qwertyluk <64921645+Qwertyluk@users.noreply.github.com> Date: Tue, 14 May 2024 22:44:52 +0200 Subject: [PATCH 006/224] Update concurrency.md (#4724) --- entity-framework/core/saving/concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/saving/concurrency.md b/entity-framework/core/saving/concurrency.md index 84642f2697..57b7b0949f 100644 --- a/entity-framework/core/saving/concurrency.md +++ b/entity-framework/core/saving/concurrency.md @@ -163,7 +163,7 @@ Optimistic concurrency via concurrency tokens isn't the only way to ensure that One mechanism to ensure consistency is the *repeatable reads* transaction isolation level. In most databases, this level guarantees that a transaction sees data in the database as it was when the transaction started, without being affected by any subsequent concurrent activity. Taking our basic sample from above, when we query for the `Person` in order to update it in some way, the database must make sure no other transactions interfere with that database row until the transaction completes. Depending on your database implementation, this happens in one of two ways: 1. When the row is queried, your transaction takes a shared lock on it. Any external transaction attempting to update the row will block until your transaction completes. This is a form of pessimistic locking, and is implemented by the SQL Server "repeatable read" isolation level. -2. Rather than locking, the database allows the external transaction to update the row, but when your own transaction attempts to do the update it, a "serialization" error will be raised, indicating that a concurrency conflict occurred. This is a form of optimistic locking - not unlike EF's concurrency token feature - and is implemented by the SQL Server snapshot isolation level, as well as by the PostgreSQL repeatable reads isolation level. +2. Rather than locking, the database allows the external transaction to update the row, but when your own transaction attempts to do the update, a "serialization" error will be raised, indicating that a concurrency conflict occurred. This is a form of optimistic locking - not unlike EF's concurrency token feature - and is implemented by the SQL Server snapshot isolation level, as well as by the PostgreSQL repeatable reads isolation level. Note that the "serializable" isolation level provides the same guarantees as repeatable read (and adds additional ones), so it functions in the same way with respect to the above. From d136cf51db92a3f016f972985beb9fc311e83dba Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Thu, 16 May 2024 02:20:56 -0700 Subject: [PATCH 007/224] Add Database.NET tool used in stream. (#4728) --- entity-framework/core/learn-more/community-standups.md | 1 + 1 file changed, 1 insertion(+) diff --git a/entity-framework/core/learn-more/community-standups.md b/entity-framework/core/learn-more/community-standups.md index 15ddb0517c..4d0775ef2a 100644 --- a/entity-framework/core/learn-more/community-standups.md +++ b/entity-framework/core/learn-more/community-standups.md @@ -118,6 +118,7 @@ Links: - Product: [Firebird](https://firebirdsql.org/) - NuGet: [FirebirdSql.Data.FirebirdClient](https://www.nuget.org/packages/FirebirdSql.Data.FirebirdClient) - Blog: [FbNetExternalEngine](https://www.tabsoverspaces.com/tools/fb-net-external-engine) +- Tool used in the stream: [Database.NET](https://fishcodelib.com/database.htm) - Docs: [What's new in EF9, with runnable samples](https://aka.ms/ef9-new) - Docs: [EF Core daily builds](https://aka.ms/ef-daily-builds) From 1fb2b1ca07d3ab05c5abf01c08533cb51a72472a Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Fri, 17 May 2024 18:48:27 +0200 Subject: [PATCH 008/224] Update what's new for 6.5 (#4730) part of dotnet/ef6#2237 --- entity-framework/ef6/what-is-new/index.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/entity-framework/ef6/what-is-new/index.md b/entity-framework/ef6/what-is-new/index.md index b8fab6af32..5e22864a10 100644 --- a/entity-framework/ef6/what-is-new/index.md +++ b/entity-framework/ef6/what-is-new/index.md @@ -2,7 +2,7 @@ title: What's new - EF6 description: What's new in Entity Framework 6 author: ajcvickers -ms.date: 09/12/2019 +ms.date: 05/17/2024 uid: ef6/what-is-new/index --- # What's new in EF6 @@ -11,9 +11,17 @@ We highly recommend that you use the latest released version of Entity Framework However, we realize that you may need to use a previous version, or that you may want to experiment with new improvements in the latest pre-release. To install specific versions of EF, see [Get Entity Framework](xref:ef6/fundamentals/install). +## EF 6.5.0 + +The EF 6.5.0 runtime was released to NuGet in June 2024. The primary goal of EF 6.5 is to include a new SQL Server / Azure SQL Database provider. See [list of important fixes](https://github.com/dotnet/ef6/milestone/17?closed=1) on Github. Here are some of the more notable ones: + +- New SQL Server / Azure SQL Database provider (contributed by the community) - [Microsoft.EntityFramework.SqlServer](https://www.nuget.org/packages/Microsoft.EntityFramework.SqlServer/). This new provider uses the modern SQL Server client [Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient). +- The `ef6` utility was updated to only support .NET 6 and newer. It was also updated to support reading from app.config files, and support Windows ARM64. +- The System.Data.SqlClient driver was updated to version 4.8.6. + ## EF 6.4.0 -The EF 6.4.0 runtime was released to NuGet in December 2019. The primary goal of EF 6.4 is to polish the features and scenarios that was delivered in EF 6.3. See [list of important fixes](https://github.com/dotnet/ef6/milestone/14?closed=1) on Github. +The EF 6.4.0 runtime was released to NuGet in December 2019. The primary goal of EF 6.4 is to polish the features and scenarios that was delivered in EF 6.3. See [list of important fixes](https://github.com/dotnet/ef6/milestone/14?closed=1) on Github. ## EF 6.3.0 From 76ef0971bd69109b776e43a8bebb7ecae40745a5 Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Wed, 22 May 2024 18:44:30 +0200 Subject: [PATCH 009/224] Update support.md for EF 6.5 (#4731) relates to https://github.com/dotnet/ef6/issues/2237 --- entity-framework/efcore-and-ef6/support.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/entity-framework/efcore-and-ef6/support.md b/entity-framework/efcore-and-ef6/support.md index d8cc2efd9e..9c88daceed 100644 --- a/entity-framework/efcore-and-ef6/support.md +++ b/entity-framework/efcore-and-ef6/support.md @@ -2,7 +2,7 @@ title: Entity Framework Support Policies description: Support policies for every evolution of Entity Framework author: ajcvickers -ms.date: 02/16/2022 +ms.date: 05/22/2024 uid: efcore-and-ef6/support --- @@ -12,7 +12,7 @@ Entity Framework was first released in 2008 as part of the .NET Framework. Since - The first version of Entity Framework and Entity Framework 4 are fully contained in the .NET Framework - Entity Framework 4.1, 4.2, 4.3, and 5.0 have some code in the .NET Framework, and some code shipped as NuGet packages -- Entity Framework 6.0, 6.1, 6.2, 6.3, and 6.4 are shipped entirely as NuGet packages +- Entity Framework 6.0, 6.1, 6.2, 6.3, 6.4, and 6.5 are shipped entirely as NuGet packages - Entity Framework Core (all versions) is an entirely separate codebase and ships as NuGet packages Support policies for each of these variations is described in this document. In all cases, the support policy applies to the latest patch of the given versions. @@ -23,10 +23,10 @@ New versions of Entity Framework Core are shipped at the same time as new .NET v Entity Framework Core is the only actively developed version of Entity Framework and we recommend using it for all new code. -## Entity Framework 6.0, 6.1, 6.2, 6.3, and 6.4 +## Entity Framework 6.0, 6.1, 6.2, 6.3, 6.4, and 6.5 -Entity Framework 6.x follows the [Modern Lifecycle Policy](/lifecycle/policies/modern). This means that only the latest patch of the latest released version is supported. At this time the latest version is 6.4.4. This version can always [be found on NuGet](https://www.nuget.org/packages/EntityFramework/). -Versions 6.0, 6.1, 6.2, and 6.3 are no longer supported. +Entity Framework 6.x follows the [Modern Lifecycle Policy](/lifecycle/policies/modern). This means that only the latest patch of the latest released version is supported. At this time the latest version is 6.5. This version can always [be found on NuGet](https://www.nuget.org/packages/EntityFramework/). +Versions 6.0, 6.1, 6.2, 6.3, and 6.4 are no longer supported. Although Entity Framework 6.x is still supported, it is no longer being developed and will only receive fixes for security issues. The Entity Framework 6.x codebase is very stable, and it is a priority to preserve this stability by not making any unnecessary changes to the code. It is strongly encouraged that new applications and existing applications that are in active development [use Entity Framework Core](xref:efcore-and-ef6/index). From 4365c2d0402015abfb86876a5e57ed67d76bd6a2 Mon Sep 17 00:00:00 2001 From: Ramy Gamal Date: Wed, 22 May 2024 21:56:25 +0300 Subject: [PATCH 010/224] Update advanced-performance-topics.md to match SQL and C# Queries (#4733) At the "Query caching and parameterization" section in the document the C# snippets evolves around "Post" entity while the SQL snippets evolves around "Blog" entity. This commit unifies these entities to "Post" entity. --- .../core/performance/advanced-performance-topics.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index 5c4370dae2..6dee1cb2ad 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -119,12 +119,12 @@ Since the expression trees contains different constants, the expression tree dif ```sql SELECT TOP(1) [b].[Id], [b].[Name] -FROM [Blogs] AS [b] -WHERE [b].[Name] = N'blog1' +FROM [Posts] AS [b] +WHERE [b].[Name] = N'post1' SELECT TOP(1) [b].[Id], [b].[Name] -FROM [Blogs] AS [b] -WHERE [b].[Name] = N'blog2' +FROM [Posts] AS [b] +WHERE [b].[Name] = N'post2' ``` Because the SQL differs, your database server will likely also need to produce a query plan for both queries, rather than reusing the same plan. @@ -137,8 +137,8 @@ Since the blog name is now *parameterized*, both queries have the same tree shap ```sql SELECT TOP(1) [b].[Id], [b].[Name] -FROM [Blogs] AS [b] -WHERE [b].[Name] = @__blogName_0 +FROM [Posts] AS [b] +WHERE [b].[Name] = @__postTitle_0 ``` Note that there is no need to parameterize each and every query: it's perfectly fine to have some queries with constants, and indeed, databases (and EF) can sometimes perform certain optimization around constants which aren't possible when the query is parameterized. See the section on [dynamically-constructed queries](#dynamically-constructed-queries) for an example where proper parameterization is crucial. From 29819db8252b87c6bb39c208a41c308a749c3785 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Wed, 22 May 2024 15:48:54 -0700 Subject: [PATCH 011/224] Add .NET Aspire (#4734) --- entity-framework/core/extensions/index.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index 3ac1a7fe60..e55b7fb9d7 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -2,7 +2,7 @@ title: Tools & Extensions - EF Core description: External tools and extensions for Entity Framework Core author: ErikEJ -ms.date: 07/21/2023 +ms.date: 05/22/2024 uid: core/extensions/index --- @@ -355,6 +355,12 @@ Update an entity graph in store to a given one by inserting, updating and removi These packages are designed to integrate directly with EF Core to expose various APIs. +### .NET Aspire + +Enhance the local development experience by simplifying the management of your cloud-native app's configuration and interconnections. For EF Core: 8. + +[Website](https://learn.microsoft.com/dotnet/aspire/get-started/aspire-overview) | [GitHub repository](https://github.com/dotnet/aspire) | [NuGet](https://www.nuget.org/profiles/aspire) + ### HotChocolate Build your own GraphQL endpoint on top of any resource. From f3af7631d31e46af27fdd25fb6797c02b1c90be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Thu, 23 May 2024 19:36:22 +0200 Subject: [PATCH 012/224] Update Firebird provider (#4735) --- entity-framework/core/providers/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/providers/index.md b/entity-framework/core/providers/index.md index c63a1fc40d..d67b7a8a86 100644 --- a/entity-framework/core/providers/index.md +++ b/entity-framework/core/providers/index.md @@ -46,7 +46,7 @@ Entity Framework Core can access many different databases through plug-in librar | [Devart.Data.Zoho.EFCore](https://www.nuget.org/packages/Devart.Data.Zoho.EFCore) | Zoho CRM | [DevArt](https://www.devart.com/dotconnect/zohocrm/) | Paid | 6, 7, 8 | [docs](https://docs.devart.com/dotconnect/zohocrm/GettingStarted.html) | | [MASES.EntityFrameworkCore.KNet](https://www.nuget.org/packages/MASES.EntityFrameworkCore.KNet/) | Apache Kafka | [MASES Group](https://masesgroup.com) | Trial, Subscription | 6, 7, 8 | [docs](https://kefcore.masesgroup.com/) | | [InterBase](https://www.nuget.org/packages/InterBaseSql.EntityFrameworkCore.InterBase/) | InterBase | [InterBase](https://interbase.com/) | | 6 | [docs](https://docwiki.embarcadero.com/InterBase/2020/en/Entity_Framework) | -| [FirebirdSql.EntityFrameworkCore.Firebird](https://www.nuget.org/packages/FirebirdSql.EntityFrameworkCore.Firebird/) | Firebird 3.0 onwards | [Jiří Činčura](https://github.com/cincuranet) | | 7 | [docs](https://github.com/FirebirdSQL/NETProvider/blob/master/docs/entity-framework-core.md) | +| [FirebirdSql.EntityFrameworkCore.Firebird](https://www.nuget.org/packages/FirebirdSql.EntityFrameworkCore.Firebird/) | Firebird 3.0 onwards | [Jiří Činčura](https://github.com/cincuranet) | | 8 | [docs](https://github.com/FirebirdSQL/NETProvider/blob/master/docs/entity-framework-core.md) | | [IBM.EntityFrameworkCore](https://www.nuget.org/packages/IBM.EntityFrameworkCore) | Db2, Informix | [IBM](https://ibm.com) | Paid, Windows | 6 | [getting started](https://community.ibm.com/community/user/hybriddatamanagement/blogs/michelle-betbadal1/2020/04/29/getting-started-with-ibm-net-provider-for-net-core) | | [IBM.EntityFrameworkCore-lnx](https://www.nuget.org/packages/IBM.EntityFrameworkCore-lnx) | Db2, Informix | [IBM](https://ibm.com) | Paid, Linux | 6 | [getting started](https://community.ibm.com/community/user/hybriddatamanagement/blogs/michelle-betbadal1/2020/04/29/getting-started-with-ibm-net-provider-for-net-core) | | [IBM.EntityFrameworkCore-osx](https://www.nuget.org/packages/IBM.EntityFrameworkCore-osx) | Db2, Informix | [IBM](https://ibm.com) | Paid, macOS | 6 | [getting started](https://community.ibm.com/community/user/hybriddatamanagement/blogs/michelle-betbadal1/2020/04/29/getting-started-with-ibm-net-provider-for-net-core) | From 15792a6d10f13af18d48661bbf1f96bdc33314f1 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 4 Jun 2024 11:34:32 +0200 Subject: [PATCH 013/224] Add breaking change note for Unhex() nullability change (#4739) --- .../ef-core-9.0/breaking-changes.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index ccea62062c..50b5a1b9eb 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -23,6 +23,7 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET | **Breaking change** | **Impact** | |:-----------------------------------------------------------------------------------|------------| | [Sync I/O via the Azure Cosmos DB provider is no longer supported](#cosmos-nosync) | Medium | +| [EF.Functions.Unhex() now returns `byte[]?`](#unhex) | Low | ## Medium-impact changes @@ -56,3 +57,33 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) ``` That being said, applications should stop using sync APIs with Azure Cosmos DB since this is not supported by the Azure Cosmos DB SDK. The ability to suppress the exception will be removed in a future release of EF Core, after which the only option will be to use async APIs. + +## Low-impact changes + + + +### EF.Functions.Unhex() now returns `byte[]?` + +[Tracking Issue #33864](https://github.com/dotnet/efcore/issues/33864) + +#### Old behavior + +The EF.Functions.Unhex() function was previously annotated to return `byte[]`. + +#### New behavior + +Starting with EF Core 9.0, Unhex() is now annotated to return `byte[]?`. + +#### Why + +Unhex() is translated to the SQLite `unhex` function, which returns NULL for invalid inputs. As a result, Unhex() returned `null` for those cases, in violation of the annotation. + +#### Mitigations + +If you are sure that the text content passed to Unhex() represents a valid, hexadecimal string, you can simply add the null-forgiving operator as an assertion that the invocation will never return null: + +```c# +var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString)!).ToListAsync(); +``` + +Otherwise, add runtime checks for null on the return value of Unhex(). From 4ab234a841eb52bd26121fb4c3c68a27e5bf8c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Thu, 6 Jun 2024 09:24:52 +0200 Subject: [PATCH 014/224] Add documentation for breaking change. (#4738) --- .../ef-core-9.0/breaking-changes.md | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index 50b5a1b9eb..810ee5f2e9 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -20,10 +20,11 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET ## Summary -| **Breaking change** | **Impact** | -|:-----------------------------------------------------------------------------------|------------| -| [Sync I/O via the Azure Cosmos DB provider is no longer supported](#cosmos-nosync) | Medium | -| [EF.Functions.Unhex() now returns `byte[]?`](#unhex) | Low | +| **Breaking change** | **Impact** | +|:-----------------------------------------------------------------------------------------------------|------------| +| [Sync I/O via the Azure Cosmos DB provider is no longer supported](#cosmos-nosync) | Medium | +| [EF.Functions.Unhex() now returns `byte[]?`](#unhex) | Low | +| [SqlFunctionExpression's nullability arguments' arity validated](#sqlfunctionexpression-nullability) | Low | ## Medium-impact changes @@ -87,3 +88,25 @@ var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString) ``` Otherwise, add runtime checks for null on the return value of Unhex(). + + + +### SqlFunctionExpression's nullability arguments' arity validated + +[Tracking Issue #33852](https://github.com/dotnet/efcore/issues/33852) + +#### Old behavior + +Previously it was possible to create a `SqlFunctionExpression` with a different number of arguments and nullability propagation arguments. + +#### New behavior + +Starting with EF Core 9.0, EF now throws if the number of arguments and nullability propagation arguments do not match. + +#### Why + +Not having matching number of arguments and nullability propagation arguments can lead to unexpected behavior. + +#### Mitigations + +Make sure the `argumentsPropagateNullability` has same number of elements as the `arguments`. When in doubt use `false` for nullability argument. From 573feeb844544b41942086c96a4edbe6b8e3c8f8 Mon Sep 17 00:00:00 2001 From: Aleksandr <48987461+s4sh4w4lk3r@users.noreply.github.com> Date: Sun, 9 Jun 2024 01:11:31 +0300 Subject: [PATCH 015/224] Updated index.md about MongoDB (#4740) MongoDB has become GA and has a release version. Read more: https://www.mongodb.com/blog/post/mongodb-provider-entity-framework-core-now-generally-available --- entity-framework/core/providers/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/providers/index.md b/entity-framework/core/providers/index.md index d67b7a8a86..ea0590c66c 100644 --- a/entity-framework/core/providers/index.md +++ b/entity-framework/core/providers/index.md @@ -28,7 +28,7 @@ Entity Framework Core can access many different databases through plug-in librar | [Pomelo.EntityFrameworkCore.MySql](https://www.nuget.org/packages/Pomelo.EntityFrameworkCore.MySql) | MySQL, MariaDB | [Pomelo Foundation Project](https://github.com/PomeloFoundation) | | 6, 7, 8 | [readme](https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/blob/master/README.md) | | [MySql.EntityFrameworkCore](https://www.nuget.org/packages/MySql.EntityFrameworkCore) | MySQL | [MySQL project](https://dev.mysql.com) (Oracle) | | 6, 7 | [docs](https://dev.mysql.com/doc/connector-net/en/connector-net-entityframework-core.html) | | [Oracle.EntityFrameworkCore](https://www.nuget.org/packages/Oracle.EntityFrameworkCore/) | Oracle DB 11.2 onwards | [Oracle](https://www.oracle.com/technetwork/topics/dotnet/) | | 6, 7 | [website](https://www.oracle.com/technetwork/topics/dotnet/) | -| [MongoDB.EntityFrameworkCore](https://www.nuget.org/packages/MongoDB.EntityFrameworkCore/) | MongoDB | [MongoDB](https://www.mongodb.com/) | Currently in preview | 7 | [docs](https://www.mongodb.com/docs/entity-framework/current/) | +| [MongoDB.EntityFrameworkCore](https://www.nuget.org/packages/MongoDB.EntityFrameworkCore/) | MongoDB | [MongoDB](https://www.mongodb.com/) | | 8 | [docs](https://www.mongodb.com/docs/entity-framework/current/) | | [Devart.Data.MySql.EFCore](https://www.nuget.org/packages/Devart.Data.MySql.EFCore/) | MySQL 5 onwards | [DevArt](https://www.devart.com/dotconnect/mysql/) | Paid | 6, 7, 8 | [docs](https://docs.devart.com/dotconnect/mysql/GettingStarted.html) | | [Devart.Data.Oracle.EFCore](https://www.nuget.org/packages/Devart.Data.Oracle.EFCore/) | Oracle DB 9.2.0.4 onwards | [DevArt](https://www.devart.com/dotconnect/oracle/) | Paid | 6, 7, 8 | [docs](https://docs.devart.com/dotconnect/oracle/GettingStarted.html) | | [Devart.Data.PostgreSql.EFCore](https://www.nuget.org/packages/Devart.Data.PostgreSql.EFCore/) | PostgreSQL 8.0 onwards | [DevArt](https://www.devart.com/dotconnect/postgresql/) | Paid | 6, 7, 8 | [docs](https://docs.devart.com/dotconnect/postgresql/GettingStarted.html) | From d5f92917aba96c2e132b04ee72229024ff31cda1 Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Tue, 11 Jun 2024 18:10:39 +0100 Subject: [PATCH 016/224] What's New for preview 5 (#4744) * What's New for preview 5 * Fixing unrelated link issues: - Use relative - Remove broken --- entity-framework/core/extensions/index.md | 2 +- .../core/learn-more/community-standups.md | 1 - .../core/what-is-new/ef-core-9.0/whatsnew.md | 309 +++++++++++++++++- .../CosmosDiagnosticsSample.cs | 28 +- .../CosmosImplicitOwnershipSample.cs | 21 +- .../CosmosPrimitiveTypesSample.cs | 15 +- .../NewInEFCore6.Cosmos/Program.cs | 6 +- .../App/App.csproj | 2 +- .../Model/Model.csproj | 8 +- .../HierarchicalPartitionKeysSample.cs | 248 ++++++++++++++ .../NewInEFCore9.Cosmos.csproj | 2 +- .../NewInEFCore9.Cosmos/Program.cs | 1 + .../NewInEFCore9/DateOnlyTimeOnlySample.cs | 251 ++++++++++++++ .../NewInEFCore9/NewInEFCore9.csproj | 18 +- .../Miscellaneous/NewInEFCore9/Program.cs | 46 +-- .../Miscellaneous/NewInEFCore9/QuerySample.cs | 10 + 16 files changed, 894 insertions(+), 74 deletions(-) create mode 100644 samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs create mode 100644 samples/core/Miscellaneous/NewInEFCore9/DateOnlyTimeOnlySample.cs diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index e55b7fb9d7..6745b955bb 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -359,7 +359,7 @@ These packages are designed to integrate directly with EF Core to expose various Enhance the local development experience by simplifying the management of your cloud-native app's configuration and interconnections. For EF Core: 8. -[Website](https://learn.microsoft.com/dotnet/aspire/get-started/aspire-overview) | [GitHub repository](https://github.com/dotnet/aspire) | [NuGet](https://www.nuget.org/profiles/aspire) +[Website](/dotnet/aspire/get-started/aspire-overview) | [GitHub repository](https://github.com/dotnet/aspire) | [NuGet](https://www.nuget.org/profiles/aspire) ### HotChocolate diff --git a/entity-framework/core/learn-more/community-standups.md b/entity-framework/core/learn-more/community-standups.md index 4d0775ef2a..29c59cf79e 100644 --- a/entity-framework/core/learn-more/community-standups.md +++ b/entity-framework/core/learn-more/community-standups.md @@ -1591,7 +1591,6 @@ Featuring: Links: - Blog: [Oracle EF Core 3.1 Production Release](https://medium.com/oracledevs/oracle-ef-core-3-1-production-release-9e470eaf3d03) -- Blog: [Seeding data in EF Core using SQL scripts](https://dejanstojanovic.net/aspnet/2020/september/seeding-data-in-ef-core-using-sql-scripts/) - Blog: [Announcing Entity Framework Core (EFCore) 5.0 RC1](https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-efcore-5-0-rc1/) - Docs: [Migrations Overview](xref: core/managing-schemas/migrations/index) - Docs: [EF Core daily builds](https://aka.ms/ef-daily-builds) 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 e6926d5cec..a1d6852efc 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 @@ -2,13 +2,13 @@ title: What's New in EF Core 9 description: Overview of new features in EF Core 9 author: ajcvickers -ms.date: 05/02/2024 +ms.date: 06/09/2024 uid: core/what-is-new/ef-core-9.0/whatsnew --- # What's New in EF Core 9 -EF Core 9 (EF9) is the next release after EF Core 8 and is scheduled for release in November 2024. See [_Plan for Entity Framework Core 9_](xref:core/what-is-new/ef-core-9.0/plan) for details. +EF Core 9 (EF9) is the next release after EF Core 8 and is scheduled for release in November 2024. EF9 is available as [daily builds](https://github.com/dotnet/efcore/blob/main/docs/DailyBuilds.md) which contain all the latest EF9 features and API tweaks. The samples here make use of these daily builds. @@ -26,6 +26,261 @@ EF9 targets .NET 8, and can therefore be used with either [.NET 8 (LTS)](https:/ We are working on significant updates in EF9 to the EF Core database provider for Azure Cosmos DB for NoSQL. +### Hierarchical partition keys + +> [!TIP] +> The code shown here comes from [HierarchicalPartitionKeysSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs). + +Each document stored in the Cosmos database has a unique resource ID. In addition, each document can contain a "partition key" which determines the logical partitioning of data such that the database can be effectively scaled. More information on choosing partition keys can be found in [_Partitioning and horizontal scaling in Azure Cosmos DB_](/azure/cosmos-db/partitioning-overview). + +Recent releases of Azure Cosmos DB for NoSQL (Cosmos SDK version 3.33.0 or later) have expanded partitioning capabilities to support [subpartitioning through the specification of up to three levels of hierarchy in the partition key](/azure/cosmos-db/hierarchical-partition-keys). EF Core 9 supports specification of hierarchical partition keys in the model, automatic extraction of these values from queries, and manual specification of a hierarchical partition key for a given query. + +#### Configuring hierarchical partition keys + +Partition keys are specified using the model building API, typically in . There must be a mapped property in the entity type for each level of the partition key. For example, consider a `UserSession` entity type: + + +[!code-csharp[UserSession](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=UserSession)] + +The following code specifies a three-level partition key using the `TenantId`, `UserId`, and `SessionId` properties: + + +[!code-csharp[HasPartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=HasPartitionKey)] + +> [!TIP] +> This partition key definition follows the example given in [_Choose your hierarchical partition keys_](/azure/cosmos-db/hierarchical-partition-keys#choose-your-hierarchical-partition-keys) from the Azure Cosmos DB documentation. + +Notice how, starting with EF Core 9, properties of any mapped type can be used in the partition key. For `bool` and numeric types, like the `int SessionId` property, the value is used directly in the partition key. Other types, like the `Guid UserId` property, are automatically converted to strings. + +#### Saving documents with hierarchical partition keys + +Saving a new document with a hierarchical partition key is the same as saving any new document with EF Core. The primary key and partition key properties must have non-default values, or EF Core value generation can be used to create values. For example, the following code inserts `UserSession` documents where the `Id` property is generated by EF Core, and all the partition key properties have been set explicitly: + + +[!code-csharp[Inserts](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=Inserts)] + +The logs from calling `SaveChangesAsync` show in the following `CreateItem` calls: + +```output +info: 6/10/2024 18:41:04.456 CosmosEventId.ExecutedCreateItem[30104] (Microsoft.EntityFrameworkCore.Database.Command) + Executed CreateItem (167 ms, 7.81 RU) ActivityId='23891b55-7375-40e5-aa4b-2c57ca6a376e', Container='UserSessionContext', Id='UserSession|d5e2614b-71f2-4e6b-d41a-08dc89748055', Partition='["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",7.0]' +info: 6/10/2024 18:41:04.478 CosmosEventId.ExecutedCreateItem[30104] (Microsoft.EntityFrameworkCore.Database.Command) + Executed CreateItem (14 ms, 7.81 RU) ActivityId='7fdcfb3e-455c-45dd-b444-02b66575a28f', Container='UserSessionContext', Id='UserSession|01cc0102-5212-4785-d41b-08dc89748055', Partition='["Microsoft","adae5dde-8a67-432d-9dec-fd7ec86fd9f6",7.0]' +info: 6/10/2024 18:41:04.491 CosmosEventId.ExecutedCreateItem[30104] (Microsoft.EntityFrameworkCore.Database.Command) + Executed CreateItem (13 ms, 7.81 RU) ActivityId='3f7e6026-8edf-4f2c-8918-09434dc039bf', Container='UserSessionContext', Id='UserSession|e5a467c0-bb1e-4ffe-d41c-08dc89748055', Partition='["Microsoft","61967254-aff8-493a-b7f8-e62da36d8367",7.0]' +info: 6/10/2024 18:41:04.507 CosmosEventId.ExecutedCreateItem[30104] (Microsoft.EntityFrameworkCore.Database.Command) + Executed CreateItem (15 ms, 7.81 RU) ActivityId='04c6f4b2-0ad0-4708-874e-dc8967726d18', Container='UserSessionContext', Id='UserSession|fd47726a-fb68-4c63-d41d-08dc89748055', Partition='["Microsoft","bc0150cf-5147-44b8-8823-865f4f2323e1",7.0]' +``` + +Notice that the partition key values have been extracted from the entity instance and included in the call to `CreateItem` to ensure maximum efficiency on the server. + +#### Point reads using hierarchical partition keys + +By convention, EF Core includes the partition key properties in the primary key definition for the entity type. For example, inspecting the [model debug view](xref:core/modeling/index#debug-view) shows the following mapping for the `UserSession` entity type: + +```output +EntityType: UserSession + Properties: + Id (Guid) Required PK AfterSave:Throw ValueGenerated.OnAdd + TenantId (string) Required PK AfterSave:Throw + UserId (Guid) Required PK AfterSave:Throw + SessionId (int) Required PK AfterSave:Throw + Discriminator (no field, string) Shadow Required AfterSave:Throw + Username (string) + __id (no field, string) Shadow Required AlternateKey AfterSave:Throw + __jObject (no field, JObject) Shadow BeforeSave:Ignore AfterSave:Ignore ValueGenerated.OnAddOrUpdate + Keys: + Id, TenantId, UserId, SessionId PK + __id, TenantId, UserId, SessionId +``` + +Notice that the primary key definition is `Id, TenantId, UserId, SessionId`. This means that can be used to lookup a document. For example: + + +[!code-csharp[FindAsync](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=FindAsync)] + +Logging from EF Core shows that a point-read (using `ReadItem`) is executed for maximum efficiency: + +```output +info: 6/10/2024 18:41:04.651 CosmosEventId.ExecutingReadItem[30101] (Microsoft.EntityFrameworkCore.Database.Command) + Reading resource 'UserSession|e5a467c0-bb1e-4ffe-d41c-08dc89748055' item from container 'UserSessionContext' in partition '["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",7.0]'. +info: 6/10/2024 18:41:04.668 CosmosEventId.ExecutedReadItem[30103] (Microsoft.EntityFrameworkCore.Database.Command) + Executed ReadItem (8 ms, 1 RU) ActivityId='a016f26c-6bd0-4c66-953b-a8f1297df41a', Container='UserSessionContext', Id='UserSession|e5a467c0-bb1e-4ffe-d41c-08dc89748055', Partition='["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",7.0]' +``` + +#### Queries using hierarchical partition keys + +EF Core will extract the partition key values from queries and apply them to the Cosmos query API to ensure the queries are constrained appropriately to the fewest number of partitions possible. For example, consider a LINQ query that supplies values for all levels of the partition key: + + +[!code-csharp[FullPartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=FullPartitionKey)] + +When executing this query, EF Core will extract the values of the `tenantId`, `userId`, and `sessionId` parameters, and pass them to the Cosmos query API as the partition key value. For example, see the logs from executing the query above: + +```output +info: 6/10/2024 19:06:00.017 CosmosEventId.ExecutingSqlQuery[30100] (Microsoft.EntityFrameworkCore.Database.Command) + Executing SQL query for container 'UserSessionContext' in partition '["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",7.0]' [Parameters=[]] + SELECT c + FROM root c + WHERE ((c["Discriminator"] = "UserSession") AND CONTAINS(c["Username"], "a")) +``` + +Notice that the partition key comparisons have been removed from the `WHERE` clause, and are instead passed directly to the Cosmos API as partition key `["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",7.0]`. + +> [!IMPORTANT] +> Because the query includes values for all parts of the partition key, this that the query us routed to the single partition that contains the data for the specified values of `TenantId`, `UserId`, and `SessionId`. This is more efficient than the queries below which only use none, or only some, of the partition key values. + +With hierarchical partitions, more efficient queries can still be generated when only the top partition key hierarchy is known. For example, the following LINQ query uses the top two parts of the partition key--that is, `TenantId` and `UserId`: + + +[!code-csharp[TopTwoPartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=TopTwoPartitionKey)] + +EF Core still extracts the partition key values when executing this query: + +```output +info: 6/10/2024 19:24:46.581 CosmosEventId.ExecutingSqlQuery[30100] (Microsoft.EntityFrameworkCore.Database.Command) + Executing SQL query for container 'UserSessionContext' in partition '["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c"]' [Parameters=[]] + SELECT c + FROM root c + WHERE ((c["Discriminator"] = "UserSession") AND CONTAINS(c["Username"], "a")) +``` + +This query does not include the `SessionId`, so it cannot target a single partition. However, it will still be a targeted, cross-partition query returning data for all sessions of a single tenant and user ID. + +Likewise, if only the top value in the hierarchy is specified, then it will be used on its own. For example: + + +[!code-csharp[TopOnePartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=TopOnePartitionKey)] + +Which results in the following logs: + +```output +info: 6/11/2024 09:30:42.532 CosmosEventId.ExecutingSqlQuery[30100] (Microsoft.EntityFrameworkCore.Database.Command) + Executing SQL query for container 'UserSessionContext' in partition '["Microsoft"]' [Parameters=[]] + SELECT c + FROM root c + WHERE ((c["Discriminator"] = "UserSession") AND CONTAINS(c["Username"], "a")) +``` + +Since this query only contains the `TenantId` part of the partition key it cannot target a single partition. However, as with the previous example it will still be a targeted, cross-partition query returning data for all sessions and users in a single tenant. + +It is important to understand that using the second and/or third values of the hierarchical partition key, without including the first value, will result in a query that covers all partitions. For example, consider a query including both `SessionId` and `UserId`, but not including `TenantId`: + + +[!code-csharp[BottomTwoPartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=BottomTwoPartitionKey)] + +The logs show that this is translated without a partition key, since the `TenantId` is missing: + +```output +info: 6/11/2024 09:30:42.553 CosmosEventId.ExecutingSqlQuery[30100] (Microsoft.EntityFrameworkCore.Database.Command) + Executing SQL query for container 'UserSessionContext' in partition 'None' [Parameters=[]] + SELECT c + FROM root c + WHERE (c["Discriminator"] = "UserSession") +``` + +> [!NOTE] +> [Issue #33960](https://github.com/dotnet/efcore/issues/33960) is tracking a bug in this translation. + ### Role-based access Azure Cosmos DB for NoSQL includes a [built-in role-based access control (RBAC) system](/azure/cosmos-db/role-based-access-control). This is now supported by EF9 for both management and use of containers. No changes are required to application code. See [Issue #32197](https://github.com/dotnet/efcore/issues/32197) for more information. @@ -425,6 +680,56 @@ The meth This enhancement was contributed by [@wertzui](https://github.com/wertzui). Many thanks! +### Queries using Count != 0 are optimized + +> [!TIP] +> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). + +In EF8, the following LINQ query was translated to use the SQL `COUNT` function: + + +[!code-csharp[NormalizeCount](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=NormalizeCount)] + +EF9 now generates a more efficient translation using `EXISTS`: + +```sql +SELECT "b"."Id", "b"."Name", "b"."SiteUri" +FROM "Blogs" AS "b" +WHERE EXISTS ( + SELECT 1 + FROM "Posts" AS "p" + WHERE "b"."Id" = "p"."BlogId") +``` + +### More `TimeOnly` methods are translated for Azure SQL/SQL Server + +> [!TIP] +> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). + +Queries using and are now translated when using SQL Server or Azure SQL. For example, the following LINQ query uses `FromDateTime` to extract the time-of-day value from a column and compare it to a `TimeOnly` value passed in: + + +[!code-csharp[FromDateTime](../../../../samples/core/Miscellaneous/NewInEFCore9/DateOnlyTimeOnlySample.cs?name=FromDateTime)] + +This is translated to the following when using SQL Azure or SQL Server: + +```sql +SELECT [s].[Id], [s].[Founded], [s].[LastVisited], [s].[LegacyTime], [s].[Name], [s].[OpeningHours] +FROM [Schools] AS [s] +WHERE CAST([s].[LastVisited] AS time) >= @__visitedTime_0 +``` + +`FromTimeSpan` is translated in a similar manner. + ## ExecuteUpdate and ExecuteDelete diff --git a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosDiagnosticsSample.cs b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosDiagnosticsSample.cs index c237fe17e3..3942e95ee8 100644 --- a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosDiagnosticsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosDiagnosticsSample.cs @@ -1,18 +1,18 @@ using System; using System.Collections.Generic; -using System.Linq; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; public static class CosmosDiagnosticsSample { - public static void Cosmos_diagnostics() + public static async Task Cosmos_diagnostics() { Console.WriteLine($">>>> Sample: {nameof(Cosmos_diagnostics)}"); Console.WriteLine(); - Helpers.RecreateCleanDatabase(); - Helpers.PopulateDatabase(); + await Helpers.RecreateCleanDatabase(); + await Helpers.PopulateDatabase(); using var context = new ShapesContext(); @@ -30,7 +30,7 @@ public static void Cosmos_diagnostics() InsertedOn = DateTime.UtcNow }; context.Add(triangle); - context.SaveChanges(); + await context.SaveChangesAsync(); #endregion Console.WriteLine(); @@ -38,7 +38,7 @@ public static void Cosmos_diagnostics() Console.WriteLine(); #region QueryEvents - var equilateral = context.Triangles.Single(e => e.Name == "Equilateral"); + var equilateral = await context.Triangles.SingleAsync(e => e.Name == "Equilateral"); #endregion Console.WriteLine(); @@ -46,7 +46,7 @@ public static void Cosmos_diagnostics() Console.WriteLine(); #region FindEvents - var isosceles = context.Triangles.Find("Isosceles", "TrianglesPartition"); + var isosceles = await context.Triangles.FindAsync("Isosceles", "TrianglesPartition"); #endregion Console.WriteLine(); @@ -55,7 +55,7 @@ public static void Cosmos_diagnostics() #region UpdateEvents triangle.Angle2 = 89; - context.SaveChanges(); + await context.SaveChangesAsync(); #endregion Console.WriteLine(); @@ -64,7 +64,7 @@ public static void Cosmos_diagnostics() #region DeleteEvents context.Remove(triangle); - context.SaveChanges(); + await context.SaveChangesAsync(); #endregion Console.WriteLine(); @@ -72,15 +72,15 @@ public static void Cosmos_diagnostics() public static class Helpers { - public static void RecreateCleanDatabase() + public static async Task RecreateCleanDatabase() { using var context = new ShapesContext(quiet: true); - context.Database.EnsureDeleted(); - context.Database.EnsureCreated(); + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); } - public static void PopulateDatabase() + public static async Task PopulateDatabase() { using var context = new ShapesContext(quiet: true); @@ -94,7 +94,7 @@ public static void PopulateDatabase() }; context.AddRange(triangles); - context.SaveChanges(); + await context.SaveChangesAsync(); } } diff --git a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosImplicitOwnershipSample.cs b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosImplicitOwnershipSample.cs index 66e5ae80f1..54592e885c 100644 --- a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosImplicitOwnershipSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosImplicitOwnershipSample.cs @@ -2,20 +2,21 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; public static class CosmosImplicitOwnershipSample { - public static void Cosmos_models_use_implicit_ownership_by_default() + public static async Task Cosmos_models_use_implicit_ownership_by_default() { Console.WriteLine($">>>> Sample: {nameof(Cosmos_models_use_implicit_ownership_by_default)}"); Console.WriteLine(); using (var context = new FamilyContext()) { - context.Database.EnsureDeleted(); - context.Database.EnsureCreated(); + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); context.AddRange( new Family @@ -44,7 +45,7 @@ public static void Cosmos_models_use_implicit_ownership_by_default() LastName = "Wakefield", Parents = { - new() { FamilyName = "Wakefield", FirstName = "Robin" }, + new() { FamilyName = "Wakefield", FirstName = "Robin" }, new() { FamilyName = "Miller", FirstName = "Ben" } }, Children = @@ -69,14 +70,14 @@ public static void Cosmos_models_use_implicit_ownership_by_default() IsRegistered = true }); - context.SaveChanges(); + await context.SaveChangesAsync(); } Console.WriteLine(); using (var context = new FamilyContext()) { - var families = context.Families.ToList(); + var families = await context.Families.ToListAsync(); Console.WriteLine(); @@ -96,10 +97,10 @@ public class Family { [JsonPropertyName("id")] public string Id { get; set; } - + public string LastName { get; set; } public bool IsRegistered { get; set; } - + public Address Address { get; set; } public IList Parents { get; } = new List(); @@ -153,7 +154,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasPartitionKey(e => e.LastName); #endregion } - + // Never called; just for documentation. private void OldOnModelCreating(ModelBuilder modelBuilder) { @@ -167,7 +168,7 @@ private void OldOnModelCreating(ModelBuilder modelBuilder) .OwnsMany(c => c.Pets); modelBuilder.Entity() - .OwnsOne(f => f.Address); + .OwnsOne(f => f.Address); #endregion } diff --git a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs index 6934aaebeb..9613eeb2ee 100644 --- a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs @@ -1,17 +1,18 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; public static class CosmosPrimitiveTypesSample { - public static void Collections_and_dictionaries_of_primitive_types() + public static async Task Collections_and_dictionaries_of_primitive_types() { Console.WriteLine($">>>> Sample: {nameof(Collections_and_dictionaries_of_primitive_types)}"); Console.WriteLine(); - Helpers.RecreateCleanDatabase(); + await Helpers.RecreateCleanDatabase(); #region Insert using var context = new BooksContext(); @@ -35,14 +36,14 @@ public static void Collections_and_dictionaries_of_primitive_types() }; context.Add(book); - context.SaveChanges(); + await context.SaveChangesAsync(); #endregion #region Updates book.Quotes.Add("Pressing the emergency button lowered the rods again."); book.Notes["48"] = "Chiesa d'Oro"; - context.SaveChanges(); + await context.SaveChangesAsync(); #endregion Console.WriteLine(); @@ -50,12 +51,12 @@ public static void Collections_and_dictionaries_of_primitive_types() public static class Helpers { - public static void RecreateCleanDatabase() + public static async Task RecreateCleanDatabase() { using var context = new BooksContext(quiet: true); - context.Database.EnsureDeleted(); - context.Database.EnsureCreated(); + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); } } diff --git a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/Program.cs b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/Program.cs index c914a3af48..a7fe86192e 100644 --- a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/Program.cs +++ b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/Program.cs @@ -5,12 +5,12 @@ public class Program public static async Task Main() { // Note: These samples requires the Cosmos DB emulator to be installed and running - CosmosPrimitiveTypesSample.Collections_and_dictionaries_of_primitive_types(); + await CosmosPrimitiveTypesSample.Collections_and_dictionaries_of_primitive_types(); await CosmosQueriesSample.Cosmos_queries(); - CosmosDiagnosticsSample.Cosmos_diagnostics(); + await CosmosDiagnosticsSample.Cosmos_diagnostics(); CosmosModelConfigurationSample.Cosmos_configure_time_to_live(); await CosmosModelConfigurationSample.Cosmos_configure_time_to_live_per_instance(); - CosmosImplicitOwnershipSample.Cosmos_models_use_implicit_ownership_by_default(); + await CosmosImplicitOwnershipSample.Cosmos_models_use_implicit_ownership_by_default(); CosmosMinimalApiSample.Add_a_DbContext_and_provider(); } } diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj index fe513d3fc4..8accd90c2f 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj @@ -9,7 +9,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj index 2af439d9d3..a877bb1332 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj @@ -15,13 +15,13 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs new file mode 100644 index 0000000000..b99ba2b865 --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs @@ -0,0 +1,248 @@ +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +public static class HierarchicalPartitionKeysSample +{ + public static async Task UseHierarchicalPartitionKeys() + { + Console.WriteLine($">>>> Sample: {nameof(UseHierarchicalPartitionKeys)}"); + Console.WriteLine(); + + await Helpers.RecreateCleanDatabase(); + + Guid userSessionId; + + using (var context = new UserSessionContext()) + { + #region Inserts + var tenantId = "Microsoft"; + var sessionId = 7; + + context.AddRange( + new UserSession + { + TenantId = tenantId, + UserId = new Guid("99A410D7-E467-4CC5-92DE-148F3FC53F4C"), + SessionId = sessionId, + Username = "mac" + }, + new UserSession + { + TenantId = tenantId, + UserId = new Guid("ADAE5DDE-8A67-432D-9DEC-FD7EC86FD9F6"), + SessionId = sessionId, + Username = "toast" + }, + new UserSession + { + TenantId = tenantId, + UserId = new Guid("61967254-AFF8-493A-B7F8-E62DA36D8367"), + SessionId = sessionId, + Username = "willow" + }, + new UserSession + { + TenantId = tenantId, + UserId = new Guid("BC0150CF-5147-44B8-8823-865F4F2323E1"), + SessionId = sessionId, + Username = "alice" + }); + + await context.SaveChangesAsync(); + #endregion + + userSessionId = context.ChangeTracker.Entries().Single(e => e.Entity.Username == "willow").Entity.Id; + } + + Console.WriteLine(); + Console.WriteLine("Use Find to create a point-read:"); + Console.WriteLine(); + + using (var context = new UserSessionContext()) + { + #region FindAsync + var tenantId = "Microsoft"; + var sessionId = 7; + var userId = new Guid("99A410D7-E467-4CC5-92DE-148F3FC53F4C"); + + var session = await context.Sessions.FindAsync( + userSessionId, tenantId, userId, sessionId); + #endregion + } + + Console.WriteLine(); + Console.WriteLine("Execute a query with full hierarchical partition key info:"); + Console.WriteLine(); + + using (var context = new UserSessionContext()) + { + #region FullPartitionKey + var tenantId = "Microsoft"; + var sessionId = 7; + var userId = new Guid("99A410D7-E467-4CC5-92DE-148F3FC53F4C"); + + var sessions = await context.Sessions + .Where( + e => e.TenantId == tenantId + && e.UserId == userId + && e.SessionId == sessionId + && e.Username.Contains("a")) + .ToListAsync(); + #endregion + } + + Console.WriteLine(); + Console.WriteLine("Execute a query with only top two levels of hierarchical partition key:"); + Console.WriteLine(); + + using (var context = new UserSessionContext()) + { + #region TopTwoPartitionKey + var tenantId = "Microsoft"; + var userId = new Guid("99A410D7-E467-4CC5-92DE-148F3FC53F4C"); + + var sessions = await context.Sessions + .Where( + e => e.TenantId == tenantId + && e.UserId == userId + && e.Username.Contains("a")) + .ToListAsync(); + #endregion + } + + Console.WriteLine(); + Console.WriteLine("Execute a query with only top level of hierarchical partition key:"); + Console.WriteLine(); + + using (var context = new UserSessionContext()) + { + #region TopOnePartitionKey + var tenantId = "Microsoft"; + + var sessions = await context.Sessions + .Where( + e => e.TenantId == tenantId + && e.Username.Contains("a")) + .ToListAsync(); + #endregion + } + + Console.WriteLine(); + Console.WriteLine("Execute a queries with incomplete subkey values:"); + Console.WriteLine(); + + using (var context = new UserSessionContext()) + { + var tenantId = "Microsoft"; + var sessionId = 7; + var userId = new Guid("99A410D7-E467-4CC5-92DE-148F3FC53F4C"); + + #region BottomPartitionKey + var sessions1 = await context.Sessions + .Where( + e => e.SessionId == sessionId + && e.Username.Contains("a")) + .ToListAsync(); + #endregion + + #region MiddlePartitionKey + var sessions2 = await context.Sessions + .Where( + e => e.UserId == userId + && e.Username.Contains("a")) + .ToListAsync(); + #endregion + + #region BottomTwoPartitionKey + var sessions3 = await context.Sessions + .Where( + e => e.SessionId == sessionId + && e.UserId == userId + && e.Username.Contains("a")) + .ToListAsync(); + #endregion + } + } + + public static class Helpers + { + public static async Task RecreateCleanDatabase() + { + await using var context = new UserSessionContext(quiet: true); + + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); + } + } + + #region UserSession + public class UserSession + { + // Item ID + public Guid Id { get; set; } + + // Partition Key + public string TenantId { get; set; } = null!; + public Guid UserId { get; set; } + public int SessionId { get; set; } + + // Other members + public string Username { get; set; } = null!; + } + #endregion + + public class UserSessionContext : DbContext + { + public DbSet Sessions { get; set; } + + private readonly bool _quiet; + + public UserSessionContext(bool quiet = false) + { + _quiet = quiet; + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + #region HasPartitionKey + modelBuilder + .Entity() + .HasPartitionKey(e => new { e.TenantId, e.UserId, e.SessionId }); + #endregion + + // See https://github.com/dotnet/efcore/issues/33961 + modelBuilder + .Entity() + .Property(e => e.Id).ValueGeneratedOnAdd(); + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder + .EnableSensitiveDataLogging() + .UseCosmos( + "https://localhost:8081/", + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", + "HierarchicalPartitionKeys", + cosmosOptionsBuilder => + { + cosmosOptionsBuilder.HttpClientFactory( + () => new HttpClient( + new HttpClientHandler + { + ServerCertificateCustomValidationCallback = + HttpClientHandler.DangerousAcceptAnyServerCertificateValidator + })); + }); + + if (!_quiet) + { + optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information); + } + } + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj index ba4fe7e8f0..4a5031a626 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/Program.cs b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/Program.cs index dacbe2028a..95a17c33f8 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/Program.cs +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/Program.cs @@ -7,5 +7,6 @@ public static async Task Main() // Note: These samples requires the Cosmos DB emulator to be installed and running CosmosSyncApisSample.Cosmos_provider_blocks_sync_APIs(); await CosmosPrimitiveTypesSample.Collections_and_dictionaries_of_primitive_types(); + await HierarchicalPartitionKeysSample.UseHierarchicalPartitionKeys(); } } diff --git a/samples/core/Miscellaneous/NewInEFCore9/DateOnlyTimeOnlySample.cs b/samples/core/Miscellaneous/NewInEFCore9/DateOnlyTimeOnlySample.cs new file mode 100644 index 0000000000..6a792c8b3a --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9/DateOnlyTimeOnlySample.cs @@ -0,0 +1,251 @@ +namespace NewInEfCore9; + +public static class DateOnlyTimeOnlySample +{ + public static Task Can_use_DateOnly_TimeOnly_on_SQL_Server() + { + PrintSampleName(); + return DateOnlyTimeOnlyTest(); + } + + public static Task Can_use_DateOnly_TimeOnly_on_SQL_Server_with_JSON() + { + PrintSampleName(); + return DateOnlyTimeOnlyTest(); + } + + public static Task Can_use_DateOnly_TimeOnly_on_SQLite() + { + PrintSampleName(); + return DateOnlyTimeOnlyTest(); + } + + private static async Task DateOnlyTimeOnlyTest() + where TContext : BritishSchoolsContextBase, new() + { + await using var context = new TContext(); + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); + await context.Seed(); + + context.LoggingEnabled = true; + context.ChangeTracker.Clear(); + + Console.WriteLine(); + + // Issue https://github.com/dotnet/efcore/issues/25103 + if (!context.UseSqlite) + { + #region FromDateTime + var visitedTime = new TimeOnly(12, 0); + var visited = await context.Schools + .Where(p => TimeOnly.FromDateTime(p.LastVisited) >= visitedTime) + .ToListAsync(); + #endregion + } + + Console.WriteLine(); + + // Issue https://github.com/dotnet/efcore/issues/25103 + if (!context.UseSqlite) + { + #region FromTimeSpan + var visitedTime = new TimeOnly(12, 0); + var visited = await context.Schools + .Where(p => TimeOnly.FromTimeSpan(p.LegacyTime) >= visitedTime) + .ToListAsync(); + #endregion + } + + Console.WriteLine(); + + // Issue https://github.com/dotnet/efcore/issues/25103 + if (!context.UseSqlite) + { + var visitedAt = DateTime.UtcNow; + var visitedSchools = await context.Schools + .AsNoTracking() + .SelectMany(e => e.OpeningHours) + .Where(e => e.OpensAt <= TimeOnly.FromDateTime(visitedAt) && e.OpensAt > TimeOnly.FromDateTime(visitedAt)) + .ToListAsync(); + } + + // Issue https://github.com/dotnet/efcore/issues/33937 + // // Issue https://github.com/dotnet/efcore/issues/30223 + // if (!context.UsesJson + // && !context.UseSqlite) + // { + // await context.Schools + // .SelectMany(e => e.OpeningHours) + // .Where(e => e.DayOfWeek == DayOfWeek.Friday) + // .ExecuteUpdateAsync(s => s.SetProperty(t => t.OpensAt, t => t.OpensAt!.Value.AddHours(-1))); + // } + + Console.WriteLine(); + } + + private static void PrintSampleName([CallerMemberName] string? methodName = null) + { + Console.WriteLine($">>>> Sample: {methodName}"); + Console.WriteLine(); + } + + public abstract class BritishSchoolsContextBase : DbContext + { + protected BritishSchoolsContextBase(bool useSqlite = false) + { + UseSqlite = useSqlite; + } + + public bool UseSqlite { get; } + public virtual bool UsesJson => false; + public bool LoggingEnabled { get; set; } + + public DbSet Schools => Set(); + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => (UseSqlite + ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") + : optionsBuilder.UseSqlServer( + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0", + sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) + .EnableSensitiveDataLogging() + .LogTo( + s => + { + if (LoggingEnabled) + { + Console.WriteLine(s); + } + }, LogLevel.Information); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + } + + protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) + { + } + + public async Task Seed() + { + AddRange( + new School + { + Name = "Stowe School", + Founded = new(1923, 5, 11), + Terms = + { + new() { Name = "Michaelmas", FirstDay = new(2022, 9, 7), LastDay = new(2022, 12, 16) }, + new() { Name = "Lent", FirstDay = new(2023, 1, 8), LastDay = new(2023, 3, 24) }, + new() { Name = "Summer", FirstDay = new(2023, 4, 18), LastDay = new(2023, 7, 8) } + }, + OpeningHours = + { + new(DayOfWeek.Sunday, null, null), + new(DayOfWeek.Monday, new(8, 00), new(18, 00)), + new(DayOfWeek.Tuesday, new(8, 00), new(18, 00)), + new(DayOfWeek.Wednesday, new(8, 00), new(18, 00)), + new(DayOfWeek.Thursday, new(8, 00), new(18, 00)), + new(DayOfWeek.Friday, new(8, 00), new(18, 00)), + new(DayOfWeek.Saturday, new(8, 00), new(17, 00)) + } + }, + new School + { + Name = "Farr High School", + Founded = new(1964, 5, 1), + Terms = + { + new() { Name = "Autumn", FirstDay = new(2022, 8, 16), LastDay = new(2022, 12, 23) }, + new() { Name = "Winter", FirstDay = new(2023, 1, 9), LastDay = new(2023, 3, 31) }, + new() { Name = "Summer", FirstDay = new(2023, 4, 17), LastDay = new(2023, 6, 29) } + }, + OpeningHours = + { + new(DayOfWeek.Sunday, null, null), + new(DayOfWeek.Monday, new(8, 45), new(15, 35)), + new(DayOfWeek.Tuesday, new(8, 45), new(15, 35)), + new(DayOfWeek.Wednesday, new(8, 45), new(15, 35)), + new(DayOfWeek.Thursday, new(8, 45), new(15, 35)), + new(DayOfWeek.Friday, new(8, 45), new(12, 50)), + new(DayOfWeek.Saturday, null, null) + } + }); + + await SaveChangesAsync(); + } + } + + public class BritishSchoolsContext : BritishSchoolsContextBase + { + } + + public class BritishSchoolsContextJson : BritishSchoolsContextBase + { + + public override bool UsesJson => true; + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().OwnsMany(e => e.OpeningHours).ToJson(); + } + } + + public class BritishSchoolsContextSqlite : BritishSchoolsContextBase + { + public BritishSchoolsContextSqlite() + : base(useSqlite: true) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().OwnsMany( + e => e.OpeningHours, b => + { + b.Property("Id"); + b.HasKey("Id"); + }); + } + } + + public class School + { + public int Id { get; set; } + public string Name { get; set; } = null!; + public DateOnly Founded { get; set; } + public DateTime LastVisited { get; set; } + public TimeSpan LegacyTime { get; set; } + public List Terms { get; } = new(); + public List OpeningHours { get; } = new(); + } + + public class Term + { + public int Id { get; set; } + public string Name { get; set; } = null!; + public DateOnly FirstDay { get; set; } + public DateOnly LastDay { get; set; } + public School School { get; set; } = null!; + } + + [Owned] + public class OpeningHours + { + public OpeningHours(DayOfWeek dayOfWeek, TimeOnly? opensAt, TimeOnly? closesAt) + { + DayOfWeek = dayOfWeek; + OpensAt = opensAt; + ClosesAt = closesAt; + } + + public DayOfWeek DayOfWeek { get; private set; } + public TimeOnly? OpensAt { get; set; } + public TimeOnly? ClosesAt { get; set; } + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj index 1f4c24d2a1..c96a49f1f9 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj @@ -10,15 +10,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9/Program.cs b/samples/core/Miscellaneous/NewInEFCore9/Program.cs index 9f63b9e133..bda58bf996 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/Program.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/Program.cs @@ -7,26 +7,30 @@ public static async Task Main() await PrimitiveCollectionsSample.Queries_using_readonly_primitive_collections(); await PrimitiveCollectionsSample.Queries_using_readonly_primitive_collections_SQLite(); - // await ComplexTypesSample.GropupBy_complex_type_instances(); - // await ComplexTypesSample.GropupBy_complex_type_instances_on_SQLite(); - // - // await QuerySample.Query_improvements_in_EF9(); - // await QuerySample.Query_improvements_in_EF9_on_SQLite(); - // - // // Note that SQL Server 2022 is required for Greater and Least queries. - // // await LeastGreatestSample.Queries_using_Least_and_Greatest(); - // await LeastGreatestSample.Queries_using_Least_and_Greatest_on_SQLite(); - // - // await CustomConventionsSample.Conventions_enhancements_in_EF9(); - // - // await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed(); - // await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed_on_SQLite(); - // - // await ExecuteUpdateSample.ExecuteUpdate_for_complex_type_instances(); - // await ExecuteUpdateSample.ExecuteUpdate_for_complex_type_instances_on_SQLite(); - // - // await HierarchyIdSample.SQL_Server_HierarchyId(); - // - // await ModelBuildingSample.Model_building_improvements_in_EF9(); + await ComplexTypesSample.GropupBy_complex_type_instances(); + await ComplexTypesSample.GropupBy_complex_type_instances_on_SQLite(); + + await QuerySample.Query_improvements_in_EF9(); + await QuerySample.Query_improvements_in_EF9_on_SQLite(); + + // Note that SQL Server 2022 is required for Greater and Least queries. + // await LeastGreatestSample.Queries_using_Least_and_Greatest(); + await LeastGreatestSample.Queries_using_Least_and_Greatest_on_SQLite(); + + await CustomConventionsSample.Conventions_enhancements_in_EF9(); + + await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed(); + await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed_on_SQLite(); + + await ExecuteUpdateSample.ExecuteUpdate_for_complex_type_instances(); + await ExecuteUpdateSample.ExecuteUpdate_for_complex_type_instances_on_SQLite(); + + await HierarchyIdSample.SQL_Server_HierarchyId(); + + await ModelBuildingSample.Model_building_improvements_in_EF9(); + + await DateOnlyTimeOnlySample.Can_use_DateOnly_TimeOnly_on_SQLite(); + await DateOnlyTimeOnlySample.Can_use_DateOnly_TimeOnly_on_SQL_Server(); + await DateOnlyTimeOnlySample.Can_use_DateOnly_TimeOnly_on_SQL_Server_with_JSON(); } } diff --git a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs index 8b855cffc2..a91b67aa55 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs @@ -96,6 +96,16 @@ async Task> GetPostsForceConstant(int id) .Where(p => p.Tags.Count > 3) .ToHashSetAsync(ReferenceEqualityComparer.Instance); #endregion + + Console.WriteLine(); + Console.WriteLine("Normalize Count != 0:"); + Console.WriteLine(); + + #region NormalizeCount + var blogsWithPost = await context.Blogs + .Where(b => b.Posts.Count > 0) + .ToListAsync(); + #endregion } private static void PrintSampleName([CallerMemberName] string? methodName = null) From 2c1f465d48b18b3b5dcdcf3dca994722427c4749 Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Wed, 12 Jun 2024 01:22:02 +0200 Subject: [PATCH 017/224] Add MDS provider readme contents to docs (#4742) --- entity-framework/ef6/what-is-new/index.md | 2 +- .../what-is-new/microsoft-ef6-sqlserver.md | 158 ++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md diff --git a/entity-framework/ef6/what-is-new/index.md b/entity-framework/ef6/what-is-new/index.md index 5e22864a10..a9fd5a2cf3 100644 --- a/entity-framework/ef6/what-is-new/index.md +++ b/entity-framework/ef6/what-is-new/index.md @@ -15,7 +15,7 @@ To install specific versions of EF, see [Get Entity Framework](xref:ef6/fundamen The EF 6.5.0 runtime was released to NuGet in June 2024. The primary goal of EF 6.5 is to include a new SQL Server / Azure SQL Database provider. See [list of important fixes](https://github.com/dotnet/ef6/milestone/17?closed=1) on Github. Here are some of the more notable ones: -- New SQL Server / Azure SQL Database provider (contributed by the community) - [Microsoft.EntityFramework.SqlServer](https://www.nuget.org/packages/Microsoft.EntityFramework.SqlServer/). This new provider uses the modern SQL Server client [Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient). +- New SQL Server / Azure SQL Database provider (contributed by the community) - [Microsoft.EntityFramework.SqlServer](https://www.nuget.org/packages/Microsoft.EntityFramework.SqlServer/). This new provider uses the modern SQL Server client [Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient). For more information about configuration of this provider, see [Microsoft.EntityFramework.SqlServer Guide](xref:ef6/what-is-new/microsoft-ef6-sqlserver). - The `ef6` utility was updated to only support .NET 6 and newer. It was also updated to support reading from app.config files, and support Windows ARM64. - The System.Data.SqlClient driver was updated to version 4.8.6. diff --git a/entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md b/entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md new file mode 100644 index 0000000000..0d7e4b806c --- /dev/null +++ b/entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md @@ -0,0 +1,158 @@ +--- +title: Entity Framework 6 SQL Server provider based on Microsoft.Data.SqlClient +description: Microsoft.EntityFramework.SqlServer guide +author: ajcvickers +ms.date: 06/11/2024 +uid: ef6/what-is-new/microsoft-ef6-sqlserver +--- + +# Entity Framework 6 SQL Server provider based on Microsoft.Data.SqlClient + +This Entity Framework 6 provider is a replacement provider for the built-in SQL Server provider. + +This provider depends on the modern [Microsoft.Data.SqlClient](https://github.com/dotnet/SqlClient) ADO.NET provider, which includes the following advantages over the currently used driver: + +- Current client receiving full support in contrast to `System.Data.SqlClient`, which is in maintenance mode +- Suports new SQL Server features, including support for the SQL Server 2022 enchanced client protocol (TDS8) +- Supports most Azure Active Directory authentication methods +- Supports Always Encrypted with .NET + +Notice that this provider is a runtime only update and will not work with the existing Visual Studio tooling. + +The latest build of this package is available from [NuGet](https://www.nuget.org/packages/Microsoft.EntityFramework.SqlServer) + +## Configuration + +There are various ways to configure Entity Framework to use this provider. + +You can register the provider in code using an attribute: + +````csharp +[DbConfigurationType(typeof(MicrosoftSqlDbConfiguration))] +public class SchoolContext : DbContext +{ + public SchoolContext() : base() + { + } + + public DbSet Students { get; set; } +} +```` +If you have multiple classes inheriting from DbContext in your solution, add the DbConfigurationType attribute to all of them. + +Or you can use the SetConfiguration method before any data access calls: +````csharp + DbConfiguration.SetConfiguration(new MicrosoftSqlDbConfiguration()); +```` +Or add the following lines to your existing derived DbConfiguration class: +````csharp +SetProviderFactory(MicrosoftSqlProviderServices.ProviderInvariantName, Microsoft.Data.SqlClient.SqlClientFactory.Instance); +SetProviderServices(MicrosoftSqlProviderServices.ProviderInvariantName, MicrosoftSqlProviderServices.Instance); +// Optional +SetExecutionStrategy(MicrosoftSqlProviderServices.ProviderInvariantName, () => new MicrosoftSqlAzureExecutionStrategy()); +```` +You can also use App.Config based configuration: + +````xml + + + +
+ + + + + + + + + + + + +```` +If you use App.Config with a .NET 6 or later app, you must remove the `` section above and register the DbProviderFactory in code once: + +````csharp +DbProviderFactories.RegisterFactory(MicrosoftSqlProviderServices.ProviderInvariantName, Microsoft.Data.SqlClient.SqlClientFactory.Instance); +```` + +## EDMX usage + +If you use an EDMX file, update the `Provider` name: + +````xml + + + + +```` + +> In order to use the EDMX file with the Visual Studio designer, you must switch the provider name back to `System.Data.SqlClient` + +Also update the provider name inside the EntityConnection connection string - `provider=Microsoft.Data.SqlClient` + +````xml + +```` + +## Code changes + +To use the provider in an existing solution, a few code changes are required (as needed). + +`using System.Data.SqlClient;` => `using Microsoft.Data.SqlClient;` + +`using Microsoft.SqlServer.Server;` => `using Microsoft.Data.SqlClient.Server;` + +The following classes have been renamed to avoid conflicts with classes that uses `System.Data.SqlClient` in the existing SQL Server provider: + +`SqlAzureExecutionStrategy` => `MicrosoftSqlAzureExecutionStrategy` + +`SqlDbConfiguration` => `MicrosoftSqlDbConfiguration` + +`SqlProviderServices` => `MicrosoftSqlProviderServices` + +`SqlServerMigrationSqlGenerator` => `MicrosoftSqlServerMigrationSqlGenerator` + +`SqlSpatialServices` => `MicrosoftSqlSpatialServices` + +`SqlConnectionFactory` => `MicrosoftSqlConnectionFactory` + +`LocalDbConnectionFactory` => `MicrosoftLocalDbConnectionFactory` + +## Known issues + +**Azure App Service with .NET Framework and connection strings configuration** + +If you use Azure App Service with .NET Framework and the [connection strings configuration feature](https://learn.microsoft.com/azure/app-service/configure-common?tabs=portal#configure-connection-strings), you can encounter runtime issues, as the `ProviderName` connection string setting in this scenario is hardcoded to `System.Data.SqlClient`. + +Solution is to use a derived MicrosoftSqlDbConfiguration class like this: + +```csharp +public class AppServiceConfiguration : MicrosoftSqlDbConfiguration +{ + public AppServiceConfiguration() + { + SetProviderFactory("System.Data.SqlClient", Microsoft.Data.SqlClient.SqlClientFactory.Instance); + SetProviderServices("System.Data.SqlClient", MicrosoftSqlProviderServices.Instance); + SetExecutionStrategy("System.Data.SqlClient", () => new MicrosoftSqlAzureExecutionStrategy()); + } +} +``` + +Then use this derived class in the code-based configuration described above. + +**EntityFramework.dll installed in GAC** + +If an older version of EntityFramework.dll is installed in the .NET Framework GAC (Global Assembly Cache), you might get this error: + +`The 'PrimitiveTypeKind' attribute is invalid - The value 'HierarchyId' is invalid according to its datatype` + +Solution is to remove the .dll from the GAC. EF6 assemblies should never be installed in the GAC. From 304de39b796726f93aa0a1086ba94417d1d25c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Wed, 12 Jun 2024 12:00:39 +0200 Subject: [PATCH 018/224] Documentation about metrics (#4743) --- .openpublishing.redirection.json | 5 ++ .../{event-counters.md => metrics.md} | 90 ++++++++++++++++--- .../advanced-performance-topics.md | 2 +- .../core/performance/performance-diagnosis.md | 6 +- .../core/what-is-new/ef-core-5.0/whatsnew.md | 2 +- entity-framework/toc.yml | 4 +- 6 files changed, 91 insertions(+), 18 deletions(-) rename entity-framework/core/logging-events-diagnostics/{event-counters.md => metrics.md} (58%) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index ddf8a596a4..83e84b0743 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -474,6 +474,11 @@ "source_path": "entity-framework/core/modeling/concurrency.md", "redirect_url": "/ef/core/saving/concurrency", "redirect_document_id": false + }, + { + "source_path": "entity-framework/core/logging-events-diagnostics/event-counters.md", + "redirect_url": "/ef/core/logging-events-diagnostics/metrics", + "redirect_document_id": false } ] } diff --git a/entity-framework/core/logging-events-diagnostics/event-counters.md b/entity-framework/core/logging-events-diagnostics/metrics.md similarity index 58% rename from entity-framework/core/logging-events-diagnostics/event-counters.md rename to entity-framework/core/logging-events-diagnostics/metrics.md index 856712794e..7f275107ff 100644 --- a/entity-framework/core/logging-events-diagnostics/event-counters.md +++ b/entity-framework/core/logging-events-diagnostics/metrics.md @@ -1,12 +1,14 @@ --- -title: Event Counters - EF Core -description: Tracking EF Core performance and diagnosing anomalies with .NET event counters -author: roji -ms.date: 11/17/2020 -uid: core/logging-events-diagnostics/event-counters +title: Metrics - EF Core +description: Tracking EF Core performance and diagnosing anomalies with .NET metrics +author: cincuranet +ms.date: 06/11/2024 +uid: core/logging-events-diagnostics/metrics --- -# Event Counters +# Metrics in EF Core + +## Introduction Entity Framework Core (EF Core) exposes continuous numeric metrics which can provide a good indication of your program's health. These metrics can be used for the following purposes: @@ -14,9 +16,75 @@ Entity Framework Core (EF Core) exposes continuous numeric metrics which can pro * Expose problematic coding practices which can lead to degraded performance * Track down and isolate anomalous program behavior +## Metrics + +EF Core reports metrics via the standard API. `Microsoft.EntityFrameworkCore` is the name of the meter. It's recommended to read [.NET documentation on metrics](/dotnet/core/diagnostics/metrics). + +> [!NOTE] +> This feature is being introduced in EF Core 9.0 (in preview). [See event counters below](#event-counters-legacy) for older versions of EF Core. + +### Metrics and their meaning + +* [`microsoft.entityframeworkcore.active_dbcontexts`](#metric-microsoftentityframeworkcoreactive_dbcontexts) +* [`microsoft.entityframeworkcore.queries`](#metric-microsoftentityframeworkcorequeries) +* [`microsoft.entityframeworkcore.savechanges`](#metric-microsoftentityframeworkcoresavechanges) +* [`microsoft.entityframeworkcore.compiled_query_cache_hit_rate`](#metric-microsoftentityframeworkcorecompiled_query_cache_hit_rate) +* [`microsoft.entityframeworkcore.execution_strategy_operation_failures`](#metric-microsoftentityframeworkcoreexecution_strategy_operation_failures) +* [`microsoft.entityframeworkcore.optimistic_concurrency_failures`](#metric-microsoftentityframeworkcoreoptimistic_concurrency_failures) + +#### Metric: `microsoft.entityframeworkcore.active_dbcontexts` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `microsoft.entityframeworkcore.active_dbcontexts` | ObservableUpDownCounter | `{dbcontext}` | Number of currently active `DbContext` instances. | + +Available starting in: Entity Framework Core 9.0. + +#### Metric: `microsoft.entityframeworkcore.queries` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `microsoft.entityframeworkcore.queries` | ObservableCounter | `{query}` | Cumulative count of queries executed. | + +Available starting in: Entity Framework Core 9.0. + +#### Metric: `microsoft.entityframeworkcore.savechanges` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `microsoft.entityframeworkcore.savechanges` | ObservableCounter | `{savechanges}` | Cumulative count of changes saved. | + +Available starting in: Entity Framework Core 9.0. + +#### Metric: `microsoft.entityframeworkcore.compiled_query_cache_hit_rate` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `microsoft.entityframeworkcore.compiled_query_cache_hit_rate` | ObservableGauge | `%` | Hit rate - since last observation - for the compiled query cache. | + +Available starting in: Entity Framework Core 9.0. + +#### Metric: `microsoft.entityframeworkcore.execution_strategy_operation_failures` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `microsoft.entityframeworkcore.execution_strategy_operation_failures` | ObservableCounter | `{failure}` | Cumulative number of failed operation executed by an `IExecutionStrategy`. | + +Available starting in: Entity Framework Core 9.0. + +#### Metric: `microsoft.entityframeworkcore.optimistic_concurrency_failures` + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `microsoft.entityframeworkcore.optimistic_concurrency_failures` | ObservableCounter | `{failure}` | Cumulative number of optimistic concurrency failures. | + +Available starting in: Entity Framework Core 9.0. + +## Event Counters (legacy) + EF Core reports metrics via the standard .NET event counters feature; it's recommended to read [this blog post](https://devblogs.microsoft.com/dotnet/introducing-diagnostics-improvements-in-net-core-3-0/) for a quick overview of how counters work. -## Attach to a process using dotnet-counters +### Attach to a process using dotnet-counters The [dotnet-counters tool](/dotnet/core/diagnostics/dotnet-counters) can be used to attach to a running process and report EF Core event counters regularly; nothing special needs to be done in the program for these counters to be available. @@ -24,14 +92,14 @@ First, install the `dotnet-counters` tool: `dotnet tool install --global dotnet- Next, find the process ID (PID) of the .NET process running your EF Core application: -### [Windows](#tab/windows) +#### [Windows](#tab/windows) 1. Open the Windows Task Manager by right-clicking on the task bar and selecting "Task Manager". 2. Make sure that the "More details" option is selected at the bottom of the window. 3. In the Processes tab, right-click a column and make sure that the PID column is enabled. 4. Locate your application in the process list, and get its process ID from the PID column. -### [Linux or macOS](#tab/fluent-api) +#### [Linux or macOS](#tab/fluent-api) 1. Use the `ps` command to list all processes running for your user. 2. Locate your application in the process list, and get its process ID from the PID column. @@ -65,7 +133,7 @@ Press p to pause, r to resume, q to quit. SaveChanges (Total) 0 ``` -## Counters and their meaning +### Counters and their meaning Counter name | Description -------------------------------------------------------------------------------- | ---- @@ -76,6 +144,6 @@ Queries
(`total-queries` and `queries-per-second`) Query Cache Hit Rate (%)
(`compiled-query-cache-hit-rate`) | The ratio of query cache hits to misses. The first time a given LINQ query is executed by EF Core (excluding parameters), it must be compiled in what is a relatively heavy process. In a normal application, all queries are reused, and the query cache hit rate should be stable at 100% after an initial warmup period. If this number is less than 100% over time, you may experience degraded perf due to repeated compilations, which could be a result of suboptimal dynamic query generation. SaveChanges
(`total-save-changes` and `save-changes-per-second`) | The number of times `SaveChanges` has been called. Note that `SaveChanges` saves multiple changes in a single batch, so this doesn't necessarily represent each individual update done on a single entity. -## Additional resources +### Additional resources * [.NET documentation on event counters](/dotnet/core/diagnostics/event-counters) diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index 6dee1cb2ad..9bd4516206 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -144,7 +144,7 @@ WHERE [b].[Name] = @__postTitle_0 Note that there is no need to parameterize each and every query: it's perfectly fine to have some queries with constants, and indeed, databases (and EF) can sometimes perform certain optimization around constants which aren't possible when the query is parameterized. See the section on [dynamically-constructed queries](#dynamically-constructed-queries) for an example where proper parameterization is crucial. > [!NOTE] -> EF Core's [event counters](xref:core/logging-events-diagnostics/event-counters) report the Query Cache Hit Rate. In a normal application, this counter reaches 100% soon after program startup, once most queries have executed at least once. If this counter remains stable below 100%, that is an indication that your application may be doing something which defeats the query cache - it's a good idea to investigate that. +> EF Core's [metrics](xref:core/logging-events-diagnostics/metrics) report the Query Cache Hit Rate. In a normal application, this metric reaches 100% soon after program startup, once most queries have executed at least once. If this metric remains stable below 100%, that is an indication that your application may be doing something which defeats the query cache - it's a good idea to investigate that. > [!NOTE] > How the database manages caches query plans is database-dependent. For example, SQL Server implicitly maintains an LRU query plan cache, whereas PostgreSQL does not (but prepared statements can produce a very similar end effect). Consult your database documentation for more details. diff --git a/entity-framework/core/performance/performance-diagnosis.md b/entity-framework/core/performance/performance-diagnosis.md index 05741022af..09492fac7b 100644 --- a/entity-framework/core/performance/performance-diagnosis.md +++ b/entity-framework/core/performance/performance-diagnosis.md @@ -81,11 +81,11 @@ While the above information is specific to SQL Server, other databases typically > [!IMPORTANT] > Databases sometimes generate different query plans depending on actual data in the database. For example, if a table contains only a few rows, a database may choose not to use an index on that table, but to perform a full table scan instead. If analyzing query plans on a test database, always make sure it contains data that is similar to your production system. -## Event counters +## Metrics -The above sections focused on how to get information about your commands, and how these commands are executed in the database. In addition to that, EF exposes a set of *event counters* which provide more lower-level information on what's happening inside EF itself, and how your application is using it. These counters can be very useful for diagnosing specific performance issues and performance anomalies, such as [query caching issues](xref:core/performance/advanced-performance-topics#dynamically-constructed-queries) which cause constant recompilation, undisposed DbContext leaks, and others. +The above sections focused on how to get information about your commands, and how these commands are executed in the database. In addition to that, EF exposes a set of *metrics* which provide more lower-level information on what's happening inside EF itself, and how your application is using it. These metrics can be very useful for diagnosing specific performance issues and performance anomalies, such as [query caching issues](xref:core/performance/advanced-performance-topics#dynamically-constructed-queries) which cause constant recompilation, undisposed DbContext leaks, and others. -See the dedicated page on [EF's event counters](xref:core/logging-events-diagnostics/event-counters) for more information. +See the dedicated page on [EF's metrics](xref:core/logging-events-diagnostics/metrics) for more information. ## Benchmarking with EF Core diff --git a/entity-framework/core/what-is-new/ef-core-5.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-5.0/whatsnew.md index a25fbdd259..4b39c417f6 100644 --- a/entity-framework/core/what-is-new/ef-core-5.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-5.0/whatsnew.md @@ -309,7 +309,7 @@ EF Core 5.0 exposes [event counters](https://devblogs.microsoft.com/dotnet/intro SaveChanges (Total) 1 ``` -For further information, [see the full documentation on event counters](xref:core/logging-events-diagnostics/event-counters). +For further information, [see the full documentation on event counters](xref:core/logging-events-diagnostics/metrics#event-counters-legacy). ## Other features diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index 5bade783fe..557be098a4 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -326,8 +326,8 @@ - name: Diagnostic listeners href: core/logging-events-diagnostics/diagnostic-listeners.md #- name: Debug views - - name: Event counters - href: core/logging-events-diagnostics/event-counters.md + - name: Metrics + href: core/logging-events-diagnostics/metrics.md - name: Testing items: From 0231603912c0481eecb4d105db468bbeac09a373 Mon Sep 17 00:00:00 2001 From: Jay Patel <117800195+JayPatel-Tandem@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:18:58 +0530 Subject: [PATCH 019/224] Update one-to-many.md for a small grammar mistake (#4748) A sentence was grammatically wrong in this document. --- entity-framework/core/modeling/relationships/one-to-many.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/modeling/relationships/one-to-many.md b/entity-framework/core/modeling/relationships/one-to-many.md index 28ee9a89e5..0e3d163336 100644 --- a/entity-framework/core/modeling/relationships/one-to-many.md +++ b/entity-framework/core/modeling/relationships/one-to-many.md @@ -463,7 +463,7 @@ This relationship is not discovered by convention, since EF will always, by conv ## One-to-many with composite foreign key -In all the examples so far, the primary or alternate key property of the principal consisted of a single property. Primary or alternate keys can also be formed form more than one property--these are known as ["composite keys"](xref:core/modeling/keys). When the principal of a relationship has a composite key, then the foreign key of the dependent must also be a composite key with the same number of properties. For example: +In all the examples so far, the primary or alternate key property of the principal consisted of a single property. Primary or alternate keys can also be formed from more than one property--these are known as ["composite keys"](xref:core/modeling/keys). When the principal of a relationship has a composite key, then the foreign key of the dependent must also be a composite key with the same number of properties. For example: +[!code-csharp[PatIndexExample](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=PatIndexExample)] + +The result translates directly into `PATINDEX` function on SQL Server: + +```sql +SELECT [p].[Id], PATINDEX(N'%.NET%', [p].[Content]) AS [Index] +FROM [Posts] AS [p] +``` + +This enhancement was contributed by [@smnsht](https://github.com/smnsht). Many thanks! + +### Added translation for `ToString()` on enums + +In EF9 we enabled translation of `ToString()` on an enum. It translates to a `CASE` block listing all the enum values. Below is an example of a query that uses pattern matching on the the enum names: + + +[!code-csharp[EnumToString](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=EnumToString)] + +This translates to the following query on SQL Server: + +```sql +SELECT [b].[Name] +FROM [Blogs] AS [b] +WHERE CASE [b].[Language] + WHEN 0 THEN N'English' + WHEN 1 THEN N'MandarinChinese' + WHEN 2 THEN N'Hindi' + WHEN 3 THEN N'Spanish' + WHEN 4 THEN N'French' + WHEN 5 THEN N'ModernStandardArabic' + WHEN 6 THEN N'Other' + ELSE CAST([b].[Language] AS nvarchar(max)) +END LIKE N'%ish' +``` + +This enhancement was contributed by [@Danevandy99](https://github.com/Danevandy99). Many thanks! + +### Added support for `Sum` and `Average` for decimal on Sqlite + +In EF9 it is possible to perform sum and average aggregation on decimal values using Sqlite database. A query below lists all blogs along with an average rating of all their posts: + + +[!code-csharp[AverageOnDecimal](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=AverageOnDecimal)] + +This translates to the following SQL on Sqlite: + +```sql +SELECT "b"."Name", ( + SELECT ef_avg("p"."Rating") + FROM "Posts" AS "p" + WHERE "b"."Id" = "p"."BlogId") AS "AveragePostRating" +FROM "Blogs" AS "b" +``` + +This enhancement was contributed by [@ranma42](https://github.com/ranma42). Many thanks! + +### C# semantics for comparison operations on nullable values + +In EF8 comparisons between nullable elements were not performed correctly for some scenarios. In C#, if one or both operands are null, the result of a comparison operation is false; otherwise, the contained values of operands are compared. In EF8 we used to translate comparisons using database null semantics. This would produce results different than similar query using Linq to Objects. +Moreover, we would produce different results when comparison was done in filter vs projection. Some queris would also produce differet results between Sql Server and Sqlite/Postgres. + +For example, the query: + + +[!code-csharp[NegatedNullableComparisonFilter](../../../../samples/core/Miscellaneous/NewInEFCore9/NullSemanticsSample.cs?name=NegatedNullableComparisonFilter)] + +would generate the following SQL: + +```sql +SELECT [e].[NullableIntOne], [e].[NullableIntTwo] +FROM [Entities] AS [e] +WHERE NOT ([e].[NullableIntOne] > [e].[NullableIntTwo]) +``` + +which filters out entities whose `NullableIntOne` or `NullableIntTwo` are set to null. + +In EF9 we produce: + +```sql +SELECT [e].[NullableIntOne], [e].[NullableIntTwo] +FROM [Entities] AS [e] +WHERE CASE + WHEN [e].[NullableIntOne] > [e].[NullableIntTwo] THEN CAST(0 AS bit) + ELSE CAST(1 AS bit) +END = CAST(1 AS bit) +``` + +Similar comparison performed in a projection: + + +[!code-csharp[NegatedNullableComparisonProjection](../../../../samples/core/Miscellaneous/NewInEFCore9/NullSemanticsSample.cs?name=NegatedNullableComparisonProjection)] + +resulted in the following SQL: + +```sql +SELECT [e].[NullableIntOne], [e].[NullableIntTwo], CASE + WHEN NOT ([e].[NullableIntOne] > [e].[NullableIntTwo]) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [Operation] +FROM [Entities] AS [e] +``` + +which returns `false` for entities whose `NullableIntOne` or `NullableIntTwo` are set to null (rather than `true` expected in C#). Running the same scenario on Sqlite generated: + +```sql +SELECT "e"."NullableIntOne", "e"."NullableIntTwo", NOT ("e"."NullableIntOne" > "e"."NullableIntTwo") AS "Operation" +FROM "Entities" AS "e" +``` + +which results in `Nullable object must have a value` exception, as translation produces `null` value for cases where `NullableIntOne` or `NullableIntTwo` are null. + +EF9 now properly handles these scenarios, producing results consistent with Linq to Objects and across different providers. + +This enhancement was contributed by [@ranma42](https://github.com/ranma42). Many thanks! + +### Improved translation of logical negation operator (!) + +In EF9 we improved translation of some queries using logical negation. + +Here is an example of a query affected by these changes, specifically when using Sqlite: + + +[!code-csharp[NegatedContainsImprovements](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=NegatedContainsImprovements)] + +In EF8 we would produce the following query: + +```sql +SELECT "p"."Content" +FROM "Posts" AS "p" +WHERE NOT (instr("p"."Content", 'Announcing') > 0) +``` + +In EF9 we "push" `NOT` operation into the comparison: + +```sql +SELECT "p"."Content" +FROM "Posts" AS "p" +WHERE instr("p"."Content", 'Announcing') <= 0 +``` + +Another example, applicable to SQL Server, is a negated conditional operation. + + +[!code-csharp[CaseTranslationImprovements](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=CaseTranslationImprovements)] + +In EF8 used to result in nested `CASE` blocks: + +```sql +SELECT CASE + WHEN CASE + WHEN [b].[Id] > 5 THEN CAST(0 AS bit) + ELSE CAST(1 AS bit) + END = CAST(0 AS bit) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Blogs] AS [b] +``` + +In EF9 we removed the nesting: + +```sql +SELECT CASE + WHEN [b].[Id] > 5 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END +FROM [Blogs] AS [b] +``` + +On SQL Server, when projecting a negated bool property: + + +[!code-csharp[XorBoolProjection](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=XorBoolProjection)] + + EF8 would generate a `CASE` block because comparisons can't appear in the projection directly in SQL Server queries: + + ```sql +SELECT [p].[Title], CASE + WHEN [p].[Archived] = CAST(0 AS bit) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [Active] +FROM [Posts] AS [p] + ``` + + In EF9 this translation has been simplified and now uses exclusive or (`^`): + +```sql +SELECT [p].[Title], [p].[Archived] ^ CAST(1 AS bit) AS [Active] +FROM [Posts] AS [p] +``` + +These enhancements were contributed by [@ranma42](https://github.com/ranma42). Many thanks! + +### Improved translation for Contains used with HashSet and other collection types + +In EF8 we introduced support for primitive collections and changed how [some queries using primitive collection parameters are translated](xref:core/what-is-new/ef-core-8.0/whatsnew#queries-with-primitive-collections). In EF9 we extended this to support all `ICollection` types. + +> [NOTE!] +> This only applies to primitive collection parameters and inline collections. Primitive collections that are part of entities are still limited to arrays, lists and [in EF9 also read-only arrays/lists](#read-only-primitive-collections). + +### `Convert.To*` methods can now accept argument of type `object` + +In EF8 passing a parameter of type object to one of the methods on `System.Convert` class (e.g. `Convert.ToDouble`) would result in a translation error. In EF9 we allow converting from `object`: + + +[!code-csharp[ConvertFromObject](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=ConvertFromObject)] + +These enhancements were contributed by [@imangd](https://github.com/imangd). Many thanks! + ## ExecuteUpdate and ExecuteDelete @@ -1145,51 +1399,6 @@ INNER JOIN "Pubs" AS "p" ON "w"."ClosestPubId" = "p"."Id" -### Specify caching for sequences - -> [!TIP] -> The code shown here comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs). - -EF9 allows setting the [caching options for database sequences](/sql/t-sql/statements/create-sequence-transact-sql) for any relational database provider that supports this. For example, `UseCache` can be used to explicitly turn on caching and set the cache size: - - -[!code-csharp[UseCache](../../../../samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs?name=UseCache)] - -This results in the following sequence definition when using SQL Server: - -```sql -CREATE SEQUENCE [MyCachedSequence] AS int START WITH 11 INCREMENT BY 2 MINVALUE 10 MAXVALUE 255000 CYCLE CACHE 3; -``` - -Similarly, `UseNoCache` explicitly turns off caching: - - -[!code-csharp[UseNoCache](../../../../samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs?name=UseNoCache)] - -```sql -CREATE SEQUENCE [MyUncachedSequence] AS int START WITH 11 INCREMENT BY 2 MINVALUE 10 MAXVALUE 255000 CYCLE NO CACHE; -``` - -If neither `UseCache` or `UseNoCache` are called, then caching is not specified and the database will use whatever its default is. This may be a different default for different databases. - -This enhancement was contributed by [@bikbov](https://github.com/bikbov). Many thanks! - - - ### Specify fill-factor for keys and indexes > [!TIP] diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj index 8accd90c2f..785143a414 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj @@ -9,7 +9,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj index a877bb1332..af0deefb2e 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj @@ -15,13 +15,13 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj index 4a5031a626..f74ca111e6 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/NewInEFCore9/BlogsContext.cs b/samples/core/Miscellaneous/NewInEFCore9/BlogsContext.cs index 27f45592d4..b88e3baa71 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/BlogsContext.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/BlogsContext.cs @@ -13,11 +13,25 @@ public Blog(string name) public int Id { get; private set; } public string Name { get; set; } + public Language Language { get; set; } + public virtual Uri SiteUri { get; set; } = null!; public virtual Website Site { get; set; } = null!; public virtual List Posts { get; } = new(); } + +public enum Language +{ + English, + MandarinChinese, + Hindi, + Spanish, + French, + ModernStandardArabic, + Other, +} + public class Website { public Website(Uri uri, string email) @@ -34,11 +48,12 @@ public Website(Uri uri, string email) public class Post { - public Post(string title, string content, DateOnly publishedOn) + public Post(string title, string content, DateOnly publishedOn, decimal rating) { Title = title; Content = content; PublishedOn = publishedOn; + Rating = rating; } public int Id { get; private set; } @@ -47,6 +62,7 @@ public Post(string title, string content, DateOnly publishedOn) public DateOnly PublishedOn { get; set; } public bool Archived { get; set; } public int BlogId { get; set; } + public decimal Rating { get; set; } public virtual Blog Blog { get; set; } = null!; public virtual List Tags { get; } = new(); public virtual Author? Author { get; set; } @@ -55,8 +71,8 @@ public Post(string title, string content, DateOnly publishedOn) public class FeaturedPost : Post { - public FeaturedPost(string title, string content, DateOnly publishedOn, string promoText) - : base(title, content, publishedOn) + public FeaturedPost(string title, string content, DateOnly publishedOn, decimal rating, string promoText) + : base(title, content, publishedOn, rating) { PromoText = promoText; } @@ -299,13 +315,16 @@ public async Task Seed() new Post( "Productivity comes to .NET MAUI in Visual Studio 2022", "Visual Studio 2022 17.3 is now available and...", - new DateOnly(2022, 8, 9)) { Tags = { tagDotNetMaui, tagDotNet }, Author = maddy, Metadata = BuildPostMetadata() }, + new DateOnly(2022, 8, 9), + 4.0M) { Tags = { tagDotNetMaui, tagDotNet }, Author = maddy, Metadata = BuildPostMetadata() }, new Post( "Announcing .NET 7 Preview 7", ".NET 7 Preview 7 is now available with improvements to System.LINQ, Unix...", - new DateOnly(2022, 8, 9)) { Tags = { tagDotNet }, Author = jeremy, Metadata = BuildPostMetadata() }, + new DateOnly(2022, 8, 9), + 4.2M) { Tags = { tagDotNet }, Author = jeremy, Metadata = BuildPostMetadata() }, new Post( "ASP.NET Core updates in .NET 7 Preview 7", ".NET 7 Preview 7 is now available! Check out what's new in...", - new DateOnly(2022, 8, 9)) + new DateOnly(2022, 8, 9), + 4.1M) { Tags = { tagDotNet, tagAspDotNet, tagAspDotNetCore }, Author = dan, Metadata = BuildPostMetadata() }, @@ -313,12 +332,14 @@ public async Task Seed() "Announcing Entity Framework 7 Preview 7: Interceptors!", "Announcing EF7 Preview 7 with new and improved interceptors, and...", new DateOnly(2022, 8, 9), + 4.5M, "Loads of runnable code!") { Tags = { tagEntityFramework, tagDotNet, tagDotNetCore }, Author = arthur, Metadata = BuildPostMetadata() } }, - Site = new(new("https://devblogs.microsoft.com/dotnet/"), "dotnet@example.com") + Site = new(new("https://devblogs.microsoft.com/dotnet/"), "dotnet@example.com"), + Language = Language.English, }, new("1unicorn2") { @@ -327,20 +348,25 @@ public async Task Seed() new Post( "Hacking my Sixth Form College network in 1991", "Back in 1991 I was a student at Franklin Sixth Form College...", - new DateOnly(2020, 4, 10)) { Tags = { tagHacking }, Author = arthur, Metadata = BuildPostMetadata() }, + new DateOnly(2020, 4, 10), + 4.5M) { Tags = { tagHacking }, Author = arthur, Metadata = BuildPostMetadata() }, new FeaturedPost( "All your versions are belong to us", "Totally made up conversations about choosing Entity Framework version numbers...", new DateOnly(2020, 3, 26), + 3.9M, "Way funny!") { Tags = { tagEntityFramework }, Author = arthur, Metadata = BuildPostMetadata() }, new Post( "Moving to Linux", "A few weeks ago, I decided to move from Windows to Linux as...", - new DateOnly(2020, 3, 7)) { Tags = { tagLinux }, Author = arthur, Metadata = BuildPostMetadata(), Archived = true }, + new DateOnly(2020, 3, 7), + 3.5M) { Tags = { tagLinux }, Author = arthur, Metadata = BuildPostMetadata(), Archived = true }, new Post( "Welcome to One Unicorn 2.0!", "I created my first blog back in 2011..", - new DateOnly(2020, 2, 29)) { Tags = { tagEntityFramework }, Author = arthur, Metadata = BuildPostMetadata() } + new DateOnly(2020, 2, 29), + 4.8M) { Tags = { tagEntityFramework }, Author = arthur, Metadata = BuildPostMetadata() } }, - Site = new(new("https://blog.oneunicorn.com/"), "unicorn@example.com") + Site = new(new("https://blog.oneunicorn.com/"), "unicorn@example.com"), + Language = Language.English, }, new("Brice's Blog") { @@ -348,25 +374,29 @@ public async Task Seed() { new FeaturedPost( "SQLite in Visual Studio 2022", "A couple of years ago, I was thinking of ways...", - new DateOnly(2022, 7, 26), "Love for VS!") + new DateOnly(2022, 7, 26), 4.5M, "Love for VS!") { Tags = { tagSqlite, tagVisualStudio }, Author = brice, Metadata = BuildPostMetadata() }, new Post( "On .NET - Entity Framework Migrations Explained", "This week, @JamesMontemagno invited me onto the On .NET show...", - new DateOnly(2022, 5, 4)) + new DateOnly(2022, 5, 4), + 4.7M) { Tags = { tagEntityFramework, tagDotNet }, Author = brice, Metadata = BuildPostMetadata() }, new Post( "Dear DBA: A silly idea", "We have fun on the Entity Framework team...", - new DateOnly(2022, 3, 31)) { Tags = { tagEntityFramework }, Author = brice, Metadata = BuildPostMetadata(), Archived = true }, + new DateOnly(2022, 3, 31), + 3.5M) { Tags = { tagEntityFramework }, Author = brice, Metadata = BuildPostMetadata(), Archived = true }, new Post( "Microsoft.Data.Sqlite 6", "It’s that time of year again. Microsoft.Data.Sqlite version...", - new DateOnly(2021, 11, 8)) { Tags = { tagSqlite, tagDotNet }, Author = brice, Metadata = BuildPostMetadata() } + new DateOnly(2021, 11, 8), + 4.2M) { Tags = { tagSqlite, tagDotNet }, Author = brice, Metadata = BuildPostMetadata() } }, - Site = new(new("https://www.bricelam.net/"), "brice@example.com") + Site = new(new("https://www.bricelam.net/"), "brice@example.com"), + Language = Language.English, }, new("Developer for Life") { @@ -374,7 +404,7 @@ public async Task Seed() { new Post( "GraphQL for .NET Developers", "A comprehensive overview of GraphQL as...", - new DateOnly(2021, 7, 1)) + new DateOnly(2021, 7, 1), 4.1M) { Tags = { tagDotNet, tagGraphQl, tagAspDotNetCore }, Author = jeremy, Metadata = BuildPostMetadata() }, @@ -382,6 +412,7 @@ public async Task Seed() "Azure Cosmos DB With EF Core on Blazor Server", "Learn how to build Azure Cosmos DB apps using Entity Framework Core...", new DateOnly(2021, 5, 16), + 4.5M, "Blazor FTW!") { Tags = @@ -398,7 +429,8 @@ public async Task Seed() new Post( "Multi-tenancy with EF Core in Blazor Server Apps", "Learn several ways to implement multi-tenant databases in Blazor Server apps...", - new DateOnly(2021, 4, 29)) + new DateOnly(2021, 4, 29), + 3.8M) { Tags = { tagDotNet, tagEntityFramework, tagAspDotNetCore, tagBlazor }, Author = jeremy, @@ -406,13 +438,15 @@ public async Task Seed() }, new Post( "An Easier Blazor Debounce", "Where I propose a simple method to debounce input without...", - new DateOnly(2021, 4, 12)) + new DateOnly(2021, 4, 12), + 4.5M) { Tags = { tagDotNet, tagAspDotNetCore, tagBlazor }, Author = jeremy, Metadata = BuildPostMetadata() } }, - Site = new(new("https://blog.jeremylikness.com/"), "jeremy@example.com") - } + Site = new(new("https://blog.jeremylikness.com/"), "jeremy@example.com"), + Language = Language.English, + } }; await AddRangeAsync(blogs); diff --git a/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs b/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs index 487cc5ea22..5555917b6a 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs @@ -56,22 +56,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .HasFillFactor(80); #endregion - #region UseCache - modelBuilder.HasSequence("MyCachedSequence") - .HasMin(10).HasMax(255000) - .IsCyclic() - .StartsAt(11).IncrementsBy(2) - .UseCache(3); - #endregion - - #region UseNoCache - modelBuilder.HasSequence("MyUncachedSequence") - .HasMin(10).HasMax(255000) - .IsCyclic() - .StartsAt(11).IncrementsBy(2) - .UseNoCache(); - #endregion - #region DefaultCache modelBuilder.HasSequence("MySequence") .HasMin(10).HasMax(255000) diff --git a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj index c96a49f1f9..227f11b250 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj @@ -10,15 +10,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9/NullSemanticsSample.cs b/samples/core/Miscellaneous/NewInEFCore9/NullSemanticsSample.cs new file mode 100644 index 0000000000..7285911c3d --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore9/NullSemanticsSample.cs @@ -0,0 +1,156 @@ +namespace NewInEfCore9; + +public static class NullSemanticsSample +{ + public static Task Null_semantics_improvements_in_EF9() + { + PrintSampleName(); + return NullSemanticsInComparisonTest(); + } + + public static Task Null_semantics_improvements_in_EF9_on_SQLite() + { + PrintSampleName(); + return NullSemanticsInComparisonTest(); + } + + private static async Task NullSemanticsInComparisonTest() + where TContext : NullSemanticsContextBase, new() + { + await using var context = new TContext(); + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); + await context.Seed(); + + context.LoggingEnabled = true; + context.ChangeTracker.Clear(); + + Console.WriteLine(); + Console.WriteLine("C# null semantics for comparison operators:"); + Console.WriteLine(); + + #region NegatedNullableComparisonFilter + var negatedNullableComparisonFilter = await context.Entities + .Where(x => !(x.NullableIntOne > x.NullableIntTwo)) + .Select(x => new { x.NullableIntOne, x.NullableIntTwo }).ToListAsync(); + #endregion + + var negatedNullableComparisonFilterL2O = context.Entities.AsEnumerable().Where(x => !(x.NullableIntOne > x.NullableIntTwo)).Select(x => new { x.NullableIntOne, x.NullableIntTwo }).ToList(); + + #region NullableComparisonProjection + var nullableComparisonProjection = await context.Entities.Select(x => new + { + x.NullableIntOne, + x.NullableIntTwo, + Operation = x.NullableIntOne > x.NullableIntTwo + }).ToListAsync(); + #endregion + + var nullableComparisonProjectionL2O = context.Entities.AsEnumerable().Select(x => new { x.NullableIntOne, x.NullableIntTwo, Operation = x.NullableIntOne > x.NullableIntTwo }).ToList(); + + #region NegatedNullableComparisonProjection + var negatedNullableComparisonProjection = await context.Entities.Select(x => new + { + x.NullableIntOne, + x.NullableIntTwo, + Operation = !(x.NullableIntOne > x.NullableIntTwo) + }).ToListAsync(); + #endregion + + var negatedNullableComparisonProjectionL2O = context.Entities.AsEnumerable().Select(x => new { x.NullableIntOne, x.NullableIntTwo, Operation = !(x.NullableIntOne > x.NullableIntTwo) }).ToList(); + } + + private static void PrintSampleName([CallerMemberName] string? methodName = null) + { + Console.WriteLine($">>>> Sample: {methodName}"); + Console.WriteLine(); + } + + public class NullSemanticsEntity + { + public int Id { get; set; } + + public int? NullableIntOne { get; set; } + public int? NullableIntTwo { get; set; } + public bool? NullableBoolOne { get; set; } + public bool? NullableBoolTwo { get; set; } + + public int Int { get; set; } + public bool BoolOne { get; set;} + public bool BoolTwo { get; set; } + + } + + public class NullSemanticsContext : NullSemanticsContextBase + { + } + + public class NullSemanticsContextSqlite : NullSemanticsContextBase + { + public NullSemanticsContextSqlite() + : base(useSqlite: true) + { + } + } + + public abstract class NullSemanticsContextBase : DbContext + { + protected NullSemanticsContextBase(bool useSqlite = false) + { + UseSqlite = useSqlite; + } + + public bool UseSqlite { get; } + public bool LoggingEnabled { get; set; } + + public DbSet Entities => Set(); + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => (UseSqlite + ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") + : optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={GetType().Name};ConnectRetryCount=0")) + .EnableSensitiveDataLogging() + .LogTo( + s => + { + if (LoggingEnabled) + { + Console.WriteLine(s); + } + }, LogLevel.Information); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever(); + } + + public async Task Seed() + { + var entities = new List(); + (int? Int, bool? Bool)[] data = [ (1, true), (2, false), (null, null) ]; + + var k = 0; + for (var i = 0; i < data.Length; i++) + { + for (var j = 0; j < data.Length; j++) + { + k++; + entities.Add(new NullSemanticsEntity + { + Id = k, + NullableBoolOne = data[i].Bool, + NullableBoolTwo = data[j].Bool, + NullableIntOne = data[i].Int, + NullableIntTwo = data[j].Int, + BoolOne = data[k % 2].Bool!.Value, + BoolTwo = data[(k + 1) % 2].Bool!.Value, + Int = data[k % 2].Int!.Value, + }); + } + } + + await AddRangeAsync(entities); + await SaveChangesAsync(); + } + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs b/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs index c050e002e3..3811e2715e 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs @@ -308,7 +308,7 @@ public async Task Seed() Booleans = new() { true, false, true }, Urls = new() { new("https://127.0.0.1/"), new("http://192.168.0.1/"), new("https://devblogs.microsoft.com/dotnet/") }, SomeInts = new() { 1, 2, 3 }, - DddIds = new() { new(1), new(2), new(3) } + DddIds = new() { new(1), new(2), new(3) }, }); var oak = new Pub("The Royal Oak", new[] { "Oakham", "Carling", "Guinness", "John Smiths", "Bathams", "Tennents" }); diff --git a/samples/core/Miscellaneous/NewInEFCore9/Program.cs b/samples/core/Miscellaneous/NewInEFCore9/Program.cs index bda58bf996..181190ccbf 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/Program.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/Program.cs @@ -4,6 +4,7 @@ public class Program { public static async Task Main() { + await PrimitiveCollectionsSample.Queries_using_readonly_primitive_collections(); await PrimitiveCollectionsSample.Queries_using_readonly_primitive_collections_SQLite(); @@ -17,6 +18,9 @@ public static async Task Main() // await LeastGreatestSample.Queries_using_Least_and_Greatest(); await LeastGreatestSample.Queries_using_Least_and_Greatest_on_SQLite(); + await NullSemanticsSample.Null_semantics_improvements_in_EF9(); + await NullSemanticsSample.Null_semantics_improvements_in_EF9_on_SQLite(); + await CustomConventionsSample.Conventions_enhancements_in_EF9(); await JsonColumnsSample.Columns_from_JSON_are_pruned_when_needed(); diff --git a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs index a91b67aa55..b9dea7fb9c 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs @@ -106,6 +106,56 @@ async Task> GetPostsForceConstant(int id) .Where(b => b.Posts.Count > 0) .ToListAsync(); #endregion + + if (!context.UseSqlite) + { + #region PatIndexExample + var patIndexExample = await context.Posts.Select(p => new + { + p.Id, + Index = EF.Functions.PatIndex("%.NET%", p.Content) + }).ToListAsync(); + #endregion + } + + #region CaseTranslationImprovements + var caseSimplification = await context.Blogs + .Select(b => !(b.Id > 5 ? false : true)) + .ToListAsync(); + #endregion + + if (context.UseSqlite) + { + #region NegatedContainsImprovements + var negatedContainsSimplification = await context.Posts + .Where(p => !p.Content.Contains("Announcing")) + .Select(p => new { p.Content }).ToListAsync(); + #endregion + } + + #region XorBoolProjection + var negatedBoolProjection = await context.Posts.Select(x => new { x.Title, Active = !x.Archived }).ToListAsync(); + #endregion + + #region EnumToString + var englishAndSpanishBlogs = await context.Blogs + .Where(x => x.Language.ToString().EndsWith("ish")) + .Select(x => x.Name).ToListAsync(); + #endregion + + #region AverageOnDecimal + var averagePostRating = await context.Blogs.Select(x => new + { + x.Name, + AveragePostRating = x.Posts.Average(xx => xx.Rating) + }).ToListAsync(); + #endregion + + #region ConvertFromObject + var blogWithConversion = await context.Blogs + .Where(x => Convert.ToDecimal((object)Convert.ToString(x.Id)) == 1.0M) + .ToListAsync(); + #endregion } private static void PrintSampleName([CallerMemberName] string? methodName = null) From 1b3057741419bd57b6044e2f5694a43ae82270e8 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Fri, 20 Sep 2024 13:47:19 -0700 Subject: [PATCH 035/224] Add missing page to ToC (#4810) Update title for Advanced Performance Topics Reference the released rc1 Fix or suppress warnings --- .../performance/advanced-performance-topics.md | 2 +- entity-framework/toc.yml | 2 ++ .../CommandLine/Properties/launchSettings.json | 12 ++++++++++++ .../Properties/launchSettings.json | 12 ++++++++++++ .../MultiDb/Properties/launchSettings.json | 12 ++++++++++++ .../Properties/launchSettings.json | 12 ++++++++++++ .../NewInEFCore9.CompiledModels/App/App.csproj | 2 +- .../Model/Model.csproj | 8 ++++---- .../CosmosSyncApisSample.cs | 10 ++++++++-- .../HierarchicalPartitionKeysSample.cs | 1 - .../NewInEFCore9.Cosmos.csproj | 2 +- .../NewInEFCore9/NewInEFCore9.csproj | 18 +++++++++--------- .../NewInEFCore9/PrimitiveCollectionsSample.cs | 2 +- .../Properties/launchSettings.json | 12 ++++++++++++ .../Properties/launchSettings.json | 12 ++++++++++++ samples/core/Querying/SqlQueries/Program.cs | 1 + .../Properties/launchSettings.json | 12 ++++++++++++ .../Properties/launchSettings.json | 12 ++++++++++++ 18 files changed, 124 insertions(+), 20 deletions(-) create mode 100644 samples/core/Miscellaneous/CommandLine/Properties/launchSettings.json create mode 100644 samples/core/Miscellaneous/ConfiguringDbContext/Properties/launchSettings.json create mode 100644 samples/core/Miscellaneous/Multitenancy/MultiDb/Properties/launchSettings.json create mode 100644 samples/core/Miscellaneous/Multitenancy/SingleDbSingleTable/Properties/launchSettings.json create mode 100644 samples/core/Performance/AspNetContextPooling/Properties/launchSettings.json create mode 100644 samples/core/Performance/AspNetContextPoolingWithState/Properties/launchSettings.json create mode 100644 samples/core/Schemas/ThreeProjectMigrations/WebApplication1/Properties/launchSettings.json create mode 100644 samples/core/Testing/BloggingWebApi/Properties/launchSettings.json diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index 9bd4516206..164759812c 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -1,5 +1,5 @@ --- -title: Advanced Performance Topics +title: Advanced Performance Topics - EF Core description: Advanced performance topics for Entity Framework Core author: roji ms.date: 9/26/2023 diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index 4ac3399f45..38d9a2c077 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -21,6 +21,8 @@ href: efcore-and-ef6/porting/port-database.md - name: Porting to a hybrid model href: efcore-and-ef6/porting/port-hybrid.md + - name: Behavior Changes between EF6 and EF Core + href: efcore-and-ef6/porting/port-behavior.md - name: Detailed cases to consider when Porting href: efcore-and-ef6/porting/port-detailed-cases.md - name: Use EF6 and EF Core in the same application diff --git a/samples/core/Miscellaneous/CommandLine/Properties/launchSettings.json b/samples/core/Miscellaneous/CommandLine/Properties/launchSettings.json new file mode 100644 index 0000000000..b26cc61c35 --- /dev/null +++ b/samples/core/Miscellaneous/CommandLine/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "CommandLine": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58213;http://localhost:58218" + } + } +} \ No newline at end of file diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/Properties/launchSettings.json b/samples/core/Miscellaneous/ConfiguringDbContext/Properties/launchSettings.json new file mode 100644 index 0000000000..a2507be0b6 --- /dev/null +++ b/samples/core/Miscellaneous/ConfiguringDbContext/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "ConfiguringDbContext": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58221;http://localhost:58223" + } + } +} \ No newline at end of file diff --git a/samples/core/Miscellaneous/Multitenancy/MultiDb/Properties/launchSettings.json b/samples/core/Miscellaneous/Multitenancy/MultiDb/Properties/launchSettings.json new file mode 100644 index 0000000000..0ae2ccadcf --- /dev/null +++ b/samples/core/Miscellaneous/Multitenancy/MultiDb/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "MultiDb": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58210;http://localhost:58219" + } + } +} \ No newline at end of file diff --git a/samples/core/Miscellaneous/Multitenancy/SingleDbSingleTable/Properties/launchSettings.json b/samples/core/Miscellaneous/Multitenancy/SingleDbSingleTable/Properties/launchSettings.json new file mode 100644 index 0000000000..d273faadba --- /dev/null +++ b/samples/core/Miscellaneous/Multitenancy/SingleDbSingleTable/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "SingleDbSingleTable": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58209;http://localhost:58217" + } + } +} \ No newline at end of file diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj index 785143a414..d0893b1f77 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/App/App.csproj @@ -9,7 +9,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj index af0deefb2e..66c2064a9a 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/Model/Model.csproj @@ -15,13 +15,13 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs index 0c90397a22..5a19643cdc 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs @@ -93,13 +93,19 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder + { + optionsBuilder = optionsBuilder .ConfigureWarnings(b => b.Log(CosmosEventId.SyncNotSupported)) - .LogTo(Console.WriteLine, LogLevel.Information) .EnableSensitiveDataLogging() .UseCosmos( "https://localhost:8081/", "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", "Triangles"); + + if (!quiet) + { + optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information); + } + } } } diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs index b99ba2b865..e4448501e0 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs @@ -137,7 +137,6 @@ public static async Task UseHierarchicalPartitionKeys() using (var context = new UserSessionContext()) { - var tenantId = "Microsoft"; var sessionId = 7; var userId = new Guid("99A410D7-E467-4CC5-92DE-148F3FC53F4C"); diff --git a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj index f74ca111e6..0e4ad15bea 100644 --- a/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9.Cosmos/NewInEFCore9.Cosmos.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj index 227f11b250..39476a1f38 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj +++ b/samples/core/Miscellaneous/NewInEFCore9/NewInEFCore9.csproj @@ -10,15 +10,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs b/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs index 3811e2715e..1667738a16 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs @@ -176,7 +176,7 @@ public DogWalk(string name) public int Id { get; set; } public string Name { get; set; } public Terrain Terrain { get; set; } - public ReadOnlyCollection DaysVisited { get; set; } + public required ReadOnlyCollection DaysVisited { get; set; } public Pub ClosestPub { get; set; } = null!; } diff --git a/samples/core/Performance/AspNetContextPooling/Properties/launchSettings.json b/samples/core/Performance/AspNetContextPooling/Properties/launchSettings.json new file mode 100644 index 0000000000..0bd72ebfd6 --- /dev/null +++ b/samples/core/Performance/AspNetContextPooling/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "AspNetContextPooling": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58220;http://localhost:58222" + } + } +} \ No newline at end of file diff --git a/samples/core/Performance/AspNetContextPoolingWithState/Properties/launchSettings.json b/samples/core/Performance/AspNetContextPoolingWithState/Properties/launchSettings.json new file mode 100644 index 0000000000..2892dcf901 --- /dev/null +++ b/samples/core/Performance/AspNetContextPoolingWithState/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "AspNetContextPoolingWithState": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58214;http://localhost:58216" + } + } +} \ No newline at end of file diff --git a/samples/core/Querying/SqlQueries/Program.cs b/samples/core/Querying/SqlQueries/Program.cs index 520309a877..a13001a60b 100644 --- a/samples/core/Querying/SqlQueries/Program.cs +++ b/samples/core/Querying/SqlQueries/Program.cs @@ -4,6 +4,7 @@ namespace EFQuerying.RawSQL; +#pragma warning disable EF1002 // Risk of vulnerability to SQL injection. internal class Program { private static void Main(string[] args) diff --git a/samples/core/Schemas/ThreeProjectMigrations/WebApplication1/Properties/launchSettings.json b/samples/core/Schemas/ThreeProjectMigrations/WebApplication1/Properties/launchSettings.json new file mode 100644 index 0000000000..4ea55d68cb --- /dev/null +++ b/samples/core/Schemas/ThreeProjectMigrations/WebApplication1/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "WebApplication1": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58211;http://localhost:58215" + } + } +} \ No newline at end of file diff --git a/samples/core/Testing/BloggingWebApi/Properties/launchSettings.json b/samples/core/Testing/BloggingWebApi/Properties/launchSettings.json new file mode 100644 index 0000000000..117c7b9765 --- /dev/null +++ b/samples/core/Testing/BloggingWebApi/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "BloggingWebApi": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:58208;http://localhost:58212" + } + } +} \ No newline at end of file From 83c994ed31ffcc7b5eab1e2cc449a597d9010598 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sun, 22 Sep 2024 15:18:35 +0200 Subject: [PATCH 036/224] Remove the empty "EF 9.0 plan" page (#4811) --- entity-framework/core/what-is-new/ef-core-9.0/plan.md | 11 ----------- entity-framework/toc.yml | 4 ---- 2 files changed, 15 deletions(-) delete mode 100644 entity-framework/core/what-is-new/ef-core-9.0/plan.md diff --git a/entity-framework/core/what-is-new/ef-core-9.0/plan.md b/entity-framework/core/what-is-new/ef-core-9.0/plan.md deleted file mode 100644 index 4da73b27cf..0000000000 --- a/entity-framework/core/what-is-new/ef-core-9.0/plan.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Plan for Entity Framework Core 9 -description: The themes and features planned for EF Core 9 -author: ajcvickers -ms.date: 12/01/2023 -uid: core/what-is-new/ef-core-9.0/plan ---- - -# Plan for Entity Framework Core 9 - -Coming soon... diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index 38d9a2c077..aa4fe15a08 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -36,8 +36,6 @@ href: core/what-is-new/ef-core-8.0/whatsnew.md - name: "Breaking changes in EF Core 8.0" href: core/what-is-new/ef-core-8.0/breaking-changes.md - - name: "The plan for EF Core 9.0" - href: core/what-is-new/ef-core-9.0/plan.md - name: Getting started items: - name: EF Core Overview @@ -68,8 +66,6 @@ href: core/what-is-new/release-planning.md - name: EF Core 9.0 items: - - name: High-level plan - href: core/what-is-new/ef-core-9.0/plan.md - name: "What's new?" href: core/what-is-new/ef-core-9.0/whatsnew.md - name: Breaking changes From 56a59109e323dcb8cf480980797bddf850159dc2 Mon Sep 17 00:00:00 2001 From: Henri Nieminen Date: Mon, 23 Sep 2024 09:17:06 +0200 Subject: [PATCH 037/224] Fix incorrect halfling name in HierarchyId example (#4813) --- entity-framework/core/providers/sql-server/hierarchyid.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/providers/sql-server/hierarchyid.md b/entity-framework/core/providers/sql-server/hierarchyid.md index 3177fc98c8..aed1634ec3 100644 --- a/entity-framework/core/providers/sql-server/hierarchyid.md +++ b/entity-framework/core/providers/sql-server/hierarchyid.md @@ -94,7 +94,7 @@ In this tree: - Balbo is at the root of the tree, represented by `/`. - Balbo has five children, represented by `/1/`, `/2/`, `/3/`, `/4/`, and `/5/`. -- Balbo's first child, Mungo, also has five children, represented by `/1/1/`, `/1/2/`, `/1/3/`, `/1/4/`, and `/1/5/`. Notice that the `HierarchyId` for Balbo (`/1/`) is the prefix for all his children. +- Balbo's first child, Mungo, also has five children, represented by `/1/1/`, `/1/2/`, `/1/3/`, `/1/4/`, and `/1/5/`. Notice that the `HierarchyId` for Mungo (`/1/`) is the prefix for all his children. - Similarly, Balbo's third child, Ponto, has two children, represented by `/3/1/` and `/3/2/`. Again the each of these children is prefixed by the `HierarchyId` for Ponto, which is represented as `/3/`. - And so on down the tree... From 348c59586deab5cfba9829c4330d8962df0baeb7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 23 Sep 2024 23:44:52 +0200 Subject: [PATCH 038/224] Improvements to 9.0 what's new section on translations/SQL (#4814) --- .../core/what-is-new/ef-core-9.0/whatsnew.md | 497 ++++++------------ .../Miscellaneous/NewInEFCore9/QuerySample.cs | 9 +- 2 files changed, 160 insertions(+), 346 deletions(-) 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 80105540bd..7422428c78 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 @@ -350,11 +350,17 @@ Check back here for examples of how to use pre-compiled queries as the experienc ## LINQ and SQL translation -The team is working on some significant architecture changes to the query pipeline in EF Core 9 as part of our continued improvements to JSON mapping and document databases. This means we need to get **people like you** to run your code on these new internals. (If you're reading a "What's New" doc at this point in the release, then you're a really engaged part of the community; thank you!) We have over 120,000 tests, but it's not enough! We need you, people running real code on our bits, in order to find issues and ship a solid release! +Like with every release, EF9 includes a large number of improvements to the LINQ querying capabilities. New queries can be translated, and many SQL translations for supported scenarios have been improved, for both better performance and readability. - +The number of improvements is too great to list them all here. Below, some of the more important improvements are highlighted; see [this issue](https://github.com/dotnet/efcore/issues/34151) for a more complete listing of the work done in 9.0. -### GroupBy complex types +We'd like to call out Andrea Canciani ([@ranma42](https://github.com/ranma42)) for his numerous, high-quality contributions to optimizing the SQL that gets generated by EF Core! + + + +### Complex types: GroupBy and ExecuteUpdate support + +#### GroupBy > [!TIP] > The code shown here comes from [ComplexTypesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs). @@ -377,81 +383,145 @@ FROM [Stores] AS [s] GROUP BY [s].[StoreAddress_City], [s].[StoreAddress_Country], [s].[StoreAddress_Line1], [s].[StoreAddress_Line2], [s].[StoreAddress_PostCode] ``` - - -### Prune columns passed to OPENJSON's WITH clause +#### ExecuteUpdate > [!TIP] -> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/JsonColumnsSample.cs). +> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs). -EF9 removes unnecessary columns when calling `OPENJSON WITH`. For example, consider a query that obtains a count from a JSON collection using a predicate: +Similarly, in EF9 `ExecuteUpdate` has also been improved to accept complex type properties. However, each member of the complex type must be specified explicitly. For example: -[!code-csharp[PruneJSON](../../../../samples/core/Miscellaneous/NewInEFCore9/JsonColumnsSample.cs?name=PruneJSON)] +[!code-csharp[UpdateComplexType](../../../../samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs?name=UpdateComplexType)] -In EF8, this query generates the following SQL when using the Azure SQL database provider: +This generates SQL that updates each column mapped to the complex type: ```sql -SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata] -FROM [Posts] AS [p] -WHERE ( - SELECT COUNT(*) - FROM OPENJSON([p].[Metadata], '$.Updates') WITH ( - [PostedFrom] nvarchar(45) '$.PostedFrom', - [UpdatedBy] nvarchar(max) '$.UpdatedBy', - [UpdatedOn] date '$.UpdatedOn', - [Commits] nvarchar(max) '$.Commits' AS JSON - ) AS [u] - WHERE [u].[UpdatedOn] >= @__date_0) = 1 +UPDATE [s] +SET [s].[StoreAddress_City] = @__complex_type_newAddress_0_City, + [s].[StoreAddress_Country] = @__complex_type_newAddress_0_Country, + [s].[StoreAddress_Line1] = @__complex_type_newAddress_0_Line1, + [s].[StoreAddress_Line2] = NULL, + [s].[StoreAddress_PostCode] = @__complex_type_newAddress_0_PostCode +FROM [Stores] AS [s] +WHERE [s].[Region] = N'Germany' +``` + +Previously, you had to manually list out the different properties of the complex type in your `ExecuteUpdate` call. + + + +### Prune unneeded elements from SQL + +Previously, EF sometimes produced SQL which contained elements that weren't actually needed; in most cases, these were possibly needed at an earlier stage of SQL processing, and were left behind. EF9 now prunes most such elements, resulting in more compact and, in some cases, more efficient SQL. + +#### Table pruning + +As a first example, the SQL generated by EF sometimes contained JOINs to tables which weren't actually needed in the query. Consider the following model, which uses [table-per-type (TPT) inheritance mapping](xref:core/modeling/inheritance#table-per-type-configuration): + +```csharp +public class Order +{ + public int Id { get; set; } + ... + + public Customer Customer { get; set; } +} + +public class DiscountedOrder : Order +{ + public double Discount { get; set; } +} + +public class Customer +{ + public int Id { get; set; } + ... + + public List Orders { get; set; } +} + +public class BlogContext : DbContext +{ + ... + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().UseTptMappingStrategy(); + } +} ``` -Notice that the `UpdatedBy`, and `Commits` are not needed in this query. Starting with EF9, these columns are now pruned away: +If we then execute the following query to get all Customers with at least one Order: + +```csharp +var customers = await context.Customers.Where(o => o.Orders.Any()).ToListAsync(); +``` + +EF8 generated the following SQL: ```sql -SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata] -FROM [Posts] AS [p] -WHERE ( - SELECT COUNT(*) - FROM OPENJSON([p].[Metadata], '$.Updates') WITH ( - [PostedFrom] nvarchar(45) '$.PostedFrom', - [UpdatedOn] date '$.UpdatedOn' - ) AS [u] - WHERE [u].[UpdatedOn] >= @__date_0) = 1 +SELECT [c].[Id], [c].[Name] +FROM [Customers] AS [c] +WHERE EXISTS ( + SELECT 1 + FROM [Orders] AS [o] + LEFT JOIN [DiscountedOrders] AS [d] ON [o].[Id] = [d].[Id] + WHERE [c].[Id] = [o].[CustomerId]) ``` -In some scenarios, this results in complete removal of the `WITH` clause. For example: +Note that the query contained a join to the `DiscountedOrders` table even though no columns were referenced on it. EF9 generates a pruned SQL without the join: - -[!code-csharp[PruneJSONPrimitive](../../../../samples/core/Miscellaneous/NewInEFCore9/JsonColumnsSample.cs?name=PruneJSONPrimitive)] +```c# +SELECT [c].[Id], [c].[Name] +FROM [Customers] AS [c] +WHERE EXISTS ( + SELECT 1 + FROM [Orders] AS [o] + WHERE [c].[Id] = [o].[CustomerId]) +``` + +#### Projection pruning -In EF8, this query translates to the following SQL: +Similarly, let's examine the following query: + +```csharp +var orders = await context.Orders + .Where(o => o.Amount > 10) + .Take(5) + .CountAsync(); +``` + +On EF8, this query generated the following SQL: ```sql -SELECT [t].[Id], [t].[Text] -FROM [Tags] AS [t] -WHERE ( - SELECT COUNT(*) - FROM OPENJSON([t].[Text]) WITH ([value] nvarchar(max) '$') AS [t0]) = 1 +SELECT COUNT(*) +FROM ( + SELECT TOP(@__p_0) [o].[Id] + FROM [Orders] AS [o] + WHERE [o].[Amount] > 10 +) AS [t] ``` -In EF9, this has been improved to: +Note that the `[o].[Id]` projection isn't needed in the subquery, since the outer SELECT expression simply counts the rows. EF9 generates the following instead: ```sql -SELECT [t].[Id], [t].[Text] -FROM [Tags] AS [t] -WHERE ( - SELECT COUNT(*) - FROM OPENJSON([t].[Text]) AS [t0]) = 1 +SELECT COUNT(*) +FROM ( + SELECT TOP(@__p_0) 1 AS empty + FROM [Orders] AS [o] + WHERE [o].[Amount] > 10 +) AS [s] ``` +... and the projection is empty. This may not seem like much, but it can significantly simplify the SQL in some cases; you're welcome to scroll through some of the [SQL changes in the tests](https://github.com/dotnet/efcore/pull/32672/files#diff-95664269d9a59fe9627612bf1d3e1704e76f6065e329edeecd14a8bf436db058L4011) to see the effect. + ### Translations involving GREATEST/LEAST @@ -543,8 +613,7 @@ Except in some special cases, EF Core parameterizes variables used in a LINQ que #region DefaultParameterization async Task> GetPosts(int id) => await context.Posts - .Where( - e => e.Title == ".NET Blog" && e.Id == id) + .Where(e => e.Title == ".NET Blog" && e.Id == id) .ToListAsync(); --> [!code-csharp[DefaultParameterization](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=DefaultParameterization)] @@ -552,16 +621,15 @@ Except in some special cases, EF Core parameterizes variables used in a LINQ que This translates to the following SQL and parameters when using Azure SQL: ```output -info: 2/5/2024 15:43:13.789 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) - Executed DbCommand (1ms) [Parameters=[@__id_0='1'], CommandType='Text', CommandTimeout='30'] - SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata] - FROM [Posts] AS [p] - WHERE [p].[Title] = N'.NET Blog' AND [p].[Id] = @__id_0 +Executed DbCommand (1ms) [Parameters=[@__id_0='1'], CommandType='Text', CommandTimeout='30'] +SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata] +FROM [Posts] AS [p] +WHERE [p].[Title] = N'.NET Blog' AND [p].[Id] = @__id_0 ``` Notice that EF created a constant in the SQL for ".NET Blog" because this value will not change from query to query. Using a constant allows this value to be examined by the database engine when creating a query plan, potentially resulting in a more efficient query. -On the other hand, the value of `id` is parameterized, since the same query may be executed with many different values for `id`. Creating a constant in this case results in pollution of the query cache with lots of queries that differ only in parameter values. This is very bad for overall performance of the database. +On the other hand, the value of `id` is parameterized, since the same query may be executed with many different values for `id`. Creating a constant in this case would result in pollution of the query cache with lots of queries that differ only in `id` values. This is very bad for overall performance of the database. Generally speaking, these defaults should not be changed. However, EF Core 8.0.2 introduces an `EF.Constant` method which forces EF to use a constant even if a parameter would be used by default. For example: @@ -569,8 +637,7 @@ Generally speaking, these defaults should not be changed. However, EF Core 8.0.2 #region ForceConstant async Task> GetPostsForceConstant(int id) => await context.Posts - .Where( - e => e.Title == ".NET Blog" && e.Id == EF.Constant(id)) + .Where(e => e.Title == ".NET Blog" && e.Id == EF.Constant(id)) .ToListAsync(); --> [!code-csharp[ForceConstant](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=ForceConstant)] @@ -578,11 +645,10 @@ Generally speaking, these defaults should not be changed. However, EF Core 8.0.2 The translation now contains a constant for the `id` value: ```output -info: 2/5/2024 15:43:13.812 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) - Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] - SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata] - FROM [Posts] AS [p] - WHERE [p].[Title] = N'.NET Blog' AND [p].[Id] = 1 +Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] +SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata] +FROM [Posts] AS [p] +WHERE [p].[Title] = N'.NET Blog' AND [p].[Id] = 1 ``` EF9 introduces the `EF.Parameter` method to do the opposite. That is, force EF to use a parameter even if the value is a constant in code. For example: @@ -591,8 +657,7 @@ EF9 introduces the `EF.Parameter` method to do the opposite. That is, force EF t #region ForceParameter async Task> GetPostsForceParameter(int id) => await context.Posts - .Where( - e => e.Title == EF.Parameter(".NET Blog") && e.Id == id) + .Where(e => e.Title == EF.Parameter(".NET Blog") && e.Id == id) .ToListAsync(); --> [!code-csharp[ForceParameter](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=ForceParameter)] @@ -600,11 +665,10 @@ EF9 introduces the `EF.Parameter` method to do the opposite. That is, force EF t The translation now contains a parameter for the ".NET Blog" string: ```output -info: 2/5/2024 15:43:13.803 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) - Executed DbCommand (1ms) [Parameters=[@__p_0='.NET Blog' (Size = 4000), @__id_1='1'], CommandType='Text', CommandTimeout='30'] - SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata] - FROM [Posts] AS [p] - WHERE [p].[Title] = @__p_0 AND [p].[Id] = @__id_1 +Executed DbCommand (1ms) [Parameters=[@__p_0='.NET Blog' (Size = 4000), @__id_1='1'], CommandType='Text', CommandTimeout='30'] +SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata] +FROM [Posts] AS [p] +WHERE [p].[Title] = @__p_0 AND [p].[Id] = @__id_1 ``` @@ -644,7 +708,7 @@ ORDER BY (SELECT 1) OFFSET @__p_1 ROWS FETCH NEXT @__p_2 ROWS ONLY ``` -In EF9, the `IQueryable` in the `dotnetPosts` is inlined, resulting in a single round trip: +In EF9, the `IQueryable` in the `dotnetPosts` is inlined, resulting in a single database round trip: ```sql SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Title], [p].[PromoText], [p].[Metadata], ( @@ -659,27 +723,6 @@ OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY -### New `ToHashSetAsync` methods - -> [!TIP] -> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). - -The methods have existed since .NET Core 2.0. In EF9, the equivalent async methods have been added. For example: - - -[!code-csharp[ToHashSetAsync](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=ToHashSetAsync)] - -This enhancement was contributed by [@wertzui](https://github.com/wertzui). Many thanks! - ### Queries using Count != 0 are optimized > [!TIP] @@ -705,111 +748,9 @@ WHERE EXISTS ( WHERE "b"."Id" = "p"."BlogId") ``` -### More `TimeOnly` methods are translated for Azure SQL/SQL Server - -> [!TIP] -> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). - -Queries using and are now translated when using SQL Server or Azure SQL. For example, the following LINQ query uses `FromDateTime` to extract the time-of-day value from a column and compare it to a `TimeOnly` value passed in: - - -[!code-csharp[FromDateTime](../../../../samples/core/Miscellaneous/NewInEFCore9/DateOnlyTimeOnlySample.cs?name=FromDateTime)] - -This is translated to the following when using SQL Azure or SQL Server: - -```sql -SELECT [s].[Id], [s].[Founded], [s].[LastVisited], [s].[LegacyTime], [s].[Name], [s].[OpeningHours] -FROM [Schools] AS [s] -WHERE CAST([s].[LastVisited] AS time) >= @__visitedTime_0 -``` - -`FromTimeSpan` is translated in a similar manner. - -### Added translation for `PATINDEX` function on SQL Server - -We added support for PATINDEX function on SQL Server which returns the starting position of the first occurrence of a pattern in a specified expression. The function can be accessed in the following way: - - -[!code-csharp[PatIndexExample](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=PatIndexExample)] - -The result translates directly into `PATINDEX` function on SQL Server: - -```sql -SELECT [p].[Id], PATINDEX(N'%.NET%', [p].[Content]) AS [Index] -FROM [Posts] AS [p] -``` - -This enhancement was contributed by [@smnsht](https://github.com/smnsht). Many thanks! - -### Added translation for `ToString()` on enums - -In EF9 we enabled translation of `ToString()` on an enum. It translates to a `CASE` block listing all the enum values. Below is an example of a query that uses pattern matching on the the enum names: - - -[!code-csharp[EnumToString](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=EnumToString)] - -This translates to the following query on SQL Server: - -```sql -SELECT [b].[Name] -FROM [Blogs] AS [b] -WHERE CASE [b].[Language] - WHEN 0 THEN N'English' - WHEN 1 THEN N'MandarinChinese' - WHEN 2 THEN N'Hindi' - WHEN 3 THEN N'Spanish' - WHEN 4 THEN N'French' - WHEN 5 THEN N'ModernStandardArabic' - WHEN 6 THEN N'Other' - ELSE CAST([b].[Language] AS nvarchar(max)) -END LIKE N'%ish' -``` - -This enhancement was contributed by [@Danevandy99](https://github.com/Danevandy99). Many thanks! - -### Added support for `Sum` and `Average` for decimal on Sqlite - -In EF9 it is possible to perform sum and average aggregation on decimal values using Sqlite database. A query below lists all blogs along with an average rating of all their posts: - - -[!code-csharp[AverageOnDecimal](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=AverageOnDecimal)] - -This translates to the following SQL on Sqlite: - -```sql -SELECT "b"."Name", ( - SELECT ef_avg("p"."Rating") - FROM "Posts" AS "p" - WHERE "b"."Id" = "p"."BlogId") AS "AveragePostRating" -FROM "Blogs" AS "b" -``` - -This enhancement was contributed by [@ranma42](https://github.com/ranma42). Many thanks! - ### C# semantics for comparison operations on nullable values -In EF8 comparisons between nullable elements were not performed correctly for some scenarios. In C#, if one or both operands are null, the result of a comparison operation is false; otherwise, the contained values of operands are compared. In EF8 we used to translate comparisons using database null semantics. This would produce results different than similar query using Linq to Objects. +In EF8 comparisons between nullable elements were not performed correctly for some scenarios. In C#, if one or both operands are null, the result of a comparison operation is false; otherwise, the contained values of operands are compared. In EF8 we used to translate comparisons using database null semantics. This would produce results different than similar query using LINQ to Objects. Moreover, we would produce different results when comparison was done in filter vs projection. Some queris would also produce differet results between Sql Server and Sqlite/Postgres. For example, the query: @@ -873,15 +814,15 @@ FROM "Entities" AS "e" which results in `Nullable object must have a value` exception, as translation produces `null` value for cases where `NullableIntOne` or `NullableIntTwo` are null. -EF9 now properly handles these scenarios, producing results consistent with Linq to Objects and across different providers. +EF9 now properly handles these scenarios, producing results consistent with LINQ to Objects and across different providers. This enhancement was contributed by [@ranma42](https://github.com/ranma42). Many thanks! ### Improved translation of logical negation operator (!) -In EF9 we improved translation of some queries using logical negation. +EF9 brings many optimizimations around SQL `CASE/WHEN`, `COALESCE`, negation, and various other constructs; most of these were contributed by Andrea Canciani ([@ranma42](https://github.com/ranma42)) - many thanks for all of these! Below, we'll detail just a few of these optimizations around logical negation. -Here is an example of a query affected by these changes, specifically when using Sqlite: +Let's examine the following query: [!code-csharp[NegatedContainsImprovements](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=NegatedContainsImprovements)] -In EF8 we would produce the following query: +In EF8 we would produce the following SQL: ```sql SELECT "p"."Content" @@ -955,150 +896,26 @@ END AS [Active] FROM [Posts] AS [p] ``` - In EF9 this translation has been simplified and now uses exclusive or (`^`): +In EF9 this translation has been simplified and now uses exclusive or (`^`): ```sql SELECT [p].[Title], [p].[Archived] ^ CAST(1 AS bit) AS [Active] FROM [Posts] AS [p] ``` -These enhancements were contributed by [@ranma42](https://github.com/ranma42). Many thanks! - -### Improved translation for Contains used with HashSet and other collection types - -In EF8 we introduced support for primitive collections and changed how [some queries using primitive collection parameters are translated](xref:core/what-is-new/ef-core-8.0/whatsnew#queries-with-primitive-collections). In EF9 we extended this to support all `ICollection` types. - -> [NOTE!] -> This only applies to primitive collection parameters and inline collections. Primitive collections that are part of entities are still limited to arrays, lists and [in EF9 also read-only arrays/lists](#read-only-primitive-collections). - -### `Convert.To*` methods can now accept argument of type `object` - -In EF8 passing a parameter of type object to one of the methods on `System.Convert` class (e.g. `Convert.ToDouble`) would result in a translation error. In EF9 we allow converting from `object`: - - -[!code-csharp[ConvertFromObject](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=ConvertFromObject)] - -These enhancements were contributed by [@imangd](https://github.com/imangd). Many thanks! - -## ExecuteUpdate and ExecuteDelete - - - -### Allow passing complex type instances to ExecuteUpdate - -> [!TIP] -> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs). +### Other query improvements -The `ExecuteUpdate` API was introduced in EF7 to perform immediate, direct updates to the database without tracking or `SaveChanges`. For example: +- The primitive collections querying support [introduced in EF8](xref:core/what-is-new/ef-core-8.0/whatsnew#queries-with-primitive-collections) has been extended to support all `ICollection` types. Note that this applies only to parameter and inline collections - primitive collections that are part of entities are still limited to arrays, lists and [in EF9 also read-only arrays/lists](#read-only-primitive-collections). +- New `ToHashSetAsync` functions to return the results of a query as a `HashSet` ([#30033](https://github.com/dotnet/efcore/issues/30033), contributed by [@wertzui](https://github.com/wertzui)). +- `TimeOnly.FromDateTime` and `FromTimeSpan` are now translated on SQL Server ([#33678](https://github.com/dotnet/efcore/issues/33678)). +- `ToString` over enums is now translated ([#33706](https://github.com/dotnet/efcore/pull/33706), contributed by [@Danevandy99](https://github.com/Danevandy99)). +- `string.Join` now translates to [CONCAT_WS](/sql/t-sql/functions/concat-ws-transact-sql) in non-aggregate context on SQL Server ([#28899](https://github.com/dotnet/efcore/issues/28899)). +- `EF.Functions.PatIndex` now translates to the SQL Server [`PATINDEX`](/sql/t-sql/functions/patindex-transact-sql) function, which returns the starting position of the first occurrence of a pattern ([#33702](https://github.com/dotnet/efcore/issues/33702), [@smnsht](https://github.com/smnsht)). +- `Sum` and `Average` now work for decimals on SQLite ([#33721](https://github.com/dotnet/efcore/pull/33721), contributed by [@ranma42](https://github.com/ranma42)). +- Fixes and optimizations to `string.StartsWith` and `EndsWith` ([#31482](https://github.com/dotnet/efcore/pull/31482)). +- `Convert.To*` methods can now accept argument of type `object` ([#33891](https://github.com/dotnet/efcore/pull/33891), contributed by [@imangd](https://github.com/imangd)). - -[!code-csharp[NormalExecuteUpdate](../../../../samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs?name=NormalExecuteUpdate)] - -Running this code executes the following query to update the `Region` to "Deutschland": - -```sql -UPDATE [s] -SET [s].[Region] = N'Deutschland' -FROM [Stores] AS [s] -WHERE [s].[Region] = N'Germany' -``` - -In EF8 `ExecuteUpdate` can also be used to update values of complex type properties. However, each member of the complex type must be specified explicitly. For example: - - -[!code-csharp[UpdateComplexTypeByMember](../../../../samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs?name=UpdateComplexTypeByMember)] - -Running this code results in the following query execution: - -```sql -UPDATE [s] -SET [s].[StoreAddress_PostCode] = @__newAddress_PostCode_4, - [s].[StoreAddress_Country] = @__newAddress_Country_3, - [s].[StoreAddress_City] = @__newAddress_City_2, - [s].[StoreAddress_Line2] = NULL, - [s].[StoreAddress_Line1] = @__newAddress_Line1_0 -FROM [Stores] AS [s] -WHERE [s].[Region] = N'Deutschland' -``` - -In EF9, the same update can be performed by passing the complex type instance itself. That is, each member does not need to be explicitly specified. For example: - - -[!code-csharp[UpdateComplexType](../../../../samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs?name=UpdateComplexType)] - -Running this code results in the same query execution as the previous example: - -```sql -UPDATE [s] -SET [s].[StoreAddress_City] = @__complex_type_newAddress_0_City, - [s].[StoreAddress_Country] = @__complex_type_newAddress_0_Country, - [s].[StoreAddress_Line1] = @__complex_type_newAddress_0_Line1, - [s].[StoreAddress_Line2] = NULL, - [s].[StoreAddress_PostCode] = @__complex_type_newAddress_0_PostCode -FROM [Stores] AS [s] -WHERE [s].[Region] = N'Germany' -``` - -Multiple updates to both complex type properties and simple properties can be combined in a single call to `ExecuteUpdate`. For example: - - -[!code-csharp[UpdateMultipleComplexType](../../../../samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs?name=UpdateMultipleComplexType)] - -Running this code results in the same query execution as the previous example: - -```sql -UPDATE [c] -SET [c].[CustomerInfo_Tag] = N'Tog', - [c].[CustomerInfo_HomeAddress_City] = N'Beetley', - [c].[CustomerInfo_HomeAddress_Country] = N'Norfolk', - [c].[CustomerInfo_HomeAddress_Line1] = N'Gressenhall Farm', - [c].[CustomerInfo_HomeAddress_Line2] = NULL, - [c].[CustomerInfo_HomeAddress_PostCode] = N'NR20 4DR', - [c].[CustomerInfo_WorkAddress_City] = N'Beetley', - [c].[CustomerInfo_WorkAddress_Country] = N'Norfolk', - [c].[CustomerInfo_WorkAddress_Line1] = N'Gressenhall Workhouse', - [c].[CustomerInfo_WorkAddress_Line2] = NULL, - [c].[CustomerInfo_WorkAddress_PostCode] = N'NR20 4DR' -FROM [Customers] AS [c] -WHERE [c].[Name] = @__name_0 -``` +The above were only some of the more important query improvements in EF9; see [this issue](https://github.com/dotnet/efcore/issues/34151) for a more complete listing. ## Migrations diff --git a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs index b9dea7fb9c..0b6c434026 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs @@ -34,8 +34,7 @@ private static async Task QueryTest() #region DefaultParameterization async Task> GetPosts(int id) => await context.Posts - .Where( - e => e.Title == ".NET Blog" && e.Id == id) + .Where(e => e.Title == ".NET Blog" && e.Id == id) .ToListAsync(); #endregion @@ -48,8 +47,7 @@ async Task> GetPosts(int id) #region ForceParameter async Task> GetPostsForceParameter(int id) => await context.Posts - .Where( - e => e.Title == EF.Parameter(".NET Blog") && e.Id == id) + .Where(e => e.Title == EF.Parameter(".NET Blog") && e.Id == id) .ToListAsync(); #endregion @@ -62,8 +60,7 @@ async Task> GetPostsForceParameter(int id) #region ForceConstant async Task> GetPostsForceConstant(int id) => await context.Posts - .Where( - e => e.Title == ".NET Blog" && e.Id == EF.Constant(id)) + .Where(e => e.Title == ".NET Blog" && e.Id == EF.Constant(id)) .ToListAsync(); #endregion From c8923aa582122024f3ca239defa9b51840df0e6c Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Tue, 24 Sep 2024 20:06:03 -0600 Subject: [PATCH 039/224] Bequeath my articles to Sam (#4815) I'm just trying to reduce GitHub notification noise. Please still feel free to at-mention me with any questions. --- entity-framework/core/cli/dbcontext-creation.md | 2 +- entity-framework/core/cli/dotnet.md | 2 +- entity-framework/core/cli/index.md | 2 +- entity-framework/core/cli/powershell.md | 2 +- entity-framework/core/cli/services.md | 2 +- entity-framework/core/get-started/overview/install.md | 2 +- entity-framework/core/managing-schemas/ensure-created.md | 2 +- entity-framework/core/managing-schemas/index.md | 2 +- entity-framework/core/managing-schemas/migrations/applying.md | 2 +- .../core/managing-schemas/migrations/history-table.md | 2 +- entity-framework/core/managing-schemas/migrations/index.md | 2 +- entity-framework/core/managing-schemas/migrations/managing.md | 2 +- entity-framework/core/managing-schemas/migrations/operations.md | 2 +- entity-framework/core/managing-schemas/migrations/projects.md | 2 +- entity-framework/core/managing-schemas/migrations/providers.md | 2 +- entity-framework/core/managing-schemas/migrations/teams.md | 2 +- entity-framework/core/managing-schemas/scaffolding/index.md | 2 +- entity-framework/core/managing-schemas/scaffolding/templates.md | 2 +- entity-framework/core/miscellaneous/connection-strings.md | 2 +- entity-framework/core/miscellaneous/internals/index.md | 2 +- entity-framework/core/miscellaneous/internals/tools.md | 2 +- entity-framework/core/miscellaneous/platforms.md | 2 +- entity-framework/core/miscellaneous/plugins.md | 2 +- entity-framework/core/modeling/spatial.md | 2 +- entity-framework/core/providers/cosmos/functions.md | 2 +- entity-framework/core/providers/sql-server/functions.md | 2 +- entity-framework/core/providers/sql-server/spatial.md | 2 +- entity-framework/core/providers/sqlite/functions.md | 2 +- entity-framework/core/providers/sqlite/index.md | 2 +- entity-framework/core/providers/sqlite/limitations.md | 2 +- entity-framework/core/providers/sqlite/spatial.md | 2 +- .../core/what-is-new/ef-core-5.0/breaking-changes.md | 2 +- 32 files changed, 32 insertions(+), 32 deletions(-) diff --git a/entity-framework/core/cli/dbcontext-creation.md b/entity-framework/core/cli/dbcontext-creation.md index 4cea002cf3..9c04da1532 100644 --- a/entity-framework/core/cli/dbcontext-creation.md +++ b/entity-framework/core/cli/dbcontext-creation.md @@ -1,7 +1,7 @@ --- title: Design-time DbContext Creation - EF Core description: Strategies for creating a design-time DbContext with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/27/2020 uid: core/cli/dbcontext-creation --- diff --git a/entity-framework/core/cli/dotnet.md b/entity-framework/core/cli/dotnet.md index fc7129d73b..9ce90fa4b9 100644 --- a/entity-framework/core/cli/dotnet.md +++ b/entity-framework/core/cli/dotnet.md @@ -1,7 +1,7 @@ --- title: EF Core tools reference (.NET CLI) - EF Core description: Reference guide for the Entity Framework Core .NET Core CLI tools -author: bricelam +author: SamMonoRT ms.date: 11/15/2021 uid: core/cli/dotnet --- diff --git a/entity-framework/core/cli/index.md b/entity-framework/core/cli/index.md index 9104fd5856..9659344157 100644 --- a/entity-framework/core/cli/index.md +++ b/entity-framework/core/cli/index.md @@ -1,7 +1,7 @@ --- title: Entity Framework Core tools reference - EF Core description: Reference guide for the Entity Framework Core CLI tool and the Visual Studio Package Manager Console -author: bricelam +author: SamMonoRT ms.date: 09/19/2018 uid: core/cli/index --- diff --git a/entity-framework/core/cli/powershell.md b/entity-framework/core/cli/powershell.md index f2d75eeb1f..5d5fda04b0 100644 --- a/entity-framework/core/cli/powershell.md +++ b/entity-framework/core/cli/powershell.md @@ -1,7 +1,7 @@ --- title: EF Core tools reference (Package Manager Console) - EF Core description: Reference guide for the Entity Framework Core Visual Studio Package Manager Console -author: bricelam +author: SamMonoRT ms.date: 11/15/2021 uid: core/cli/powershell --- diff --git a/entity-framework/core/cli/services.md b/entity-framework/core/cli/services.md index fc13d96eb4..985392c98b 100644 --- a/entity-framework/core/cli/services.md +++ b/entity-framework/core/cli/services.md @@ -1,7 +1,7 @@ --- title: Design-time services - EF Core description: Information on Entity Framework Core design-time services -author: bricelam +author: SamMonoRT ms.date: 10/22/2020 uid: core/cli/services --- diff --git a/entity-framework/core/get-started/overview/install.md b/entity-framework/core/get-started/overview/install.md index 3377822cff..68696afa78 100644 --- a/entity-framework/core/get-started/overview/install.md +++ b/entity-framework/core/get-started/overview/install.md @@ -1,7 +1,7 @@ --- title: Installing Entity Framework Core - EF Core description: Installation instructions for Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 03/23/2023 uid: core/get-started/overview/install --- diff --git a/entity-framework/core/managing-schemas/ensure-created.md b/entity-framework/core/managing-schemas/ensure-created.md index 22090bb518..20b939568a 100644 --- a/entity-framework/core/managing-schemas/ensure-created.md +++ b/entity-framework/core/managing-schemas/ensure-created.md @@ -1,7 +1,7 @@ --- title: Create and Drop APIs - EF Core description: APIs for creating and dropping databases with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/21/2021 no-loc: [EnsureDeleted, EnsureCreated] uid: core/managing-schemas/ensure-created diff --git a/entity-framework/core/managing-schemas/index.md b/entity-framework/core/managing-schemas/index.md index 01174e2d04..2b1803e4d7 100644 --- a/entity-framework/core/managing-schemas/index.md +++ b/entity-framework/core/managing-schemas/index.md @@ -1,7 +1,7 @@ --- title: Managing Database Schemas - EF Core description: Overview of strategies for managing your database schemas with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/30/2017 uid: core/managing-schemas/index --- diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md index f920458b8b..7dd17cdfda 100644 --- a/entity-framework/core/managing-schemas/migrations/applying.md +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -1,7 +1,7 @@ --- title: Applying Migrations - EF Core description: Strategies for applying schema migrations to production and development databases using Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 11/02/2021 uid: core/managing-schemas/migrations/applying --- diff --git a/entity-framework/core/managing-schemas/migrations/history-table.md b/entity-framework/core/managing-schemas/migrations/history-table.md index c6dc792317..ea9fdf8562 100644 --- a/entity-framework/core/managing-schemas/migrations/history-table.md +++ b/entity-framework/core/managing-schemas/migrations/history-table.md @@ -1,7 +1,7 @@ --- title: Custom Migrations History Table - EF Core description: Customizing a history table to use for migrations with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 11/07/2017 uid: core/managing-schemas/migrations/history-table --- diff --git a/entity-framework/core/managing-schemas/migrations/index.md b/entity-framework/core/managing-schemas/migrations/index.md index 0a6a41b548..e6d4bd5ff4 100644 --- a/entity-framework/core/managing-schemas/migrations/index.md +++ b/entity-framework/core/managing-schemas/migrations/index.md @@ -1,7 +1,7 @@ --- title: Migrations Overview - EF Core description: Overview of using migrations to manage database schemas with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/28/2020 uid: core/managing-schemas/migrations/index --- diff --git a/entity-framework/core/managing-schemas/migrations/managing.md b/entity-framework/core/managing-schemas/migrations/managing.md index eac9066ced..40a8e490fa 100644 --- a/entity-framework/core/managing-schemas/migrations/managing.md +++ b/entity-framework/core/managing-schemas/migrations/managing.md @@ -1,7 +1,7 @@ --- title: Managing Migrations - EF Core description: Adding, removing and otherwise managing database schema migrations with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/27/2020 uid: core/managing-schemas/migrations/managing --- diff --git a/entity-framework/core/managing-schemas/migrations/operations.md b/entity-framework/core/managing-schemas/migrations/operations.md index f15e366fb6..1278877bcc 100644 --- a/entity-framework/core/managing-schemas/migrations/operations.md +++ b/entity-framework/core/managing-schemas/migrations/operations.md @@ -1,7 +1,7 @@ --- title: Custom Migrations Operations - EF Core description: Managing custom and raw SQL migrations for database schema management with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/27/2020 uid: core/managing-schemas/migrations/operations --- diff --git a/entity-framework/core/managing-schemas/migrations/projects.md b/entity-framework/core/managing-schemas/migrations/projects.md index 471dcfd288..db7af9e98d 100644 --- a/entity-framework/core/managing-schemas/migrations/projects.md +++ b/entity-framework/core/managing-schemas/migrations/projects.md @@ -1,7 +1,7 @@ --- title: Using a Separate Migrations Project - EF Core description: Using a separate migration project for managing database schemas with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 11/06/2020 uid: core/managing-schemas/migrations/projects --- diff --git a/entity-framework/core/managing-schemas/migrations/providers.md b/entity-framework/core/managing-schemas/migrations/providers.md index f5984096f0..0aa74eb4e0 100644 --- a/entity-framework/core/managing-schemas/migrations/providers.md +++ b/entity-framework/core/managing-schemas/migrations/providers.md @@ -1,7 +1,7 @@ --- title: Migrations with Multiple Providers - EF Core description: Using migrations to manage database schemas when targeting multiple database providers with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/29/2020 uid: core/managing-schemas/migrations/providers --- diff --git a/entity-framework/core/managing-schemas/migrations/teams.md b/entity-framework/core/managing-schemas/migrations/teams.md index b7bb90e3f4..0a99ca8231 100644 --- a/entity-framework/core/managing-schemas/migrations/teams.md +++ b/entity-framework/core/managing-schemas/migrations/teams.md @@ -1,7 +1,7 @@ --- title: Migrations in Team Environments - EF Core description: Best practices for managing migrations and resolving conflicts in team environments with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/30/2017 uid: core/managing-schemas/migrations/teams --- diff --git a/entity-framework/core/managing-schemas/scaffolding/index.md b/entity-framework/core/managing-schemas/scaffolding/index.md index fd8afe18d9..aaba0bf5c3 100644 --- a/entity-framework/core/managing-schemas/scaffolding/index.md +++ b/entity-framework/core/managing-schemas/scaffolding/index.md @@ -1,7 +1,7 @@ --- title: Reverse Engineering - EF Core description: Reverse engineering a model from an existing database using Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 03/27/2023 uid: core/managing-schemas/scaffolding --- diff --git a/entity-framework/core/managing-schemas/scaffolding/templates.md b/entity-framework/core/managing-schemas/scaffolding/templates.md index 271ba728da..f0c13e8667 100644 --- a/entity-framework/core/managing-schemas/scaffolding/templates.md +++ b/entity-framework/core/managing-schemas/scaffolding/templates.md @@ -1,7 +1,7 @@ --- title: Custom Reverse Engineering Templates - EF Core description: Using T4 text templates to customize the scaffolded code when reverse engineering an Entity Framework Core model from a database -author: bricelam +author: SamMonoRT ms.date: 08/16/2022 uid: core/managing-schemas/scaffolding/templates --- diff --git a/entity-framework/core/miscellaneous/connection-strings.md b/entity-framework/core/miscellaneous/connection-strings.md index ba3004cde9..cb33d6b9fd 100644 --- a/entity-framework/core/miscellaneous/connection-strings.md +++ b/entity-framework/core/miscellaneous/connection-strings.md @@ -1,7 +1,7 @@ --- title: Connection Strings - EF Core description: Managing connection strings under different environments with Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 10/27/2016 uid: core/miscellaneous/connection-strings --- diff --git a/entity-framework/core/miscellaneous/internals/index.md b/entity-framework/core/miscellaneous/internals/index.md index 9aa19a4eba..8530230247 100644 --- a/entity-framework/core/miscellaneous/internals/index.md +++ b/entity-framework/core/miscellaneous/internals/index.md @@ -1,7 +1,7 @@ --- title: Architecture - EF Core description: The internal architecture of Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 11/27/2023 uid: core/miscellaneous/internals/index --- diff --git a/entity-framework/core/miscellaneous/internals/tools.md b/entity-framework/core/miscellaneous/internals/tools.md index 97fe76854d..0475c90921 100644 --- a/entity-framework/core/miscellaneous/internals/tools.md +++ b/entity-framework/core/miscellaneous/internals/tools.md @@ -1,7 +1,7 @@ --- title: Design-time Tools Architecture - EF Core description: The architecture of design-time tools in Entity Framework Core -author: bricelam +author: SamMonoRT ms.date: 11/27/2023 uid: core/miscellaneous/internals/tools --- diff --git a/entity-framework/core/miscellaneous/platforms.md b/entity-framework/core/miscellaneous/platforms.md index db68ab27ec..6db48089db 100644 --- a/entity-framework/core/miscellaneous/platforms.md +++ b/entity-framework/core/miscellaneous/platforms.md @@ -1,7 +1,7 @@ --- title: Supported .NET implementations - EF Core description: Information on supported platforms across Entity Framework Core versions -author: bricelam +author: SamMonoRT ms.date: 12/13/2022 uid: core/miscellaneous/platforms --- diff --git a/entity-framework/core/miscellaneous/plugins.md b/entity-framework/core/miscellaneous/plugins.md index a7ed041470..c08cc5806a 100644 --- a/entity-framework/core/miscellaneous/plugins.md +++ b/entity-framework/core/miscellaneous/plugins.md @@ -1,7 +1,7 @@ --- title: Plug-in APIs - EF Core description: APIs extensions can use to plug into certain Entity Framework Core components -author: bricelam +author: SamMonoRT ms.date: 8/31/2023 uid: core/miscellaneous/plugins --- diff --git a/entity-framework/core/modeling/spatial.md b/entity-framework/core/modeling/spatial.md index ee241915b0..144fd4be71 100644 --- a/entity-framework/core/modeling/spatial.md +++ b/entity-framework/core/modeling/spatial.md @@ -1,7 +1,7 @@ --- title: Spatial Data - EF Core description: Using spatial data in an Entity Framework Core model -author: bricelam +author: SamMonoRT ms.date: 11/15/2021 uid: core/modeling/spatial --- diff --git a/entity-framework/core/providers/cosmos/functions.md b/entity-framework/core/providers/cosmos/functions.md index fb66960203..45b2d8fee5 100644 --- a/entity-framework/core/providers/cosmos/functions.md +++ b/entity-framework/core/providers/cosmos/functions.md @@ -1,7 +1,7 @@ --- title: Function Mappings - Azure Cosmos DB Provider - EF Core description: Function Mappings of the Azure Cosmos DB EF Core Provider -author: bricelam +author: SamMonoRT ms.date: 7/26/2023 uid: core/providers/cosmos/functions --- diff --git a/entity-framework/core/providers/sql-server/functions.md b/entity-framework/core/providers/sql-server/functions.md index a9d96c564e..632315c014 100644 --- a/entity-framework/core/providers/sql-server/functions.md +++ b/entity-framework/core/providers/sql-server/functions.md @@ -1,7 +1,7 @@ --- title: Function Mappings - Microsoft SQL Server Database Provider - EF Core description: Function Mappings of the Microsoft SQL Server database provider -author: bricelam +author: SamMonoRT ms.date: 7/26/2023 uid: core/providers/sql-server/functions --- diff --git a/entity-framework/core/providers/sql-server/spatial.md b/entity-framework/core/providers/sql-server/spatial.md index 9e885bdd18..99a067f5de 100644 --- a/entity-framework/core/providers/sql-server/spatial.md +++ b/entity-framework/core/providers/sql-server/spatial.md @@ -1,7 +1,7 @@ --- title: Microsoft SQL Server Database Provider - Spatial Data - EF Core description: Using spatial data with the Entity Framework Core Microsoft SQL Server database provider -author: bricelam +author: SamMonoRT ms.date: 10/02/2020 uid: core/providers/sql-server/spatial --- diff --git a/entity-framework/core/providers/sqlite/functions.md b/entity-framework/core/providers/sqlite/functions.md index b36675e0ab..49037b8673 100644 --- a/entity-framework/core/providers/sqlite/functions.md +++ b/entity-framework/core/providers/sqlite/functions.md @@ -1,7 +1,7 @@ --- title: Function Mappings - SQLite Database Provider - EF Core description: Function Mappings of the SQLite EF Core database provider -author: bricelam +author: SamMonoRT ms.date: 7/26/2023 uid: core/providers/sqlite/functions --- diff --git a/entity-framework/core/providers/sqlite/index.md b/entity-framework/core/providers/sqlite/index.md index dc2efac174..7ff625161f 100644 --- a/entity-framework/core/providers/sqlite/index.md +++ b/entity-framework/core/providers/sqlite/index.md @@ -1,7 +1,7 @@ --- title: SQLite Database Provider - EF Core description: Information on the Entity Framework Core SQLite database provider -author: bricelam +author: SamMonoRT ms.date: 10/27/2016 uid: core/providers/sqlite/index --- diff --git a/entity-framework/core/providers/sqlite/limitations.md b/entity-framework/core/providers/sqlite/limitations.md index bc66dfbf0d..2ad2f8e20f 100644 --- a/entity-framework/core/providers/sqlite/limitations.md +++ b/entity-framework/core/providers/sqlite/limitations.md @@ -1,7 +1,7 @@ --- title: SQLite Database Provider - Limitations - EF Core description: Limitations of the Entity Framework Core SQLite database provider as compared to other providers -author: bricelam +author: SamMonoRT ms.date: 11/15/2021 uid: core/providers/sqlite/limitations --- diff --git a/entity-framework/core/providers/sqlite/spatial.md b/entity-framework/core/providers/sqlite/spatial.md index 15ad6e0d77..0ff653f48a 100644 --- a/entity-framework/core/providers/sqlite/spatial.md +++ b/entity-framework/core/providers/sqlite/spatial.md @@ -1,7 +1,7 @@ --- title: SQLite Database Provider - Spatial Data - EF Core description: Using spatial data with the Entity Framework Core SQLite database provider -author: bricelam +author: SamMonoRT ms.date: 10/02/2020 uid: core/providers/sqlite/spatial --- diff --git a/entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md index d389b8b91a..0ce31c6d78 100644 --- a/entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-5.0/breaking-changes.md @@ -1,7 +1,7 @@ --- title: Breaking changes in EF Core 5.0 - EF Core description: Complete list of breaking changes introduced in Entity Framework Core 5.0 -author: bricelam +author: SamMonoRT ms.date: 09/21/2022 uid: core/what-is-new/ef-core-5.0/breaking-changes --- From 4dcd006d098ef594550e70ec7fd5b3f90fcfaf99 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 26 Sep 2024 14:22:44 +0200 Subject: [PATCH 040/224] Document Cosmos changes in 9.0 (#4812) Closes #4808 Part of #4805 (new function translations for Cosmos) --- .openpublishing.redirection.json | 5 + .../core/providers/cosmos/functions.md | 83 ---- .../core/providers/cosmos/index.md | 371 +--------------- .../core/providers/cosmos/limitations.md | 6 +- .../core/providers/cosmos/modeling.md | 336 +++++++++++++++ .../core/providers/cosmos/querying.md | 312 ++++++++++++++ .../core/providers/cosmos/vector-search.md | 58 +++ .../core/querying/database-functions.md | 2 +- entity-framework/core/querying/pagination.md | 5 +- .../ef-core-9.0/breaking-changes.md | 360 ++++++++++++++-- .../core/what-is-new/ef-core-9.0/whatsnew.md | 408 ++++++++---------- entity-framework/toc.yml | 8 +- 12 files changed, 1244 insertions(+), 710 deletions(-) delete mode 100644 entity-framework/core/providers/cosmos/functions.md create mode 100644 entity-framework/core/providers/cosmos/modeling.md create mode 100644 entity-framework/core/providers/cosmos/querying.md create mode 100644 entity-framework/core/providers/cosmos/vector-search.md diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 83e84b0743..b81233e570 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -479,6 +479,11 @@ "source_path": "entity-framework/core/logging-events-diagnostics/event-counters.md", "redirect_url": "/ef/core/logging-events-diagnostics/metrics", "redirect_document_id": false + }, + { + "source_path": "entity-framework/core/providers/cosmos/functions.md", + "redirect_url": "/ef/core/providers/cosmos/querying", + "redirect_document_id": false } ] } diff --git a/entity-framework/core/providers/cosmos/functions.md b/entity-framework/core/providers/cosmos/functions.md deleted file mode 100644 index 45b2d8fee5..0000000000 --- a/entity-framework/core/providers/cosmos/functions.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Function Mappings - Azure Cosmos DB Provider - EF Core -description: Function Mappings of the Azure Cosmos DB EF Core Provider -author: SamMonoRT -ms.date: 7/26/2023 -uid: core/providers/cosmos/functions ---- -# Function Mappings of the Azure Cosmos DB EF Core Provider - -This page shows which .NET members are translated into which SQL functions when using the Azure Cosmos DB provider. - -## Date and time functions - -.NET | SQL ---------------------- | --- -DateTime.UtcNow | GetCurrentDateTime() -DateTimeOffset.UtcNow | GetCurrentDateTime() - -## Numeric functions - -.NET | SQL | Added in --------------------------- | ----------------- | -------- -double.DegreesToRadians(x) | RADIANS(@x) | EF Core 8.0 -double.RadiansToDegrees(x) | DEGREES(@x) | EF Core 8.0 -EF.Functions.Random() | RAND() -Math.Abs(value) | ABS(@value) -Math.Acos(d) | ACOS(@d) -Math.Asin(d) | ASIN(@d) -Math.Atan(d) | ATAN(@d) -Math.Atan2(y, x) | ATN2(@y, @x) -Math.Ceiling(d) | CEILING(@d) -Math.Cos(d) | COS(@d) -Math.Exp(d) | EXP(@d) -Math.Floor(d) | FLOOR(@d) -Math.Log(a, newBase) | LOG(@a, @newBase) -Math.Log(d) | LOG(@d) -Math.Log10(d) | LOG10(@d) -Math.Pow(x, y) | POWER(@x, @y) -Math.Round(d) | ROUND(@d) -Math.Sign(value) | SIGN(@value) -Math.Sin(a) | SIN(@a) -Math.Sqrt(d) | SQRT(@d) -Math.Tan(a) | TAN(@a) -Math.Truncate(d) | TRUNC(@d) - -> [!TIP] -> In addition to the methods listed here, corresponding [generic math](/dotnet/standard/generics/math) implementations -> and [MathF](/dotnet/api/system.mathf) methods are also translated. For example, `Math.Sin`, `MathF.Sin`, `double.Sin`, -> and `float.Sin` all map to the `SIN` function in SQL. - -## String functions - -.NET | SQL | Added in -------------------------------------------------------------- | ---------------------------------------------------------- | -------- -Regex.IsMatch(input, pattern) | RegexMatch(@pattern, @input) | EF Core 7.0 -Regex.IsMatch(input, pattern, options) | RegexMatch(@input, @pattern, @options) | EF Core 7.0 -string.Concat(str0, str1) | @str0 + @str1 -string.Equals(a, b, StringComparison.Ordinal) | STRINGEQUALS(@a, @b) -string.Equals(a, b, StringComparison.OrdinalIgnoreCase) | STRINGEQUALS(@a, @b, true) -stringValue.Contains(value) | CONTAINS(@stringValue, @value) -stringValue.EndsWith(value) | ENDSWITH(@stringValue, @value) -stringValue.Equals(value, StringComparison.Ordinal) | STRINGEQUALS(@stringValue, @value) -stringValue.Equals(value, StringComparison.OrdinalIgnoreCase) | STRINGEQUALS(@stringValue, @value, true) -stringValue.FirstOrDefault() | LEFT(@stringValue, 1) -stringValue.IndexOf(value) | INDEX_OF(@stringValue, @value) -stringValue.IndexOf(value, startIndex) | INDEX_OF(@stringValue, @value, @startIndex) -stringValue.LastOrDefault() | RIGHT(@stringValue, 1) -stringValue.Length | LENGTH(@stringValue) -stringValue.Replace(oldValue, newValue) | REPLACE(@stringValue, @oldValue, @newValue) -stringValue.StartsWith(value) | STARTSWITH(@stringValue, @value) -stringValue.Substring(startIndex) | SUBSTRING(@stringValue, @startIndex, LENGTH(@stringValue)) -stringValue.Substring(startIndex, length) | SUBSTRING(@stringValue, @startIndex, @length) -stringValue.ToLower() | LOWER(@stringValue) -stringValue.ToUpper() | UPPER(@stringValue) -stringValue.Trim() | TRIM(@stringValue) -stringValue.TrimEnd() | RTRIM(@stringValue) -stringValue.TrimStart() | LTRIM(@stringValue) - -## Miscellaneous functions - -.NET | SQL ---------------------------|---- -collection.Contains(item) | @item IN @collection diff --git a/entity-framework/core/providers/cosmos/index.md b/entity-framework/core/providers/cosmos/index.md index 1e13188251..07794a9956 100644 --- a/entity-framework/core/providers/cosmos/index.md +++ b/entity-framework/core/providers/cosmos/index.md @@ -7,6 +7,9 @@ uid: core/providers/cosmos/index --- # EF Core Azure Cosmos DB Provider +> [!WARNING] +> Extensive work has gone into the Cosmos DB provider in 9.0. In order to improve the provider, a number of high-impact breaking changes had to be made; if you are upgrading an existing application, please read the [breaking changes section](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-breaking-changes) carefully. + This database provider allows Entity Framework Core to be used with Azure Cosmos DB. The provider is maintained as part of the [Entity Framework Core Project](https://github.com/dotnet/efcore). It is strongly recommended to familiarize yourself with the [Azure Cosmos DB documentation](/azure/cosmos-db/introduction) before reading this section. @@ -56,6 +59,8 @@ Saving and querying data follows the normal EF pattern: > [!IMPORTANT] > Calling [EnsureCreatedAsync](/dotnet/api/Microsoft.EntityFrameworkCore.Storage.IDatabaseCreator.EnsureCreatedAsync) is necessary to create the required containers and insert the [seed data](xref:core/modeling/data-seeding) if present in the model. However `EnsureCreatedAsync` should only be called during deployment, not normal operation, as it may cause performance issues. +> +> Azure Cosmos DB SDK does not support RBAC for management plane operations in Azure Cosmos DB. Use Azure Management API instead of EnsureCreatedAsync with RBAC. ## Connecting and authenticating @@ -70,374 +75,10 @@ The Azure Cosmos DB provider for EF Core has multiple overloads of the [UseCosmo | Account endpoint and token | `UseCosmos(accountEndpoint, tokenCredential, databaseName)` | [Resource tokens](/azure/cosmos-db/secure-access-to-data#primary-keys) | | Connection string | `UseCosmos(connectionString, databaseName)` | [Work with account keys and connection strings](/azure/cosmos-db/scripts/cli/common/keys) | -## Queries - -### LINQ queries - -[EF Core LINQ queries](xref:core/querying/index) can be executed against Azure Cosmos DB in the same way as for other database providers. For example: - - -[!code-csharp[StringTranslations](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosQueriesSample.cs?name=StringTranslations)] - -> [!NOTE] -> The Azure Cosmos DB provider does not translate the same set of LINQ queries as other providers. See [_Limitations_](xref:core/providers/cosmos/limitations) for more information. - -### SQL queries - -Queries can also be written [directly in SQL](xref:core/querying/sql-queries). For example: - - -[!code-csharp[FromSql](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosQueriesSample.cs?name=FromSql)] - -This query results in the following query execution: - -```sql -SELECT c -FROM ( - SELECT * FROM root c WHERE c["Angle1"] <= @p0 OR c["Angle2"] <= @p0 -) c -``` - -Just like for relational `FromSql` queries, the hand written SQL can be further composed using LINQ operators. For example: - - -[!code-csharp[FromSqlComposed](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosQueriesSample.cs?name=FromSqlComposed)] - -This combination of SQL and LINQ is translated to: - -```sql -SELECT DISTINCT c["Angle1"] -FROM ( - SELECT * FROM root c WHERE c["Angle1"] <= @p0 OR c["Angle2"] <= @p0 -) c -WHERE (c["InsertedOn"] <= GetCurrentDateTime()) -``` - ## Azure Cosmos DB options It is also possible to configure the Azure Cosmos DB provider with a single connection string and to specify other options to customize the connection: [!code-csharp[Configuration](../../../../samples/core/Cosmos/ModelBuilding/OptionsContext.cs?name=Configuration)] -> [!TIP] -> The code above shows possible options. It is not intended that these will all be used at the same time! See the [Azure Cosmos DB Options documentation](/dotnet/api/microsoft.azure.cosmos.cosmosclientoptions) for a detailed description of the effect of each option mentioned above. - -## Cosmos-specific model customization - -By default all entity types are mapped to the same container, named after the derived context (`"OrderContext"` in this case). To change the default container name use [HasDefaultContainer](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosModelBuilderExtensions.HasDefaultContainer): - -[!code-csharp[DefaultContainer](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=DefaultContainer)] - -To map an entity type to a different container use [ToContainer](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosEntityTypeBuilderExtensions.ToContainer): - -[!code-csharp[Container](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=Container)] - -To identify the entity type that a given item represent EF Core adds a discriminator value even if there are no derived entity types. The name and value of the discriminator [can be changed](xref:core/modeling/inheritance). - -If no other entity type will ever be stored in the same container the discriminator can be removed by calling [HasNoDiscriminator](/dotnet/api/Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder.HasNoDiscriminator): - -[!code-csharp[NoDiscriminator](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=NoDiscriminator)] - -### Partition keys - -By default, EF Core will create containers with the partition key set to `"__partitionKey"` without supplying any value for it when inserting items. But to fully leverage the performance capabilities of Azure Cosmos DB, a [carefully selected partition key](/azure/cosmos-db/partition-data) should be used. It can be configured by calling [HasPartitionKey](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosEntityTypeBuilderExtensions.HasPartitionKey): - -[!code-csharp[PartitionKey](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=PartitionKey)] - -> [!NOTE] ->The partition key property can be of any type as long as it is [converted to string](xref:core/modeling/value-conversions). - -Once configured the partition key property should always have a non-null value. A query can be made single-partition by adding a call. - -[!code-csharp[PartitionKey](../../../../samples/core/Cosmos/ModelBuilding/Sample.cs?name=PartitionKey&highlight=14)] - -It is generally recommended to add the partition key to the primary key as that best reflects the server semantics and allows some optimizations, for example in `FindAsync`. - -### Provisioned throughput - -If you use EF Core to create the Azure Cosmos DB database or containers you can configure [provisioned throughput](/azure/cosmos-db/set-throughput) for the database by calling or . For example: - - -[!code-csharp[ModelThroughput](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=ModelThroughput)] - -To configure provisioned throughput for a container call or . For example: - - -[!code-csharp[EntityTypeThroughput](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=EntityTypeThroughput)] - -### Time-to-live - -Entity types in the Azure Cosmos DB model can now be configured with a default time-to-live. For example: - -```csharp -modelBuilder.Entity().HasDefaultTimeToLive(3600); -``` - -Or, for the analytical store: - -```csharp -modelBuilder.Entity().HasAnalyticalStoreTimeToLive(3600); -``` - -Time-to-live for individual entities can be set using a property mapped to "ttl" in the JSON document. For example: - - -[!code-csharp[TimeToLiveProperty](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=TimeToLiveProperty)] - -> [!NOTE] -> A default time-to-live must configured on the entity type for the "ttl" to have any effect. See [_Time to Live (TTL) in Azure Cosmos DB_](/azure/cosmos-db/nosql/time-to-live) for more information. - -The time-to-live property is then set before the entity is saved. For example: - - -[!code-csharp[SetTtl](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=SetTtl)] - -The time-to-live property can be a [shadow property](xref:core/modeling/shadow-properties) to avoid polluting the domain entity with database concerns. For example: - - -[!code-csharp[TimeToLiveShadowProperty](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=TimeToLiveShadowProperty)] - -The shadow time-to-live property is then set by [accessing the tracked entity](xref:core/change-tracking/entity-entries). For example: - - -[!code-csharp[SetTtlShadow](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=SetTtlShadow)] - -## Embedded entities - -> [!NOTE] -> Related entity types are configured as owned by default. To prevent this for a specific entity type call . - -For Azure Cosmos DB, owned entities are embedded in the same item as the owner. To change a property name use [ToJsonProperty](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosEntityTypeBuilderExtensions.ToJsonProperty): - -[!code-csharp[PropertyNames](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=PropertyNames)] - -With this configuration the order from the example above is stored like this: - -```json -{ - "Id": 1, - "PartitionKey": "1", - "TrackingNumber": null, - "id": "1", - "Address": { - "ShipsToCity": "London", - "ShipsToStreet": "221 B Baker St" - }, - "_rid": "6QEKAM+BOOABAAAAAAAAAA==", - "_self": "dbs/6QEKAA==/colls/6QEKAM+BOOA=/docs/6QEKAM+BOOABAAAAAAAAAA==/", - "_etag": "\"00000000-0000-0000-683c-692e763901d5\"", - "_attachments": "attachments/", - "_ts": 1568163674 -} -``` - -Collections of owned entities are embedded as well. For the next example we'll use the `Distributor` class with a collection of `StreetAddress`: - -[!code-csharp[Distributor](../../../../samples/core/Cosmos/ModelBuilding/Distributor.cs?name=Distributor)] - -The owned entities don't need to provide explicit key values to be stored: - -[!code-csharp[OwnedCollection](../../../../samples/core/Cosmos/ModelBuilding/Sample.cs?name=OwnedCollection)] - -They will be persisted in this way: - -```json -{ - "Id": 1, - "Discriminator": "Distributor", - "id": "Distributor|1", - "ShippingCenters": [ - { - "City": "Phoenix", - "Street": "500 S 48th Street" - }, - { - "City": "Anaheim", - "Street": "5650 Dolly Ave" - } - ], - "_rid": "6QEKANzISj0BAAAAAAAAAA==", - "_self": "dbs/6QEKAA==/colls/6QEKANzISj0=/docs/6QEKANzISj0BAAAAAAAAAA==/", - "_etag": "\"00000000-0000-0000-683c-7b2b439701d5\"", - "_attachments": "attachments/", - "_ts": 1568163705 -} -``` - -Internally EF Core always needs to have unique key values for all tracked entities. The primary key created by default for collections of owned types consists of the foreign key properties pointing to the owner and an `int` property corresponding to the index in the JSON array. To retrieve these values entry API could be used: - -[!code-csharp[ImpliedProperties](../../../../samples/core/Cosmos/ModelBuilding/Sample.cs?name=ImpliedProperties)] - -> [!TIP] -> When necessary the default primary key for the owned entity types can be changed, but then key values should be provided explicitly. - -### Collections of primitive types - -Collections of supported primitive types, such as `string` and `int`, are discovered and mapped automatically. Supported collections are all types that implement or . For example, consider this entity type: - - -[!code-csharp[BookEntity](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs?name=BookEntity)] - -Both the list and the dictionary can be populated and inserted into the database in the normal way: - - -[!code-csharp[Insert](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs?name=Insert)] - -This results in the following JSON document: - -```json -{ - "Id": "0b32283e-22a8-4103-bb4f-6052604868bd", - "Discriminator": "Book", - "Notes": { - "36": "The Terracotta Army", - "48": "Saint Mark's Basilica", - "121": "Fridges", - "144": "Peter Higgs" - }, - "Quotes": [ - "Thomas (Tommy) Flowers was the British engineer behind the design of the Colossus computer.", - "Invented originally for Guinness, plastic widgets are nitrogen-filled spheres.", - "For 20 years after its introduction in 1979, the Walkman dominated the personal stereo market." - ], - "Title": "How It Works: Incredible History", - "id": "Book|0b32283e-22a8-4103-bb4f-6052604868bd", - "_rid": "t-E3AIxaencBAAAAAAAAAA==", - "_self": "dbs/t-E3AA==/colls/t-E3AIxaenc=/docs/t-E3AIxaencBAAAAAAAAAA==/", - "_etag": "\"00000000-0000-0000-9b50-fc769dc901d7\"", - "_attachments": "attachments/", - "_ts": 1630075016 -} -``` - -These collections can then be updated, again in the normal way: - - -[!code-csharp[Updates](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs?name=Updates)] - -Limitations: - -* Only dictionaries with string keys are supported -* Querying into the contents of primitive collections is not currently supported. Vote for [#16926](https://github.com/dotnet/efcore/issues/16926), [#25700](https://github.com/dotnet/efcore/issues/25700), and [#25701](https://github.com/dotnet/efcore/issues/25701) if these features are important to you. - -## Working with disconnected entities - -Every item needs to have an `id` value that is unique for the given partition key. By default EF Core generates the value by concatenating the discriminator and the primary key values, using '|' as a delimiter. The key values are only generated when an entity enters the `Added` state. This might pose a problem when [attaching entities](xref:core/saving/disconnected-entities) if they don't have an `id` property on the .NET type to store the value. - -To work around this limitation one could create and set the `id` value manually or mark the entity as added first, then changing it to the desired state: - -[!code-csharp[Attach](../../../../samples/core/Cosmos/ModelBuilding/Sample.cs?highlight=4&name=Attach)] - -This is the resulting JSON: - -```json -{ - "Id": 1, - "Discriminator": "Distributor", - "id": "Distributor|1", - "ShippingCenters": [ - { - "City": "Phoenix", - "Street": "500 S 48th Street" - } - ], - "_rid": "JBwtAN8oNYEBAAAAAAAAAA==", - "_self": "dbs/JBwtAA==/colls/JBwtAN8oNYE=/docs/JBwtAN8oNYEBAAAAAAAAAA==/", - "_etag": "\"00000000-0000-0000-9377-d7a1ae7c01d5\"", - "_attachments": "attachments/", - "_ts": 1572917100 -} -``` - -## Optimistic concurrency with eTags - -To configure an entity type to use [optimistic concurrency](xref:core/saving/concurrency) call . This call will create an `_etag` property in [shadow state](xref:core/modeling/shadow-properties) and set it as the concurrency token. - -[!code-csharp[Main](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=ETag)] - -To make it easier to resolve concurrency errors you can map the eTag to a CLR property using . - -[!code-csharp[Main](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=ETagProperty)] +The code above shows some possible options - these are not intended to be used at the same time. See the [Azure Cosmos DB Options documentation](/dotnet/api/microsoft.azure.cosmos.cosmosclientoptions) for a detailed description of the effect of each option mentioned above. diff --git a/entity-framework/core/providers/cosmos/limitations.md b/entity-framework/core/providers/cosmos/limitations.md index 446e0aee1e..8312ba552b 100644 --- a/entity-framework/core/providers/cosmos/limitations.md +++ b/entity-framework/core/providers/cosmos/limitations.md @@ -2,7 +2,7 @@ title: Azure Cosmos DB Provider - Limitations - EF Core description: Limitations of the Entity Framework Core Azure Cosmos DB provider as compared to other providers author: AndriySvyryd -ms.date: 02/14/2023 +ms.date: 09/26/2024 uid: core/providers/cosmos/limitations --- # EF Core Azure Cosmos DB Provider Limitations @@ -17,6 +17,8 @@ Common EF Core patterns that either do not apply, or are a pit-of-failure, when - Loading graphs of related entities from different documents is not supported. Document databases are not designed to perform joins across many documents; doing so would be very inefficient. Instead, it is more common to denormalize data so that everything needed is in one, or a small number, of documents. However, there are some forms of cross-document relationships that could be handled--see [Limited Include support for Cosmos](https://github.com/dotnet/efcore/issues/16920#issuecomment-989721078). > [!WARNING] -> Since there are no sync versions of the low level methods EF Core relies on, the corresponding functionality is currently implemented by calling `.Wait()` on the returned `Task`. This means that using methods like `SaveChanges`, or `ToList` instead of their async counterparts could lead to a deadlock in your application +> The Cosmos SDK, which the EF provider uses, does not support synchronous I/O. As a result, synchronous EF APIs such as `ToList` or `SaveChanges` throw in version 9.0 and above; always use asynchronous +> methods when using EF. +> Previous versions of EF supported the synchronous APIs by calling `.Wait()` on the returned `Task`; this is known as "sync over async", and is a highly discouraged technique that can lead to deadlocks. See the EF 9.0 [breaking change note](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-nosync) for more information. Beyond the differences in relational and document databases, and limitations in the SDK, the EF Core provider for Azure Cosmos DB NoSQL does not include everything that _could_ be implemented using the combination of EF Core and the Cosmos SDK. Potential enhancements in this area are tracked by [issues in the EF Core GitHub repo marked with the label `area-cosmos`](https://github.com/dotnet/efcore/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-cosmos+sort%3Areactions-%2B1-desc+label%3Atype-enhancement) The best way to indicate the importance of an issue is to vote (👍) for it. This data will then feed into the [planning process](xref:core/what-is-new/release-planning) for the next release. diff --git a/entity-framework/core/providers/cosmos/modeling.md b/entity-framework/core/providers/cosmos/modeling.md new file mode 100644 index 0000000000..e90377ad63 --- /dev/null +++ b/entity-framework/core/providers/cosmos/modeling.md @@ -0,0 +1,336 @@ +--- +title: Modeling - Azure Cosmos DB Provider - EF Core +description: Configuring the model with the Azure Cosmos DB EF Core Provider +author: roji +ms.date: 09/19/2024 +uid: core/providers/cosmos/modeling +--- +# Configuring the model with the EF Core Azure Cosmos DB Provider + +## Containers and entity types + +In Azure Cosmos DB, JSON documents are stored in containers. Unlike tables in relational databases, Cosmos DB containers can contain documents with different shapes - a container does not impose a uniform schema on its documents. However, various configuration options are defined at the container level, and therefore affect all documents contained within it. See the [Cosmos DB documentation on containers](/azure/cosmos-db/resource-model) for more information. + +By default, EF maps all entity types to the same container; this is usually a good default in terms of performance and pricing. The default container is named after the .NET context type (`OrderContext` in this case). To change the default container name, use : + +```csharp +modelBuilder.HasDefaultContainer("Store"); +``` + +To map an entity type to a different container use : + +```csharp +modelBuilder.Entity().ToContainer("Orders"); +``` + +Before mapping entity types to different containers, make sure you understand the potential performance and pricing implications (e.g. with regards to dedicated and shared throughput); [see the Cosmos DB documentation to learn more](/azure/cosmos-db/resource-model). + +## IDs and keys + +Cosmos DB requires all documents to have an `id` JSON property which uniquely identifies them. Like other EF providers, the EF Cosmos provider will attempt to find a property named `Id` or `Id`, and configure that property as the key of your entity type, mapping it to the `id` JSON property. You can configure any property to be the key property by using ; see [the general EF documentation on keys](xref:core/modeling/keys) for more information. + +Developers coming to Cosmos DB from other database sometimes expect the key (`Id`) property to be generated automatically. For example, on SQL Server, EF configures numeric key properties to be IDENTITY columns, where auto-incrementing values are generated in the database. In contrast, Cosmos DB does not support automatic generation of properties, and so key properties must be explicitly set. Inserting an entity type with an unset key property will simply insert the CLR default value for that property (e.g. 0 for `int`), and a second insert will fail; EF issues a warning if you attempt to do this. + +If you'd like to have a GUID as your key property, you can configure EF to generate unique, random values at the client: + +```csharp +modelBuilder.Entity().Property(b => b.Id).HasValueGenerator(); +``` + +## Partition keys + +Azure Cosmos DB uses partitioning to achieve horizontal scaling; proper modeling and careful selection of the partition key is vital for achieving good performance and keeping costs down. It's highly recommended to read [the Cosmos DB documentation on partitioning](/azure/cosmos-db/partition-data) and to plan your partitioning strategy in advance. + +To configure the partitioning key with EF, call [HasPartitionKey](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosEntityTypeBuilderExtensions.HasPartitionKey), passing it a regular property on your entity type: + +```csharp +modelBuilder.Entity().HasPartitionKey(o => o.PartitionKey); +``` + +Any property can be made into a partition key as long as it is [converted to string](xref:core/modeling/value-conversions). Once configured, the partition key property should always have a non-null value; trying to insert a new entity type with an unset partition key property will result in an error. + +Note that Cosmos allows two documents with the same `id` property to exist in a container, as long as they're in different partitions; this means that in order to uniquely identify a document within a container, both the `id` and the partition key properties must all be provided. Because of this, EF's internal notion of the entity primary key contains both of these elements by convention, unlike e.g. relational databases where there is no partition key concept. This means e.g. that [`FindAsync`](xref:core/change-tracking/entity-entries#find-and-findasync) requires both key and partition key properties ([see further docs](xref:core/providers/cosmos/querying#findasync)), and a query must specify these in its `Where` clause to benefit from efficient and cost-effective [`point reads`](xref:core/providers/cosmos/querying#point-reads). + +Note that the partition key is defined at the container level. This notably means that it's not possible to map multiple entity types to the same container, and for those entity types to have different partition keys. If you need to define different partition keys, map the relevant entity types to different containers. + +### Hierarchical partition keys + +Cosmos DB also supports _hierarchical_ partition keys to optimize data distribution even further; [see the Cosmos DB documentation for more details](/azure/cosmos-db/hierarchical-partition-keys). EF 9.0 added support for hierarchical partition keys; to configure these, simply pass up to 3 properties to [HasPartitionKey](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosEntityTypeBuilderExtensions.HasPartitionKey): + +```csharp +modelBuilder.Entity().HasPartitionKey(o => new { e.TenantId, e.UserId, e.SessionId }); +``` + +With such a hierarchical partition key, queries can be easily sent only to the a relevant subset of sub-partitions. For example, if you query for the Orders of a specific tenant, those queries will only be executed against the sub-partitions for that tenant. + +If you don't configure a partition key with EF, a warning will be logged at startup; EF Core will create containers with the partition key set to `__partitionKey`, and won't supply any value for it when inserting items. While this can work and may be a good way to start as you're exploring Cosmos DB and your data modeling, it is highly discouraged to deploy a production application without a well-configured partition key strategy. + +Once your partition keys properties are properly configured, you can provide values for them in queries; see [Querying with partition keys](xref:core/providers/cosmos/querying#partition-keys) for more information. + +## Discriminators + +Since multiple entity types may be mapped to the same container, EF Core always adds a `$type` discriminator property to all JSON documents you save (this property was called `Discriminator` before EF 9.0); this allows EF to recognize documents being loaded from the database, and materialize the right .NET type. Developers coming from relational databases may be familiar with discriminators in the context of [table-per-hierarchy inheritance (TPH)](xref:core/modeling/inheritance#table-per-hierarchy-and-discriminator-configuration); in Cosmos, discriminators are used not just in inheritance mapping scenarios, but also because the same container can contain completely different document types. + +The discriminator property name and values can be configured with the standard EF APIs, [see these docs for more information](xref:core/modeling/inheritance). If you're mapping a single entity type to a container, are confident that you'll never be mapping another one, and would like to get rid of the discriminator property, call [HasNoDiscriminator](/dotnet/api/Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder.HasNoDiscriminator): + +```csharp +modelBuilder.Entity().HasNoDiscriminator(); +``` + +Since the same container can contain entity types of different types, and the JSON `id` property must be unique within a container partition, you cannot have the same `id` value for entities of different types in the same container partition. Compare this to relational databases, where each entity type is mapped to a different table, and therefore has its own, separate key space. It is therefore your responsibility to ensure the `id` uniqueness of documents you insert into a container. If you need to have different entity types with the same primary key values, you can instruct EF to automatically insert the discriminator into the `id` property as follows: + +```csharp +modelBuilder.Entity().HasDiscriminatorInJsonId(); +``` + +While this may make it easier to work with `id` values, it may make it harder to interoperate with external applications working with your documents, as they now must be aware of EF's concatenated `id` format, as well as the discriminator values, which are by default derived from your .NET types. Note that this was the default behavior prior to EF 9.0. + +An additional option is to instruct EF to insert only the _root discriminator_, which is the discriminator of the root entity type of the hierarchy, into the `id` property: + +```csharp +modelBuilder.Entity().HasRootDiscriminatorInJsonId(); +``` + +This is similar, but allows EF to use efficient [point reads](xref:core/providers/cosmos/querying#point-reads) in more scenarios. If you need to insert a discriminator into the `id` property, consider inserting the root discriminator for better performance. + +## Provisioned throughput + +If you use EF Core to create the Azure Cosmos DB database or containers you can configure [provisioned throughput](/azure/cosmos-db/set-throughput) for the database by calling or . For example: + + +[!code-csharp[ModelThroughput](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=ModelThroughput)] + +To configure provisioned throughput for a container call or . For example: + + +[!code-csharp[EntityTypeThroughput](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=EntityTypeThroughput)] + +## Time-to-live + +Entity types in the Azure Cosmos DB model can be configured with a default time-to-live. For example: + +```csharp +modelBuilder.Entity().HasDefaultTimeToLive(3600); +``` + +Or, for the analytical store: + +```csharp +modelBuilder.Entity().HasAnalyticalStoreTimeToLive(3600); +``` + +Time-to-live for individual entities can be set using a property mapped to "ttl" in the JSON document. For example: + + +[!code-csharp[TimeToLiveProperty](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=TimeToLiveProperty)] + +> [!NOTE] +> A default time-to-live must configured on the entity type for the "ttl" to have any effect. See [_Time to Live (TTL) in Azure Cosmos DB_](/azure/cosmos-db/nosql/time-to-live) for more information. + +The time-to-live property is then set before the entity is saved. For example: + + +[!code-csharp[SetTtl](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=SetTtl)] + +The time-to-live property can be a [shadow property](xref:core/modeling/shadow-properties) to avoid polluting the domain entity with database concerns. For example: + + +[!code-csharp[TimeToLiveShadowProperty](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=TimeToLiveShadowProperty)] + +The shadow time-to-live property is then set by [accessing the tracked entity](xref:core/change-tracking/entity-entries). For example: + + +[!code-csharp[SetTtlShadow](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=SetTtlShadow)] + +## Embedded entities + +> [!NOTE] +> Related entity types are configured as owned by default. To prevent this for a specific entity type call . + +For Azure Cosmos DB, owned entities are embedded in the same item as the owner. To change a property name use [ToJsonProperty](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosEntityTypeBuilderExtensions.ToJsonProperty): + +[!code-csharp[PropertyNames](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=PropertyNames)] + +With this configuration the order from the example above is stored like this: + +```json +{ + "Id": 1, + "PartitionKey": "1", + "TrackingNumber": null, + "id": "1", + "Address": { + "ShipsToCity": "London", + "ShipsToStreet": "221 B Baker St" + }, + "_rid": "6QEKAM+BOOABAAAAAAAAAA==", + "_self": "dbs/6QEKAA==/colls/6QEKAM+BOOA=/docs/6QEKAM+BOOABAAAAAAAAAA==/", + "_etag": "\"00000000-0000-0000-683c-692e763901d5\"", + "_attachments": "attachments/", + "_ts": 1568163674 +} +``` + +Collections of owned entities are embedded as well. For the next example we'll use the `Distributor` class with a collection of `StreetAddress`: + +[!code-csharp[Distributor](../../../../samples/core/Cosmos/ModelBuilding/Distributor.cs?name=Distributor)] + +The owned entities don't need to provide explicit key values to be stored: + +[!code-csharp[OwnedCollection](../../../../samples/core/Cosmos/ModelBuilding/Sample.cs?name=OwnedCollection)] + +They will be persisted in this way: + +```json +{ + "Id": 1, + "Discriminator": "Distributor", + "id": "Distributor|1", + "ShippingCenters": [ + { + "City": "Phoenix", + "Street": "500 S 48th Street" + }, + { + "City": "Anaheim", + "Street": "5650 Dolly Ave" + } + ], + "_rid": "6QEKANzISj0BAAAAAAAAAA==", + "_self": "dbs/6QEKAA==/colls/6QEKANzISj0=/docs/6QEKANzISj0BAAAAAAAAAA==/", + "_etag": "\"00000000-0000-0000-683c-7b2b439701d5\"", + "_attachments": "attachments/", + "_ts": 1568163705 +} +``` + +Internally EF Core always needs to have unique key values for all tracked entities. The primary key created by default for collections of owned types consists of the foreign key properties pointing to the owner and an `int` property corresponding to the index in the JSON array. To retrieve these values entry API could be used: + +[!code-csharp[ImpliedProperties](../../../../samples/core/Cosmos/ModelBuilding/Sample.cs?name=ImpliedProperties)] + +> [!TIP] +> When necessary the default primary key for the owned entity types can be changed, but then key values should be provided explicitly. + +### Collections of primitive types + +Collections of supported primitive types, such as `string` and `int`, are discovered and mapped automatically. Supported collections are all types that implement or . For example, consider this entity type: + + +[!code-csharp[BookEntity](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs?name=BookEntity)] + +The `IList` and the `IDictionary` can be populated and persisted to the database: + + +[!code-csharp[Insert](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs?name=Insert)] + +This results in the following JSON document: + +```json +{ + "Id": "0b32283e-22a8-4103-bb4f-6052604868bd", + "Discriminator": "Book", + "Notes": { + "36": "The Terracotta Army", + "48": "Saint Mark's Basilica", + "121": "Fridges", + "144": "Peter Higgs" + }, + "Quotes": [ + "Thomas (Tommy) Flowers was the British engineer behind the design of the Colossus computer.", + "Invented originally for Guinness, plastic widgets are nitrogen-filled spheres.", + "For 20 years after its introduction in 1979, the Walkman dominated the personal stereo market." + ], + "Title": "How It Works: Incredible History", + "id": "Book|0b32283e-22a8-4103-bb4f-6052604868bd", + "_rid": "t-E3AIxaencBAAAAAAAAAA==", + "_self": "dbs/t-E3AA==/colls/t-E3AIxaenc=/docs/t-E3AIxaencBAAAAAAAAAA==/", + "_etag": "\"00000000-0000-0000-9b50-fc769dc901d7\"", + "_attachments": "attachments/", + "_ts": 1630075016 +} +``` + +These collections can then be updated, again in the normal way: + + +[!code-csharp[Updates](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosPrimitiveTypesSample.cs?name=Updates)] + +Limitations: + +* Only dictionaries with string keys are supported. +* Support for querying into primitive collections was added in EF Core 9.0. + +## Optimistic concurrency with eTags + +To configure an entity type to use [optimistic concurrency](xref:core/saving/concurrency) call . This call will create an `_etag` property in [shadow state](xref:core/modeling/shadow-properties) and set it as the concurrency token. + +[!code-csharp[Main](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=ETag)] + +To make it easier to resolve concurrency errors you can map the eTag to a CLR property using . + +[!code-csharp[Main](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=ETagProperty)] diff --git a/entity-framework/core/providers/cosmos/querying.md b/entity-framework/core/providers/cosmos/querying.md new file mode 100644 index 0000000000..76aed28617 --- /dev/null +++ b/entity-framework/core/providers/cosmos/querying.md @@ -0,0 +1,312 @@ +--- +title: Querying - Azure Cosmos DB Provider - EF Core +description: Querying with the Azure Cosmos DB EF Core Provider +author: roji +ms.date: 09/19/2024 +uid: core/providers/cosmos/querying +--- +# Querying with the EF Core Azure Cosmos DB Provider + +## Querying basics + +[EF Core LINQ queries](xref:core/querying/index) can be executed against Azure Cosmos DB in the same way as for other database providers. For example: + +```csharp +public class Session +{ + public Guid Id { get; set; } + public string Category { get; set; } + + public string TenantId { get; set; } = null!; + public Guid UserId { get; set; } + public int SessionId { get; set; } +} + +var stringResults = await context.Sessions + .Where( + e => e.Category.Length > 4 + && e.Category.Trim().ToLower() != "disabled" + && e.Category.TrimStart().Substring(2, 2).Equals("xy", StringComparison.OrdinalIgnoreCase)) + .ToListAsync(); +``` + +> [!NOTE] +> The Azure Cosmos DB provider does not translate the same set of LINQ queries as other providers. +> For example, the EF `Include()` operator isn't supported on Cosmos, since cross-document queries aren't supported in the database. + +## Partition keys + +The advantage of partitioning is to have your queries execute only against the partition where the relevant data is found, saving costs and ensuring faster result speed. Queries which don't specify partition keys are executed on all the partitions, which can be quite costly. + +Starting with EF 9.0, EF automatically detects and extracts partition key comparisons in your LINQ query's `Where` operators. Let's assume we execute the following query against our `Session` entity type, which is configured with a hierarchical partition key: + +```csharp +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity() + .HasPartitionKey(b => new { b.TenantId, b.UserId, b.SessionId }) +} + +var tenantId = "Microsoft"; +var userId = new Guid("99A410D7-E467-4CC5-92DE-148F3FC53F4C"); +var username = "scott"; + +var sessions = await context.Sessions + .Where( + e => e.TenantId == tenantId + && e.UserId == userId + && e.SessionId > 0 + && e.Username == username) + .ToListAsync(); +``` + +Examining the logs generated by EF, we see this query executed as follows: + +```sql +Executed ReadNext (166.6985 ms, 2.8 RU) ActivityId='312da0d2-095c-4e73-afab-27072b5ad33c', Container='test', Partition='["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c"]', Parameters=[] +SELECT VALUE c +FROM root c +WHERE ((c["SessionId"] > 0) AND CONTAINS(c["Username"], "a")) +``` + +In these logs, we notice the following: + +* The first two comparisons - on `TenantId` and `UserId` - have been lifted out, and appear in the `ReadNext` "Partition" rather than in the `WHERE` clause; this means that query will only execute on the subpartitions for those values. +* `SessionId` is also part of the hierarchical partition key, but instead of an equality comparison, it uses a greater-than operator (`>`), and therefore cannot be lifted out. It is part of the `WHERE` clause like any regular property. +* `Username` is a regular property - not part of the partition key - and therefore remains in the `WHERE` clause as well. + +Note that even though some of the partition key values are not provided, hierarchical partition keys still allow targeting only the subpartitions which correspond to the first two properties. While this isn't as efficient as targeting a single partition (as identified by all three properties), it's still much more efficient than targeting all partitions. + +Rather than referencing partition key properties in a `Where` operator, you can explicitly specify them by using the operator: + +```c# +var sessions = await context.Sessions + .WithPartitionKey(tenantId, userId) + .Where(e => e.SessionId > 0 && e.Username.Contains("a")) + .ToListAsync(); +``` + +This executes in the same way as the above query, and can be preferable if you want to make partition keys more explicit in your queries. Using may be necessary in versions of EF prior to 9.0 - keep an eye on the logs to ensure that queries are using partition keys as expected. + +## Point reads + +While Azure Cosmos DB allows for powerful querying via SQL, such queries can be quite expensive. Cosmos DB also supports _point reads_, which can be used when both the `id` property and the entire partition key are known. Such point reads directly identify a specific document in a specific partition, and execute extremely efficiently and with reduced costs. If at all possible, it's worth designing your system in a way which leverages point reads as much as possible. To read more, see the [Cosmos DB documentation](/azure/cosmos-db/nosql/how-to-dotnet-read-item). + +In the previous section, we saw EF identifying and extracting partition key comparisons from the `Where` clause for more efficient querying, restricting processing only to the relevant partitions. It's possible to go a step further, and provide the `id` property in the query as well. Let's examine the following query: + +```c# +var session = await context.Sessions.SingleAsync( + e => e.Id == someId + && e.TenantId == tenantId + && e.UserId == userId + && e.SessionId == sessionId); +``` + +In this query, a value for the `Id` property is provided (which is mapped to the Cosmos DB `id` property), as well as values for all the partition key properties. Furthermore, there are no additional components to the query. When all these conditions are met, EF is able to execute the query as a point read: + +```console +Executed ReadItem (46 ms, 1 RU) ActivityId='d7391311-2266-4811-ae2d-535904c42c43', Container='test', Id='9', Partition='["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",10.0]' +``` + +Note the `ReadItem`, which indicates that the query was executed as an efficient point read - no SQL query is involved. + +Note that as with partition key extraction, significant improvements have been made to this mechanism in EF 9.0; older versions do not reliably detect and use point reads. + +## Pagination + +> [!NOTE] +> This feature was introduced in EF Core 9.0 and is stil experimental. Please let us know how it works for you and if you have any feedback. + +Pagination refers to retrieving results in pages, rather than all at once; this is typically done for large resultsets, where a user interface is displayed, allowing users to navigate through pages of the results. + +A common way to implement pagination with databases is to use the `Skip` and `Take` LINQ operators (`OFFSET` and `LIMIT` in SQL). Given a page size of 10 results, the third page can be fetched with EF Core as follows: + +```csharp +var position = 20; +var nextPage = context.Session + .OrderBy(s => s.Id) + .Skip(position) + .Take(10) + .ToList(); +``` + +Unfortunately, this technique is quite inefficient and can considerably increase querying costs. Cosmos DB provides a special mechanism for paginating through the result of a query, via the use of _continuation tokens_: + +```csharp +CosmosPage firstPage = await context.Sessions + .OrderBy(s => s.Id) + .ToPageAsync(pageSize: 10, continuationToken: null); + +string continuationToken = firstPage.ContinuationToken; +foreach (var session in firstPage.Values) +{ + // Display/send the sessions to the user +} +``` + +Rather than terminating the LINQ query with `ToListAsync` or similar, we use the `ToPageAsync` method, instructing it to get at most 10 items in every page (note that there may be fewer items in the database). Since this is our first query, we'd like to get results from the beginning, and pass `null` as the continuation token. `ToPageAsync` returns a `CosmosPage`, which exposes a continuation token and the values in the page (up to 10 items). Your program will typically send those values to the client, along with the continuation token; this will allow resuming the query later and fetching more results. + +Let's assume the user now clicks on the "Next" button in their UI, asking for the next 10 items. You can then execute the query as follows: + +```csharp +CosmosPage nextPage = await context.Sessions.OrderBy(s => s.Id).ToPageAsync(10, continuationToken); +string continuationToken = nextPage.ContinuationToken; +foreach (var session in nextPage.Values) +{ + // Display/send the sessions to the user +} +``` + +We execute the same query, but this time we pass in the continuation token received from the first execution; this instructs Cosmos DB to continue the query where it left off, and fetch the next 10 items. Once we fetch the last page and there are no more results, the continuation token will be `null`, and the "Next" button can be grayed out. This method of paginating is extremely efficient and cost-effective compared to using `Skip` and `Take`. + +To learn more about pagination in Cosmos DB, [see this page](/azure/cosmos-db/nosql/query/pagination). + +> [!NOTE] +> Cosmos DB does not support backwards pagination, and does not provide a count of the total pages or items. +> +> `ToPageAsync` is currently annotated as experimental, since it may be replaced with a more general EF pagination API that isn't Cosmos-specific. Although using the current API will generate a compilation warning (`EF9102`), doing so should be safe - future changes may require minor tweaks in the API shape. + +## `FindAsync` + +[`FindAsync`](xref:core/change-tracking/entity-entries#find-and-findasync) is a useful API for getting an entity by its primary key, and avoiding a database roundtrip when the entity has already been loaded and is tracked by the context. + +Developers familiar with relational databases are used to the primary key of an entity type consisting e.g. of an `Id` property. When using the EF Cosmos DB provider, the primary key contains the partition key properties in addition to the property mapped to the JSON `id` property; this is the case since Cosmos DB allows different partitions to contain documents with the same JSON `id` property, and so only the combined `id` and partition key uniquely identify a single document in a container: + +```csharp +public class Session +{ + public Guid Id { get; set; } + public string PartitionKey { get; set; } + ... +} + +var mySession = await context.FindAsync(id, pkey); +``` + +If you have a hierarchical partition key, you must pass all partition key values to `FindAsync`, in the order in which they were configured. + +> [!NOTE] +> Use `FindAsync` only when the entity might already be tracked by your context, and you want to avoid the database roundtrip. +> Otherwise, simply use `SingleAsync` - there is no performance difference between the two when the entity needs to be loaded from the database. + +## SQL queries + +Queries can also be written [directly in SQL](xref:core/querying/sql-queries). For example: + +```csharp +var rating = 3; +_ = await context.Blogs + .FromSql($"SELECT VALUE c FROM root c WHERE c.Rating > {rating}") + .ToListAsync(); +``` + +This query results in the following query execution: + +```sql +SELECT VALUE s +FROM ( + SELECT VALUE c FROM root c WHERE c.Angle1 <= @p0 +) s +``` + +Note that `FromSql` was introduced in EF 9.0. In previous versions, `FromSqlRaw` can be used instead, although note that that method is vulnerable to SQL injection attacks. + +For more information on SQL querying, see the [relational documentation on SQL queries](xref:core/querying/sql-queries); most of that content is relevant for the Cosmos provider as well. + +## Function mappings + +This section shows which .NET methods and members are translated into which SQL functions when querying with the Azure Cosmos DB provider. + +### Date and time functions + +.NET | SQL | Added in +------------------------------------------ | --------------------------------------------------------------------------------- | -------- +DateTime.UtcNow | [GetCurrentDateTime()](/azure/cosmos-db/nosql/query/getcurrentdatetime) +DateTimeOffset.UtcNow | [GetCurrentDateTime()](/azure/cosmos-db/nosql/query/getcurrentdatetime) +dateTime.Year1 | [DateTimePart("yyyy", dateTime)](/azure/cosmos-db/nosql/query/datetimepart) | EF Core 9.0 +dateTimeOffset.Year1 | [DateTimePart("yyyy", dateTimeOffset)](/azure/cosmos-db/nosql/query/datetimepart) | EF Core 9.0 +dateTime.AddYears(years)1 | [DateTimeAdd("yyyy", dateTime)](/azure/cosmos-db/nosql/query/datetimeadd) | EF Core 9.0 +dateTimeOffset.AddYears(years)1 | [DateTimeAdd("yyyy", dateTimeOffset)](/azure/cosmos-db/nosql/query/datetimeadd) | EF Core 9.0 + +1 The other component members are translated as well (Month, Day...). + +### Numeric functions + +.NET | SQL | Added in +-------------------------- | --------------------------------------------------- | -------- +double.DegreesToRadians(x) | [RADIANS(@x)](/azure/cosmos-db/nosql/query/radians) | EF Core 8.0 +double.RadiansToDegrees(x) | [DEGREES(@x)](/azure/cosmos-db/nosql/query/degrees) | EF Core 8.0 +EF.Functions.Random() | [RAND()](/azure/cosmos-db/nosql/query/rand) +Math.Abs(value) | [ABS(@value)](/azure/cosmos-db/nosql/query/abs) +Math.Acos(d) | [ACOS(@d)](/azure/cosmos-db/nosql/query/acos) +Math.Asin(d) | [ASIN(@d)](/azure/cosmos-db/nosql/query/asin) +Math.Atan(d) | [ATAN(@d)](/azure/cosmos-db/nosql/query/atan) +Math.Atan2(y, x) | [ATN2(@y, @x)](/azure/cosmos-db/nosql/query/atn2) +Math.Ceiling(d) | [CEILING(@d)](/azure/cosmos-db/nosql/query/ceiling) +Math.Cos(d) | [COS(@d)](/azure/cosmos-db/nosql/query/cos) +Math.Exp(d) | [EXP(@d)](/azure/cosmos-db/nosql/query/exp) +Math.Floor(d) | [FLOOR(@d)](/azure/cosmos-db/nosql/query/floor) +Math.Log(a, newBase) | [LOG(@a, @newBase)](/azure/cosmos-db/nosql/query/log) +Math.Log(d) | [LOG(@d)](/azure/cosmos-db/nosql/query/log) +Math.Log10(d) | [LOG10(@d)](/azure/cosmos-db/nosql/query/log10) +Math.Pow(x, y) | [POWER(@x, @y)](/azure/cosmos-db/nosql/query/power) +Math.Round(d) | [ROUND(@d)](/azure/cosmos-db/nosql/query/round) +Math.Sign(value) | [SIGN(@value)](/azure/cosmos-db/nosql/query/sign) +Math.Sin(a) | [SIN(@a)](/azure/cosmos-db/nosql/query/sin) +Math.Sqrt(d) | [SQRT(@d)](/azure/cosmos-db/nosql/query/sqrt) +Math.Tan(a) | [TAN(@a)](/azure/cosmos-db/nosql/query/atan) +Math.Truncate(d) | [TRUNC(@d)](/azure/cosmos-db/nosql/query/trunc) + +> [!TIP] +> In addition to the methods listed here, corresponding [generic math](/dotnet/standard/generics/math) implementations +> and [MathF](/dotnet/api/system.mathf) methods are also translated. For example, `Math.Sin`, `MathF.Sin`, `double.Sin`, +> and `float.Sin` all map to the `SIN` function in SQL. + +### String functions + +.NET | SQL | Added in +----------------------------------------------------------------- | ---------------------------------------------------------------------------------- | -------- +Regex.IsMatch(input, pattern) | [RegexMatch(@pattern, @input)](/azure/cosmos-db/nosql/query/regexmatch) | EF Core 7.0 +Regex.IsMatch(input, pattern, options) | [RegexMatch(@input, @pattern, @options)](/azure/cosmos-db/nosql/query/regexmatch) | EF Core 7.0 +string.Concat(str0, str1) | @str0 + @str1 +string.Equals(a, b, StringComparison.Ordinal) | [STRINGEQUALS(@a, @b)](/azure/cosmos-db/nosql/query/stringequals) +string.Equals(a, b, StringComparison.OrdinalIgnoreCase) | [STRINGEQUALS(@a, @b, true)](/azure/cosmos-db/nosql/query/stringequals) +stringValue.Contains(value) | [CONTAINS(@stringValue, @value)](/azure/cosmos-db/nosql/query/contains) +stringValue.Contains(value, StringComparison.Ordinal) | [CONTAINS(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/contains) | EF Core 9.0 +stringValue.Contains(value, StringComparison.OrdinalIgnoreCase) | [CONTAINS(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/contains) | EF Core 9.0 +stringValue.EndsWith(value) | [ENDSWITH(@stringValue, @value)](/azure/cosmos-db/nosql/query/endswith) +stringValue.EndsWith(value, StringComparison.Ordinal) | [ENDSWITH(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/endswith) | EF Core 9.0 +stringValue.EndsWith(value, StringComparison.OrdinalIgnoreCase) | [ENDSWITH(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/endswith) | EF Core 9.0 +stringValue.Equals(value, StringComparison.Ordinal) | [STRINGEQUALS(@stringValue, @value)](/azure/cosmos-db/nosql/query/stringequals) +stringValue.Equals(value, StringComparison.OrdinalIgnoreCase) | [STRINGEQUALS(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/stringequals) +stringValue.FirstOrDefault() | [LEFT(@stringValue, 1)](/azure/cosmos-db/nosql/query/left) +stringValue.IndexOf(value) | [INDEX_OF(@stringValue, @value)](/azure/cosmos-db/nosql/query/index-of) +stringValue.IndexOf(value, startIndex) | [INDEX_OF(@stringValue, @value, @startIndex)](/azure/cosmos-db/nosql/query/index-of) +stringValue.LastOrDefault() | [RIGHT(@stringValue, 1)](/azure/cosmos-db/nosql/query/right) +stringValue.Length | [LENGTH(@stringValue)](/azure/cosmos-db/nosql/query/length) +stringValue.Replace(oldValue, newValue) | [REPLACE(@stringValue, @oldValue, @newValue)](/azure/cosmos-db/nosql/query/replace) +stringValue.StartsWith(value) | [STARTSWITH(@stringValue, @value)](/azure/cosmos-db/nosql/query/startswith) +stringValue.StartsWith(value, StringComparison.Ordinal) | [STARTSWITH(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/startswith) | EF Core 9.0 +stringValue.StartsWith(value, StringComparison.OrdinalIgnoreCase) | [STARTSWITH(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/startswith) | EF Core 9.0 +stringValue.Substring(startIndex) | [SUBSTRING(@stringValue, @startIndex, LENGTH(@stringValue))](/azure/cosmos-db/nosql/query/substring) +stringValue.Substring(startIndex, length) | [SUBSTRING(@stringValue, @startIndex, @length)](/azure/cosmos-db/nosql/query/substring) +stringValue.ToLower() | [LOWER(@stringValue)](/azure/cosmos-db/nosql/query/lower) +stringValue.ToUpper() | [UPPER(@stringValue)](/azure/cosmos-db/nosql/query/upper) +stringValue.Trim() | [TRIM(@stringValue)](/azure/cosmos-db/nosql/query/trim) +stringValue.TrimEnd() | [RTRIM(@stringValue)](/azure/cosmos-db/nosql/query/rtrim) +stringValue.TrimStart() | [LTRIM(@stringValue)](/azure/cosmos-db/nosql/query/ltrim) + +### Miscellaneous functions + +.NET | SQL | Notes +--------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----- +collection.Contains(item) | @item IN @collection +EF.Functions.CoalesceUndefined(x, y)1 | [x ?? y](/azure/cosmos-db/nosql/query/ternary-coalesce-operators#coalesce-operator) | Added in EF Core 9.0 +EF.Functions.IsDefined(x) | [IS_DEFINED(x)](/azure/cosmos-db/nosql/query/is-defined) | Added in EF Core 9.0 +EF.Functions.VectorDistance(vector1, vector2)2 | [VectorDistance(vector1, vector2)](/azure/cosmos-db/nosql/query/vectordistance) | Added in EF Core 9.0, Experimental +EF.Functions.VectorDistance(vector1, vector2, bruteForce)2 | [VectorDistance(vector1, vector2, bruteForce)](/azure/cosmos-db/nosql/query/vectordistance) | Added in EF Core 9.0, Experimental +EF.Functions.VectorDistance(vector1, vector2, bruteForce, distanceFunction)2 | [VectorDistance(vector1, vector2, bruteForce, distanceFunction)](/azure/cosmos-db/nosql/query/vectordistance) | Added in EF Core 9.0, Experimental + +1 Note that `EF.Functions.CoalesceUndefined` coalesces `undefined`, not `null`. To coalesce `null`, use the regular C# `??` operator. + +2 [See the documentation](xref:core/providers/cosmos/vector-search) for information on using vector search in Azure Cosmos DB. Cosmos DB vector searching is experimental and the APIs are subject to change. diff --git a/entity-framework/core/providers/cosmos/vector-search.md b/entity-framework/core/providers/cosmos/vector-search.md new file mode 100644 index 0000000000..5027b5f27d --- /dev/null +++ b/entity-framework/core/providers/cosmos/vector-search.md @@ -0,0 +1,58 @@ +--- +title: Vector Search - Azure Cosmos DB Provider - EF Core +description: Vector search with the Azure Cosmos DB EF Core Provider +author: roji +ms.date: 09/20/2024 +uid: core/providers/cosmos/vector-search +--- +# Vector search + +> [!WARNING] +> Azure Cosmos DB vector search is currently in preview. As a result, using EF's vector search APIs will generate an "experimental API" warning (`EF9103`) which must be suppressed. The APIs and capabilities may change in breaking ways in the future. + +Azure Cosmos DB now offers preview support for vector similarity search. Vector search is a fundamental part of some application types, include AI, semantic search and others. The Cosmos DB support for vector search allows storing your data and vectors, and performing your queries in a single database, which can considerably simplify your architecture and remove the need for an additional, dedicated vector database solution in your stack. To learn more about Cosmos DB vector search, [see the documentation](/azure/cosmos-db/nosql/vector-search). + +To use vector search, you must first [enroll in the preview feature](/azure/cosmos-db/nosql/vector-search#enroll-in-the-vector-search-preview-feature). Then, [define the vector policies on your container](/azure/cosmos-db/nosql/vector-search#container-vector-policies), which determine which JSON property in your documents contain vectors, various vector-related information for those properties (dimensions, data type, distance function). + +Once your container is properly set up, add a vector property to your model in the path you defined in the container policy, and configure it with EF as a vector: + +```c# +public class Blog +{ + ... + + public float[] Vector { get; set; } +} + +public class BloggingContext +{ + ... + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .Property(b => b.Embeddings) + .IsVector(DistanceFunction.Cosine, dimensions: 1536); + } +} +``` + +At this point your model is configured. Insertion of vector data is done just like any other data type with EF: + +```c# +float[] vector = /* generate vector data from text, image, etc. */ +context.Add(new Blog { Vector = vector }); +await context.SaveChangesAsync(); +``` + +Finally, use the `EF.Functions.VectorDistance()` function in LINQ queries to perform vector similarity search: + +```c# +float[] anotherVector = /* generate vector data from text, image, etc. */ +var blogs = await context.Blogs + .OrderBy(s => EF.Functions.VectorDistance(s.Vector, anotherVector)) + .Take(5) + .ToListAsync(); +``` + +This will returns the top five Blogs, based on the similarity of their `Vector` property and the externally-provided `anotherVector` data. diff --git a/entity-framework/core/querying/database-functions.md b/entity-framework/core/querying/database-functions.md index 11889d42fb..dda44347f7 100644 --- a/entity-framework/core/querying/database-functions.md +++ b/entity-framework/core/querying/database-functions.md @@ -52,4 +52,4 @@ Apart from mappings provided by EF Core providers, users can also define custom - [SqlServer built-in function mappings](xref:core/providers/sql-server/functions) - [Sqlite built-in function mappings](xref:core/providers/sqlite/functions) -- [Azure Cosmos DB built-in function mappings](xref:core/providers/cosmos/functions) +- [Azure Cosmos DB built-in function mappings](xref:core/providers/cosmos/querying#function-mappings) diff --git a/entity-framework/core/querying/pagination.md b/entity-framework/core/querying/pagination.md index 13937c48c4..75a3a0821f 100644 --- a/entity-framework/core/querying/pagination.md +++ b/entity-framework/core/querying/pagination.md @@ -12,9 +12,12 @@ Pagination refers to retrieving results in pages, rather than all at once; this > [!WARNING] > Regardless of the pagination method used, always make sure that your ordering is fully unique. For example, if results are ordered only by date, but there can be multiple results with the same date, then results could be skipped when paginating as they're ordered differently across two paginating queries. Ordering by both date and ID (or any other unique property or combination of properties) makes the ordering fully unique and avoids this problem. Note that relational databases do not apply any ordering by default, even on the primary key. +> [!NOTE] +> Azure Cosmos DB has its own mechanism for pagination, [see the dedicated documentation page](xref:core/providers/cosmos/querying#pagination). + ## Offset pagination -A common way to implement pagination with databases is to use the `Skip` and `Take` (`OFFSET` and `LIMIT` in SQL). Given a page size of 10 results, the third page can be fetched with EF Core as follows: +A common way to implement pagination with databases is to use the `Skip` and `Take` LINQ operators (`OFFSET` and `LIMIT` in SQL). Given a page size of 10 results, the third page can be fetched with EF Core as follows: [!code-csharp[Main](../../../samples/core/Querying/Pagination/Program.cs?name=OffsetPagination&highlight=4)] diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index 810ee5f2e9..a237e6e06a 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -20,33 +20,166 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET ## Summary +> [!NOTE] +> If you are using Azure Cosmos DB, please see the [separate section below on Cosmos DB breaking changes](#cosmos-breaking-changes). + | **Breaking change** | **Impact** | |:-----------------------------------------------------------------------------------------------------|------------| -| [Sync I/O via the Azure Cosmos DB provider is no longer supported](#cosmos-nosync) | Medium | -| [EF.Functions.Unhex() now returns `byte[]?`](#unhex) | Low | +| [`EF.Functions.Unhex()` now returns `byte[]?`](#unhex) | Low | | [SqlFunctionExpression's nullability arguments' arity validated](#sqlfunctionexpression-nullability) | Low | -## Medium-impact changes +## Low-impact changes + + + +### `EF.Functions.Unhex()` now returns `byte[]?` + +[Tracking Issue #33864](https://github.com/dotnet/efcore/issues/33864) + +#### Old behavior + +The `EF.Functions.Unhex()` function was previously annotated to return `byte[]`. + +#### New behavior + +Starting with EF Core 9.0, Unhex() is now annotated to return `byte[]?`. + +#### Why + +`Unhex()` is translated to the SQLite `unhex` function, which returns NULL for invalid inputs. As a result, `Unhex()` returned `null` for those cases, in violation of the annotation. + +#### Mitigations + +If you are sure that the text content passed to `Unhex()` represents a valid, hexadecimal string, you can simply add the null-forgiving operator as an assertion that the invocation will never return null: + +```csharp +var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString)!).ToListAsync(); +``` + +Otherwise, add runtime checks for null on the return value of Unhex(). + + + +### SqlFunctionExpression's nullability arguments' arity validated + +[Tracking Issue #33852](https://github.com/dotnet/efcore/issues/33852) + +#### Old behavior + +Previously it was possible to create a `SqlFunctionExpression` with a different number of arguments and nullability propagation arguments. + +#### New behavior + +Starting with EF Core 9.0, EF now throws if the number of arguments and nullability propagation arguments do not match. + +#### Why + +Not having matching number of arguments and nullability propagation arguments can lead to unexpected behavior. + +#### Mitigations + +Make sure the `argumentsPropagateNullability` has same number of elements as the `arguments`. When in doubt use `false` for nullability argument. + +## Cosmos breaking changes + +Extensive work has gone into making the Cosmos DB provider better in 9.0. The changes include a number of high-impact breaking changes; if you are upgrading an existing application, please read the following carefully. + +| **Breaking change** | **Impact** | +|:---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| [The discriminator property is now named `$type` instead of `Discriminator`](#cosmos-discriminator-name-change) | High | +| [The `id` property no longer contains the discriminator by default](#cosmos-id-property-changes) | High | +| [Sync I/O via the Azure Cosmos DB provider is no longer supported](#cosmos-nosync) | Medium | +| [SQL queries must now project JSON values directly](#cosmos-sql-queries-with-value) | Medium | +| [Undefined results are now automatically filtered from query results](#cosmos-undefined-filtering) | Medium | +| [Incorrectly translated queries are no longer translated](#cosmos-incorrect-translations) | Medium | +| [`HasIndex` now throws instead of being ignored](#cosmos-hasindex-throws) | Low | +| [`IncludeRootDiscriminatorInJsonId` was renamed to `HasRootDiscriminatorInJsonId` after 9.0.0-rc.2](#cosmos-IncludeRootDiscriminatorInJsonId-rename) | Low | + +### High-impact changes + + + +#### The discriminator property is now named `$type` instead of `Discriminator` + +[Tracking Issue #34269](https://github.com/dotnet/efcore/issues/34269) + +##### Old behavior + +EF automatically adds a discriminator property to JSON documents to identify the entity type that the document represents. In previous versions of EF, this JSON property used to be named `Discriminator` by default. + +##### New behavior + +Starting with EF Core 9.0, the discriminator property is now called `$type` by default. If you have existing documents in Cosmos DB from previous versions of EF, these use the old `Discriminator` naming, and after upgrading to EF 9.0, queries against those documents will fail. + +##### Why + +An emerging JSON practice uses a `$type` property in scenarios where a document's type needs to be identified. For example, .NET's System.Text.Json also supports polymorphism, using `$type` as its default discriminator property name ([docs](/dotnet/standard/serialization/system-text-json/polymorphism#customize-the-type-discriminator-name)). To align with the rest of the ecosystem and make it easier to interoperate with external tools, the default was changed. + +##### Mitigations + +The easiest mitigation is to simply configure the name of the discriminator property to be `Discriminator`, just as before: + +```csharp +modelBuilder.Entity().HasDiscriminator("Discriminator"); +``` + +Doing this for all your top-level entity types will make EF behave just like before. + +At this point, if you wish, you can also update all your documents to use the new `$type` naming. + + + +#### The `id` property now contains only the EF key property by default + +[Tracking Issue #34179](https://github.com/dotnet/efcore/issues/34179) + +##### Old behavior + +Previously, EF inserted the discriminator value of your entity type into the `id` property of the document. For example, if you saved a `Blog` entity type with an `Id` property containing 8, the JSON `id` property would contain `Blog|8`. + +##### New behavior + +Starting with EF Core 9.0, the JSON `id` property no longer contains the discriminator value, and only contains the avlue of your key property. For the above example, the JSON `id` property would simply be `8`. If you have existing documents in Cosmos DB from previous versions of EF, these have the discriminator value in the JSON `id` property, and after upgrading to EF 9.0, queries against those documents will fail. + +##### Why + +Since the JSON `id` property must be unique, the discriminator was previously added to it so as to allow different entities to exist with the same key value; for example, this allowed having both a `Blog` and a `Post` with an `Id` property containing 8 within the same container and partition. This was assumed to be expected by developers used to relational databases, where each entity type is mapped its own table, and therefore has its own key-space. + +EF 9.0 generally changed the mapping to be more aligned with common Cosmos DB practices and expectations, rather than to correspond to the expectations of users coming from relational databases. In addition, having the discriminator value in the `id` property made it more difficult for external tools and systems to interact with EF-generated JSON documents; such external systems aren't generally aware of the EF discriminator values, which are by default derived from .NET types. + +##### Mitigations + +The easiest mitigation is to simply configure EF to include the discriminator in the JSON `id` property, as before. A new configuration option has been introduced for this purpose: + +```csharp +modelBuilder.Entity().HasDiscriminatorInJsonId(); +``` + +Doing this for all your top-level entity types will make EF behave just like before. + +At this point, if you wish, you can also update all your documents to rewrite their JSON `id` property. Note that this is only possible if entities of different types don't share the same id value within the same container. + +### Medium-impact changes -### Sync I/O via the Azure Cosmos DB provider is no longer supported +#### Sync I/O via the Azure Cosmos DB provider is no longer supported [Tracking Issue #32563](https://github.com/dotnet/efcore/issues/32563) -#### Old behavior +##### Old behavior Previously, calling synchronous methods like `ToList` or `SaveChanges` would cause EF Core to block synchronously using `.GetAwaiter().GetResult()` when executing async calls against the Azure Cosmos DB SDK. This can result in deadlock. -#### New behavior +##### New behavior Starting with EF Core 9.0, EF now throws by default when attempting to use synchronous I/O. The exception message is "Azure Cosmos DB does not support synchronous I/O. Make sure to use and correctly await only async methods when using Entity Framework Core to access Azure Cosmos DB. See [https://aka.ms/ef-cosmos-nosync](https://aka.ms/ef-cosmos-nosync) for more information." -#### Why +##### Why Synchronous blocking on asynchronous methods can result in deadlock, and the Azure Cosmos DB SDK only supports async methods. -#### Mitigations +##### Mitigations In EF Core 9.0, the error can be suppressed with: @@ -59,54 +192,213 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) That being said, applications should stop using sync APIs with Azure Cosmos DB since this is not supported by the Azure Cosmos DB SDK. The ability to suppress the exception will be removed in a future release of EF Core, after which the only option will be to use async APIs. -## Low-impact changes + - +#### SQL queries must now project JSON values directly -### EF.Functions.Unhex() now returns `byte[]?` +[Tracking Issue #25527](https://github.com/dotnet/efcore/issues/25527) -[Tracking Issue #33864](https://github.com/dotnet/efcore/issues/33864) +##### Old behavior -#### Old behavior +Previously, EF generated queries such as the following: -The EF.Functions.Unhex() function was previously annotated to return `byte[]`. +```sql +SELECT c["City"] FROM root c +``` -#### New behavior +Such queries cause Cosmos DB to wrap each result in a JSON object, as follows: + +```json +[ + { + "City": "Berlin" + }, + { + "City": "México D.F." + } +] +``` -Starting with EF Core 9.0, Unhex() is now annotated to return `byte[]?`. +##### New behavior -#### Why +Starting with EF Core 9.0, EF now adds the `VALUE` modifier to queries as follows: -Unhex() is translated to the SQLite `unhex` function, which returns NULL for invalid inputs. As a result, Unhex() returned `null` for those cases, in violation of the annotation. +```sql +SELECT VALUE c["City"] FROM root c +``` -#### Mitigations +Such queries cause Cosmos DB to return the values directly, without being wrapped: + +```json +[ + "Berlin", + "México D.F." +] +``` -If you are sure that the text content passed to Unhex() represents a valid, hexadecimal string, you can simply add the null-forgiving operator as an assertion that the invocation will never return null: +If your application makes use of [SQL queries](xref:core/providers/cosmos/querying#sql-queries), such queries are likely broken after upgrading to EF 9.0, as they don't include the `VALUE` modifier. -```c# -var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString)!).ToListAsync(); +##### Why + +Wrapping each result in an additional JSON object can cause performance degradation in some scenarios, bloats the JSON result payload, and isn't the natural way to work with Cosmos DB. + +##### Mitigations + +To mitigate, simply add the `VALUE` modifier to the projections of your SQL queries, as shown above. + + + +#### Undefined results are now automatically filtered from query results + +[Tracking Issue #25527](https://github.com/dotnet/efcore/issues/25527) + +##### Old behavior + +Previously, EF generated queries such as the following: + +```sql +SELECT c["City"] FROM root c ``` -Otherwise, add runtime checks for null on the return value of Unhex(). +Such queries cause Cosmos DB to wrap each result in a JSON object, as follows: + +```json +[ + { + "City": "Berlin" + }, + { + "City": "México D.F." + } +] +``` - +If any of the results were undefined (e.g. the `City` property was absent from the document), an empty document was returned, and EF would return `null` for that result. -### SqlFunctionExpression's nullability arguments' arity validated +##### New behavior -[Tracking Issue #33852](https://github.com/dotnet/efcore/issues/33852) +Starting with EF Core 9.0, EF now adds the `VALUE` modifier to queries as follows: -#### Old behavior +```sql +SELECT VALUE c["City"] FROM root c +``` -Previously it was possible to create a `SqlFunctionExpression` with a different number of arguments and nullability propagation arguments. +Such queries cause Cosmos DB to return the values directly, without being wrapped: -#### New behavior +```json +[ + "Berlin", + "México D.F." +] +``` -Starting with EF Core 9.0, EF now throws if the number of arguments and nullability propagation arguments do not match. +The Cosmos DB behavior is to automatically filter `undefined` values out of results; this means that if one of the `City` properties is absent from the document, the query would return just a single result, rather than two results, with one being `null`. -#### Why +##### Why -Not having matching number of arguments and nullability propagation arguments can lead to unexpected behavior. +Wrapping each result in an additional JSON object can cause performance degradation in some scenarios, bloats the JSON result payload, and isn't the natural way to work with Cosmos DB. -#### Mitigations +##### Mitigations -Make sure the `argumentsPropagateNullability` has same number of elements as the `arguments`. When in doubt use `false` for nullability argument. +If getting `null` values for undefined results is important for your application, coalesce the `undefined` values to `null` using the new `EF.Functions.Coalesce` operator: + +```csharp +var users = await context.Customer + .Select(c => EF.Functions.CoalesceUndefined(c.City, null)) + .ToListAsync(); +``` + + + +#### Incorrectly translated queries are no longer translated + +[Tracking Issue #34123](https://github.com/dotnet/efcore/issues/34123) + +##### Old behavior + +Previously, EF translated queries such as the following: + +```csharp +var sessions = await context.Sessions + .Take(5) + .Where(s => s.Name.StartsWith("f")) + .ToListAsync(); +``` + +However, the SQL translation for this query was incorrect: + +```sql +SELECT c +FROM root c +WHERE ((c["Discriminator"] = "Session") AND STARTSWITH(c["Name"], "f")) +OFFSET 0 LIMIT @__p_0 +``` + +In SQL, the `WHERE` clause is evaluated _before_ the `OFFSET` and `LIMIT` clauses; but in the LINQ query above, the `Take` operator appears before the `Where` operator. As a result, such queries could return incorrect results. + +##### New behavior + +Starting with EF Core 9.0, such queries are no longer translated, and an exception is thrown. + +##### Why + +Incorrect translations can cause silent data corruption, which can introduce hard-to-discover bugs in your application. EF always prefer to fail-fast by throwing up-front rather than to possibly cause data corruption. + +##### Mitigations + +If you were happy with the previous behavior and would like to execute the same SQL, simply swap around the order of LINQ operators: + +```csharp +var sessions = await context.Sessions + .Where(s => s.Name.StartsWith("f")) + .Take(5) + .ToListAsync(); +``` + +Unfortunately, Cosmos does not currently support the `OFFSET` and `LIMIT` clauses in SQL subqueries, which is what the proper translation of the original LINQ query requires. + +### Low-impact changes + + + +#### `HasIndex` now throws instead of being ignored + +[Tracking Issue #34023](https://github.com/dotnet/efcore/issues/34023) + +##### Old behavior + +Previously, calls to were ignored by the EF Cosmos DB provider. + +##### New behavior + +The provider now throws if is specified. + +##### Why + +In Cosmos DB, all properties are indexed by default, and no indexing needs to be specified. While it's possible to define a custom indexing policy, this isn't currently supported by EF, and can be done via the Azure Portal without EF support. Since calls weren't doing anything, they are no longer allowed. + +##### Mitigations + +Remove any calls to . + + + +#### `IncludeRootDiscriminatorInJsonId` was renamed to `HasRootDiscriminatorInJsonId` after 9.0.0-rc.2 + +[Tracking Issue #34717](https://github.com/dotnet/efcore/pull/34717) + +##### Old behavior + +The `IncludeRootDiscriminatorInJsonId` Cosmos API was introduced in 9.0.0 rc.1. + +##### New behavior + +For the final release of EF Core 9.0, the API was renamed to `HasRootDiscriminatorInJsonId` + +##### Why + +Another related API was renamed to start with `Has` instead of `Include`, and so this one was renamed for consistency as well. + +##### Mitigations + +If your code is using the `IncludeRootDiscriminatorInJsonId` API, simply change it to reference `HasRootDiscriminatorInJsonId` instead. 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 7422428c78..37f6ba9a0b 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 @@ -24,18 +24,60 @@ EF9 targets .NET 8, and can therefore be used with either [.NET 8 (LTS)](https:/ ## Azure Cosmos DB for NoSQL -We are working on significant updates in EF9 to the EF Core database provider for Azure Cosmos DB for NoSQL. +EF 9.0 brings substantial improvements to the EF Core provider for Azure Cosmos DB; significant parts of the provider have been rewritten to provide new functionality, allow new forms of queries, and better align the provider with Cosmos DB best practices. The main high-level improvements are listed below; for a full list, [see this epic issue](https://github.com/dotnet/efcore/issues/33033). -### Hierarchical partition keys +> [!WARNING] +> As part of the improvements going into the provider, a number of high-impact breaking changes had to be made; if you are upgrading an existing application, please read the [breaking changes section](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-breaking-changes) carefully. -> [!TIP] -> The code shown here comes from [HierarchicalPartitionKeysSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs). +### Improvements querying with partition keys and document IDs Each document stored in the Cosmos database has a unique resource ID. In addition, each document can contain a "partition key" which determines the logical partitioning of data such that the database can be effectively scaled. More information on choosing partition keys can be found in [_Partitioning and horizontal scaling in Azure Cosmos DB_](/azure/cosmos-db/partitioning-overview). -Recent releases of Azure Cosmos DB for NoSQL (Cosmos SDK version 3.33.0 or later) have expanded partitioning capabilities to support [subpartitioning through the specification of up to three levels of hierarchy in the partition key](/azure/cosmos-db/hierarchical-partition-keys). EF Core 9 supports specification of hierarchical partition keys in the model, automatic extraction of these values from queries, and manual specification of a hierarchical partition key for a given query. +In EF 9.0, the Cosmos DB provider is significantly better at identifying partition key comparisons in your LINQ queries, and extracting them out to make your queries are only sent to the relevant partition; this can greatly improve the performance of your queries and reduce costs. For example: + +```csharp +var sessions = await context.Sessions + .Where(b => b.PartitionKey == "someValue" && b.Username.StartsWith("x")) + .ToListAsync(); +``` + +In this query, the provider automatically recognizes the comparison on `PartitionKey`; if we examine the logs, we'll see the following: + +```console +Executed ReadNext (189.8434 ms, 2.8 RU) ActivityId='8cd669ed-2ca5-4f2b-8923-338899071361', Container='test', Partition='["someValue"]', Parameters=[] +SELECT VALUE c +FROM root c +WHERE STARTSWITH(c["Username"], "x") +``` + +Note that the `WHERE` clause does not contain `PartitionKey`: that comparison has been "lifted" out and is used to execute the query only against the relevant partition. In previous versions, the comparison was left in the `WHERE` clause in many situations, causing the query to be executed against all partitions and resulting in increased costs and reduced performance. + +In addition, if your query also provides a value for the document's ID property, and doesn't include any other query operations, the provider can apply an additional optimization: + +```csharp +var somePartitionKey = "someValue"; +var someId = 8; +var sessions = await context.Sessions + .Where(b => b.PartitionKey == somePartitionKey && b.Id == someId) + .SingleAsync(); +``` + +The logs show the following for this query: + +```console +Executed ReadItem (73 ms, 1 RU) ActivityId='13f0f8b8-d481-47f0-bf41-67f7deb008b2', Container='test', Id='8', Partition='["someValue"]' +``` + +Here, no SQL query is sent at all. Instead, the provider performs an an extremely efficient _point read_ (`ReadItem` API), which directly fetches the document given the partition key and ID. This is the most efficient and cost-effective kind of read you can perform in Cosmos DB; [see the Cosmos DB documentation](/azure/cosmos-db/nosql/how-to-dotnet-read-item) for more information about point reads. + +To learn more about querying with partition keys and point reads, [see the querying documentation page](xref:core/providers/cosmos/querying). -#### Configuring hierarchical partition keys +### Hierarchical partition keys + +> [!TIP] +> The code shown here comes from [HierarchicalPartitionKeysSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs). + +Azure Cosmos DB originally supported a single partition key, but has since expanded partitioning capabilities to support [subpartitioning through the specification of up to three levels of hierarchy in the partition key](/azure/cosmos-db/hierarchical-partition-keys). EF Core 9 brings full support for hierarchical partition keys, allowing you take advantage of the better performance and cost savings associated with this feature. Partition keys are specified using the model building API, typically in . There must be a mapped property in the entity type for each level of the partition key. For example, consider a `UserSession` entity type: @@ -70,108 +112,7 @@ The following code specifies a three-level partition key using the `TenantId`, ` Notice how, starting with EF Core 9, properties of any mapped type can be used in the partition key. For `bool` and numeric types, like the `int SessionId` property, the value is used directly in the partition key. Other types, like the `Guid UserId` property, are automatically converted to strings. -#### Saving documents with hierarchical partition keys - -Saving a new document with a hierarchical partition key is the same as saving any new document with EF Core. The primary key and partition key properties must have non-default values, or EF Core value generation can be used to create values. For example, the following code inserts `UserSession` documents where the `Id` property is generated by EF Core, and all the partition key properties have been set explicitly: - - -[!code-csharp[Inserts](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=Inserts)] - -The logs from calling `SaveChangesAsync` show in the following `CreateItem` calls: - -```output -info: 6/10/2024 18:41:04.456 CosmosEventId.ExecutedCreateItem[30104] (Microsoft.EntityFrameworkCore.Database.Command) - Executed CreateItem (167 ms, 7.81 RU) ActivityId='23891b55-7375-40e5-aa4b-2c57ca6a376e', Container='UserSessionContext', Id='UserSession|d5e2614b-71f2-4e6b-d41a-08dc89748055', Partition='["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",7.0]' -info: 6/10/2024 18:41:04.478 CosmosEventId.ExecutedCreateItem[30104] (Microsoft.EntityFrameworkCore.Database.Command) - Executed CreateItem (14 ms, 7.81 RU) ActivityId='7fdcfb3e-455c-45dd-b444-02b66575a28f', Container='UserSessionContext', Id='UserSession|01cc0102-5212-4785-d41b-08dc89748055', Partition='["Microsoft","adae5dde-8a67-432d-9dec-fd7ec86fd9f6",7.0]' -info: 6/10/2024 18:41:04.491 CosmosEventId.ExecutedCreateItem[30104] (Microsoft.EntityFrameworkCore.Database.Command) - Executed CreateItem (13 ms, 7.81 RU) ActivityId='3f7e6026-8edf-4f2c-8918-09434dc039bf', Container='UserSessionContext', Id='UserSession|e5a467c0-bb1e-4ffe-d41c-08dc89748055', Partition='["Microsoft","61967254-aff8-493a-b7f8-e62da36d8367",7.0]' -info: 6/10/2024 18:41:04.507 CosmosEventId.ExecutedCreateItem[30104] (Microsoft.EntityFrameworkCore.Database.Command) - Executed CreateItem (15 ms, 7.81 RU) ActivityId='04c6f4b2-0ad0-4708-874e-dc8967726d18', Container='UserSessionContext', Id='UserSession|fd47726a-fb68-4c63-d41d-08dc89748055', Partition='["Microsoft","bc0150cf-5147-44b8-8823-865f4f2323e1",7.0]' -``` - -Notice that the partition key values have been extracted from the entity instance and included in the call to `CreateItem` to ensure maximum efficiency on the server. - -#### Point reads using hierarchical partition keys - -By convention, EF Core includes the partition key properties in the primary key definition for the entity type. For example, inspecting the [model debug view](xref:core/modeling/index#debug-view) shows the following mapping for the `UserSession` entity type: - -```output -EntityType: UserSession - Properties: - Id (Guid) Required PK AfterSave:Throw ValueGenerated.OnAdd - TenantId (string) Required PK AfterSave:Throw - UserId (Guid) Required PK AfterSave:Throw - SessionId (int) Required PK AfterSave:Throw - Discriminator (no field, string) Shadow Required AfterSave:Throw - Username (string) - __id (no field, string) Shadow Required AlternateKey AfterSave:Throw - __jObject (no field, JObject) Shadow BeforeSave:Ignore AfterSave:Ignore ValueGenerated.OnAddOrUpdate - Keys: - Id, TenantId, UserId, SessionId PK - __id, TenantId, UserId, SessionId -``` - -Notice that the primary key definition is `Id, TenantId, UserId, SessionId`. This means that can be used to lookup a document. For example: - - -[!code-csharp[FindAsync](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=FindAsync)] - -Logging from EF Core shows that a point-read (using `ReadItem`) is executed for maximum efficiency: - -```output -info: 6/10/2024 18:41:04.651 CosmosEventId.ExecutingReadItem[30101] (Microsoft.EntityFrameworkCore.Database.Command) - Reading resource 'UserSession|e5a467c0-bb1e-4ffe-d41c-08dc89748055' item from container 'UserSessionContext' in partition '["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",7.0]'. -info: 6/10/2024 18:41:04.668 CosmosEventId.ExecutedReadItem[30103] (Microsoft.EntityFrameworkCore.Database.Command) - Executed ReadItem (8 ms, 1 RU) ActivityId='a016f26c-6bd0-4c66-953b-a8f1297df41a', Container='UserSessionContext', Id='UserSession|e5a467c0-bb1e-4ffe-d41c-08dc89748055', Partition='["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",7.0]' -``` - -#### Queries using hierarchical partition keys - -EF Core will extract the partition key values from queries and apply them to the Cosmos query API to ensure the queries are constrained appropriately to the fewest number of partitions possible. For example, consider a LINQ query that supplies values for all levels of the partition key: +When querying, EF automatically extracts the partition key values from queries and applies them to the Cosmos query API to ensure the queries are constrained appropriately to the fewest number of partitions possible. For example, consider the following LINQ query that supplies the partition key values: -[!code-csharp[TopTwoPartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=TopTwoPartitionKey)] +* The Cosmos provider now fully supports EF's primitive collections, allowing you to perform LINQ querying on collections of e.g. ints or strings. See [What's new in EF8: primitive collections](xref:core/what-is-new/ef-core-8.0/whatsnew#primitive-collections) for more information. +* Support for arbitrary querying over non-primitive collections has been added as well. +* Lots of additional LINQ operators are now supported: indexing into collections, `Length`/`Count`, `ElementAt`, `Contains`, and many others. +* Support for aggregate operators such as `Count` and `Sum` has been added. +* Many function translations have added (see the [function mappings documentation](xref:core/providers/cosmos/querying#function-mappings) for the full list of supported translations): + * Translations for `DateTime` and `DateTimeOffset` component members (`DateTime.Year`, `DateTimeOffset.Month`...) have been added. + * `EF.Functions.IsDefined` and `EF.Functions.CoalesceUndefined` now allow dealing with `undefined` values. + * `string.Contains`, `StartsWith` and `EndsWith` now support `StringComparison.OrdinalIgnoreCase`. -EF Core still extracts the partition key values when executing this query: +For the full list of querying improvements, see [this issue](https://github.com/dotnet/efcore/issues/33033): -```output -info: 6/10/2024 19:24:46.581 CosmosEventId.ExecutingSqlQuery[30100] (Microsoft.EntityFrameworkCore.Database.Command) - Executing SQL query for container 'UserSessionContext' in partition '["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c"]' [Parameters=[]] - SELECT c - FROM root c - WHERE ((c["Discriminator"] = "UserSession") AND CONTAINS(c["Username"], "a")) +### Improved modeling aligned to Cosmos and JSON standards + +EF 9.0 maps to Cosmos DB documents in ways which are more natural for a JSON-based document database, and help interoperate with other systems accessing your documents. Although this entails breaking changes, APIs exist which allow reverting back to the pre-9.0 behavior in all cases. + +#### Simplified `id` properties without discriminators + +First, previous versions of EF inserted the discriminator value into the JSON `id` property, producing documents such as the following: + +```json +{ + "id": "Blog|1099", + ... +} ``` -This query does not include the `SessionId`, so it cannot target a single partition. However, it will still be a targeted, cross-partition query returning data for all sessions of a single tenant and user ID. +This was done in order to allow for documents of different types (e.g. Blog and Post) and the same key value (1099) to exist within the same container partition. Starting with EF 9.0, the `id` property contains contains only the key value: -Likewise, if only the top value in the hierarchy is specified, then it will be used on its own. For example: +```json +{ + "id": 1099, + ... +} +``` - -[!code-csharp[TopOnePartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=TopOnePartitionKey)] +Note this is a breaking change, since EF will no longer be able to query existing documents with the old `id` format. An API has been introduced to revert to the previous behavior, see the [breaking change note](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-id-property-changes) and the [the documentation](xref:core/providers/cosmos/modeling#Discriminators) for more details. -Which results in the following logs: +#### Discriminator property renamed to `$type` -```output -info: 6/11/2024 09:30:42.532 CosmosEventId.ExecutingSqlQuery[30100] (Microsoft.EntityFrameworkCore.Database.Command) - Executing SQL query for container 'UserSessionContext' in partition '["Microsoft"]' [Parameters=[]] - SELECT c - FROM root c - WHERE ((c["Discriminator"] = "UserSession") AND CONTAINS(c["Username"], "a")) +The default discriminator property was previously named `Discriminator`. EF 9.0 changes the default to `$type`: + +```json +{ + "id": 1099, + "$type": "Blog", + ... +} ``` -Since this query only contains the `TenantId` part of the partition key it cannot target a single partition. However, as with the previous example it will still be a targeted, cross-partition query returning data for all sessions and users in a single tenant. +This follows the emerging standard for JSON polymorphism, allowing better interoperability with other tools. For example, .NET's System.Text.Json also supports polymorphism, using `$type` as its default discriminator property name ([docs](/dotnet/standard/serialization/system-text-json/polymorphism#customize-the-type-discriminator-name)). -It is important to understand that using the second and/or third values of the hierarchical partition key, without including the first value, will result in a query that covers all partitions. For example, consider a query including both `SessionId` and `UserId`, but not including `TenantId`: +Note this is a breaking change, since EF will no longer be able to query existing documents with the old discriminator property name. See the [breaking change note](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-discriminator-name-change) for details on how to revert to the previous naming. - -[!code-csharp[BottomTwoPartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=BottomTwoPartitionKey)] +### Vector similarity search (preview) -The logs show that this is translated without a partition key, since the `TenantId` is missing: +Azure Cosmos DB now offers preview support for vector similarity search. Vector search is a fundamental part of some application types, include AI, semantic search and others. The Cosmos DB support for vector search allows storing your data and vectors and performing your queries in a single database, which can considerably simplify your architecture and remove the need for an additional, dedicated vector database solution in your stack. To learn more about Cosmos DB vector search, [see the documentation](/azure/cosmos-db/nosql/vector-search). -```output -info: 6/11/2024 09:30:42.553 CosmosEventId.ExecutingSqlQuery[30100] (Microsoft.EntityFrameworkCore.Database.Command) - Executing SQL query for container 'UserSessionContext' in partition 'None' [Parameters=[]] - SELECT c - FROM root c - WHERE (c["Discriminator"] = "UserSession") +Once your Cosmos DB container is properly set up, using vector search via EF is a simple matter of adding a vector property and configuring it: + +```c# +public class Blog +{ + ... + + public float[] Vector { get; set; } +} + +public class BloggingContext +{ + ... + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .Property(b => b.Embeddings) + .IsVector(DistanceFunction.Cosine, dimensions: 1536); + } +} ``` -> [!NOTE] -> [Issue #33960](https://github.com/dotnet/efcore/issues/33960) is tracking a bug in this translation. +Once that's done, use the `EF.Functions.VectorDistance()` function in LINQ queries to perform vector similarity search: -### Role-based access +```c# +var blogs = await context.Blogs + .OrderBy(s => EF.Functions.VectorDistance(s.Vector, vector)) + .Take(5) + .ToListAsync(); +``` -Azure Cosmos DB for NoSQL includes a [built-in role-based access control (RBAC) system](/azure/cosmos-db/role-based-access-control). This is now supported by EF9 for both management and use of containers. No changes are required to application code. See [Issue #32197](https://github.com/dotnet/efcore/issues/32197) for more information. +For more information, see the [documentation on vector search](xref:core/providers/cosmos/vector-search). -### Synchronous access blocked by default +### Pagination support -> [!TIP] -> The code shown here comes from [CosmosSyncApisSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosSyncApisSample.cs). +The Cosmos DB provider now allows for paginating through query results via _continuation tokens_, which is far more efficient and cost-effective than the traditional use of `Skip` and `Take`: -Azure Cosmos DB for NoSQL does not support synchronous (blocking) access from application code. Previously, EF masked this by default by blocking for you on async calls. However, this both encourages sync use, which is bad practice, and [may cause deadlocks](https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). Therefore, starting with EF9, an exception is thrown when synchronous access is attempted. For example: +```c# +var firstPage = await context.Posts + .OrderBy(p => p.Id) + .ToPageAsync(pageSize: 10, continuationToken: null); -```output -System.InvalidOperationException: An error was generated for warning 'Microsoft.EntityFrameworkCore.Database.SyncNotSupported': - Azure Cosmos DB does not support synchronous I/O. Make sure to use and correctly await only async methods when using - Entity Framework Core to access Azure Cosmos DB. See https://aka.ms/ef-cosmos-nosync for more information. - This exception can be suppressed or logged by passing event ID 'CosmosEventId.SyncNotSupported' to the 'ConfigureWarnings' - method in 'DbContext.OnConfiguring' or 'AddDbContext'. - at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition.Log[TLoggerCategory](IDiagnosticsLogger`1 logger, Exception exception) - at Microsoft.EntityFrameworkCore.Cosmos.Diagnostics.Internal.CosmosLoggerExtensions.SyncNotSupported(IDiagnosticsLogger`1 diagnostics) - at Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal.CosmosClientWrapper.DeleteDatabase() - at Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal.CosmosDatabaseCreator.EnsureDeleted() - at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted() +var continuationToken = page.ContinuationToken; +foreach (var post in page.Values) +{ + // Display/send the posts to the user +} ``` -As the exception says, sync access can still be used for now by configuring the warning level appropriately. For example, in `OnConfiguring` on your `DbContext` type: +The new `ToPageAsync` operator returns a `CosmosPage`, which exposes a continuation token that can be used to efficiently resume the query at a later point, fetching the next 10 items: -```csharp -protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.ConfigureWarnings(b => b.Ignore(CosmosEventId.SyncNotSupported)); +```c# +var nextPage = await context.Sessions.OrderBy(s => s.Id).ToPageAsync(10, continuationToken); ``` -Note, however, that we plan to fully remove sync support in EF11, so start updating to use async methods like `ToListAsync` and `SaveChangesAsync` as soon as possible! +For more information, [see the documentation section on pagination](xref:core/providers/cosmos/querying#pagination). -### Enhanced primitive collections +### FromSql for safer SQL querying -> [!TIP] -> The code shown here comes from [CosmosPrimitiveTypesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosPrimitiveTypesSample.cs). +The Cosmos DB provider has allowed SQL querying via . However, that API can be susceptible to SQL injection attacks when user-provided data is interpolated or concatenated into the SQL. In EF 9.0, you can now use the new `FromSql` method, which always integrates parameterized data as a parameter outside the SQL: + +```c# +var maxAngle = 8; +_ = await context.Blogs + .FromSql($"SELECT VALUE c FROM root c WHERE c.Angle1 <= {maxAngle}") + .ToListAsync(); +``` -The Cosmos DB provider has supported primitive collections in a limited form since EF Core 6. This is support is being enhanced in EF9, starting with consolidation of the metadata and API surfaces for primitive collections in document databases to align with primitive collections in relational databases. This means that primitive collections can now be explicitly mapped using the model building API, allowing for facets of the element type to be configured. For example, to map a list of required (i.e. non-null) strings: +For more information, [see the documentation section on pagination](xref:core/providers/cosmos/querying#pagination). - -[!code-csharp[ConfigureCollection](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/CosmosPrimitiveTypesSample.cs?name=ConfigureCollection)] +### Role-based access + +Azure Cosmos DB for NoSQL includes a [built-in role-based access control (RBAC) system](/azure/cosmos-db/role-based-access-control). This is now supported by EF9 for both management and use of containers. No changes are required to application code. See [Issue #32197](https://github.com/dotnet/efcore/issues/32197) for more information. + +### Synchronous I/O is now blocked by default + +Azure Cosmos DB for NoSQL does not support synchronous (blocking) APIs from application code. Previously, EF masked this by blocking for you on async calls. However, this both encourages synchronous I/O use, which is bad practice, and [may cause deadlocks](https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html). Therefore, starting with EF 9, an exception is thrown when synchronous access is attempted. For example: + +Synchronous I/O can still be used for now by configuring the warning level appropriately. For example, in `OnConfiguring` on your `DbContext` type: + +```csharp +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.ConfigureWarnings(b => b.Ignore(CosmosEventId.SyncNotSupported)); +``` -See [What's new in EF8: primitive collections](xref:core/what-is-new/ef-core-8.0/whatsnew#primitive-collections) for more information on the model building API. +Note, however, that we plan to fully remove sync support in EF 11, so start updating to use async methods like `ToListAsync` and `SaveChangesAsync` as soon as possible! ## AOT and pre-compiled queries As mentioned in the introduction, there is a lot of work going on behind the scenes to allow EF Core to run without just-in-time (JIT) compilation. Instead, EF compile ahead-of-time (AOT) everything needed to run queries in the application. This AOT compilation and related processing will happen as part of building and publishing the application. At this point in the EF9 release, there is not much available that can be used by you, the app developer. However, for those interested, the completed issues in EF9 that support AOT and pre-compiled queries are: -- [Compiled model: Use static binding instead of reflection for properties and fields](https://github.com/dotnet/efcore/issues/24900) -- [Compiled model: Generate lambdas used in change tracking](https://github.com/dotnet/efcore/issues/24904) -- [Make change tracking and the update pipeline compatible with AOT/trimming](https://github.com/dotnet/efcore/issues/29761) -- [Use interceptors to redirect the query to precompiled code](https://github.com/dotnet/efcore/issues/31331) -- [Make all SQL expression nodes quotable](https://github.com/dotnet/efcore/issues/33008) -- [Generate the compiled model during build](https://github.com/dotnet/efcore/issues/24894) -- [Discover the compiled model automatically](https://github.com/dotnet/efcore/issues/24893) -- [Make ParameterExtractingExpressionVisitor capable of extracting paths to evaluatable fragments in the tree](https://github.com/dotnet/efcore/issues/32999) -- [Generate expression trees in compiled models (query filters, value converters)](https://github.com/dotnet/efcore/issues/29924) -- [Make LinqToCSharpSyntaxTranslator more resilient to multiple declaration of the same variable in nested scopes](https://github.com/dotnet/efcore/issues/32716) -- [Optimize ParameterExtractingExpressionVisitor](https://github.com/dotnet/efcore/issues/32698) +* [Compiled model: Use static binding instead of reflection for properties and fields](https://github.com/dotnet/efcore/issues/24900) +* [Compiled model: Generate lambdas used in change tracking](https://github.com/dotnet/efcore/issues/24904) +* [Make change tracking and the update pipeline compatible with AOT/trimming](https://github.com/dotnet/efcore/issues/29761) +* [Use interceptors to redirect the query to precompiled code](https://github.com/dotnet/efcore/issues/31331) +* [Make all SQL expression nodes quotable](https://github.com/dotnet/efcore/issues/33008) +* [Generate the compiled model during build](https://github.com/dotnet/efcore/issues/24894) +* [Discover the compiled model automatically](https://github.com/dotnet/efcore/issues/24893) +* [Make ParameterExtractingExpressionVisitor capable of extracting paths to evaluatable fragments in the tree](https://github.com/dotnet/efcore/issues/32999) +* [Generate expression trees in compiled models (query filters, value converters)](https://github.com/dotnet/efcore/issues/29924) +* [Make LinqToCSharpSyntaxTranslator more resilient to multiple declaration of the same variable in nested scopes](https://github.com/dotnet/efcore/issues/32716) +* [Optimize ParameterExtractingExpressionVisitor](https://github.com/dotnet/efcore/issues/32698) Check back here for examples of how to use pre-compiled queries as the experience comes together. @@ -905,15 +869,15 @@ FROM [Posts] AS [p] ### Other query improvements -- The primitive collections querying support [introduced in EF8](xref:core/what-is-new/ef-core-8.0/whatsnew#queries-with-primitive-collections) has been extended to support all `ICollection` types. Note that this applies only to parameter and inline collections - primitive collections that are part of entities are still limited to arrays, lists and [in EF9 also read-only arrays/lists](#read-only-primitive-collections). -- New `ToHashSetAsync` functions to return the results of a query as a `HashSet` ([#30033](https://github.com/dotnet/efcore/issues/30033), contributed by [@wertzui](https://github.com/wertzui)). -- `TimeOnly.FromDateTime` and `FromTimeSpan` are now translated on SQL Server ([#33678](https://github.com/dotnet/efcore/issues/33678)). -- `ToString` over enums is now translated ([#33706](https://github.com/dotnet/efcore/pull/33706), contributed by [@Danevandy99](https://github.com/Danevandy99)). -- `string.Join` now translates to [CONCAT_WS](/sql/t-sql/functions/concat-ws-transact-sql) in non-aggregate context on SQL Server ([#28899](https://github.com/dotnet/efcore/issues/28899)). -- `EF.Functions.PatIndex` now translates to the SQL Server [`PATINDEX`](/sql/t-sql/functions/patindex-transact-sql) function, which returns the starting position of the first occurrence of a pattern ([#33702](https://github.com/dotnet/efcore/issues/33702), [@smnsht](https://github.com/smnsht)). -- `Sum` and `Average` now work for decimals on SQLite ([#33721](https://github.com/dotnet/efcore/pull/33721), contributed by [@ranma42](https://github.com/ranma42)). -- Fixes and optimizations to `string.StartsWith` and `EndsWith` ([#31482](https://github.com/dotnet/efcore/pull/31482)). -- `Convert.To*` methods can now accept argument of type `object` ([#33891](https://github.com/dotnet/efcore/pull/33891), contributed by [@imangd](https://github.com/imangd)). +* The primitive collections querying support [introduced in EF8](xref:core/what-is-new/ef-core-8.0/whatsnew#queries-with-primitive-collections) has been extended to support all `ICollection` types. Note that this applies only to parameter and inline collections - primitive collections that are part of entities are still limited to arrays, lists and [in EF9 also read-only arrays/lists](#read-only-primitive-collections). +* New `ToHashSetAsync` functions to return the results of a query as a `HashSet` ([#30033](https://github.com/dotnet/efcore/issues/30033), contributed by [@wertzui](https://github.com/wertzui)). +* `TimeOnly.FromDateTime` and `FromTimeSpan` are now translated on SQL Server ([#33678](https://github.com/dotnet/efcore/issues/33678)). +* `ToString` over enums is now translated ([#33706](https://github.com/dotnet/efcore/pull/33706), contributed by [@Danevandy99](https://github.com/Danevandy99)). +* `string.Join` now translates to [CONCAT_WS](/sql/t-sql/functions/concat-ws-transact-sql) in non-aggregate context on SQL Server ([#28899](https://github.com/dotnet/efcore/issues/28899)). +* `EF.Functions.PatIndex` now translates to the SQL Server [`PATINDEX`](/sql/t-sql/functions/patindex-transact-sql) function, which returns the starting position of the first occurrence of a pattern ([#33702](https://github.com/dotnet/efcore/issues/33702), [@smnsht](https://github.com/smnsht)). +* `Sum` and `Average` now work for decimals on SQLite ([#33721](https://github.com/dotnet/efcore/pull/33721), contributed by [@ranma42](https://github.com/ranma42)). +* Fixes and optimizations to `string.StartsWith` and `EndsWith` ([#31482](https://github.com/dotnet/efcore/pull/31482)). +* `Convert.To*` methods can now accept argument of type `object` ([#33891](https://github.com/dotnet/efcore/pull/33891), contributed by [@imangd](https://github.com/imangd)). The above were only some of the more important query improvements in EF9; see [this issue](https://github.com/dotnet/efcore/issues/34151) for a more complete listing. diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index aa4fe15a08..aaf1079e93 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -428,12 +428,16 @@ items: - name: Overview href: core/providers/cosmos/index.md + - name: Modeling + href: core/providers/cosmos/modeling.md + - name: Querying + href: core/providers/cosmos/querying.md - name: Work with unstructured data href: core/providers/cosmos/unstructured-data.md + - name: Vector search + href: core/providers/cosmos/vector-search.md - name: Azure Cosmos DB limitations href: core/providers/cosmos/limitations.md - - name: Function mappings - href: core/providers/cosmos/functions.md - name: End-to-end sample href: core/providers/cosmos/planetary-docs-sample.md - name: In-memory (not recommended) From 72bcbccdec3ab80139d34d8b0ef03343afb37046 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 1 Oct 2024 13:00:31 -0700 Subject: [PATCH 041/224] Update Cosmos notes related to RBAC (#4822) --- entity-framework/core/providers/cosmos/index.md | 9 +++++---- .../core/what-is-new/ef-core-9.0/whatsnew.md | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/entity-framework/core/providers/cosmos/index.md b/entity-framework/core/providers/cosmos/index.md index 07794a9956..f318c7c96e 100644 --- a/entity-framework/core/providers/cosmos/index.md +++ b/entity-framework/core/providers/cosmos/index.md @@ -68,12 +68,13 @@ The Azure Cosmos DB provider for EF Core has multiple overloads of the [UseCosmo > [!IMPORTANT] > Make sure to understand [_Secure access to data in Azure Cosmos DB_](/azure/cosmos-db/secure-access-to-data) to understand the security implications and best practices for using each overload of the `UseCosmos` method. +> Generally, RBAC with token credentials is the recommended access-control mechanism. | Connection Mechanism | UseCosmos Overload | More information | -|----------------------------|------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| -| Account endpoint and key | `UseCosmos(accountEndpoint, accountKey, databaseName)` | [Primary/secondary keys](/azure/cosmos-db/secure-access-to-data#primary-keys) | -| Account endpoint and token | `UseCosmos(accountEndpoint, tokenCredential, databaseName)` | [Resource tokens](/azure/cosmos-db/secure-access-to-data#primary-keys) | -| Connection string | `UseCosmos(connectionString, databaseName)` | [Work with account keys and connection strings](/azure/cosmos-db/scripts/cli/common/keys) | +|----------------------------|------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| +| Account endpoint and key | `UseCosmos(accountEndpoint, accountKey, databaseName)` | [Primary/secondary keys](/azure/cosmos-db/secure-access-to-data#primary-keys) | +| Account endpoint and token | `UseCosmos(accountEndpoint, tokenCredential, databaseName)` | [RBAC and Resource tokens](/azure/cosmos-db/secure-access-to-data#role-based-access-control) | +| Connection string | `UseCosmos(connectionString, databaseName)` | [Work with account keys and connection strings](/azure/cosmos-db/scripts/cli/common/keys) | ## Azure Cosmos DB options 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 37f6ba9a0b..01dfa1a291 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 @@ -279,7 +279,7 @@ For more information, [see the documentation section on pagination](xref:core/pr ### Role-based access -Azure Cosmos DB for NoSQL includes a [built-in role-based access control (RBAC) system](/azure/cosmos-db/role-based-access-control). This is now supported by EF9 for both management and use of containers. No changes are required to application code. See [Issue #32197](https://github.com/dotnet/efcore/issues/32197) for more information. +Azure Cosmos DB for NoSQL includes a [built-in role-based access control (RBAC) system](/azure/cosmos-db/role-based-access-control). This is now supported by EF9 for all data plane operations. However, Azure Cosmos DB SDK does not support RBAC for management plane operations in Azure Cosmos DB. Use Azure Management API instead of `EnsureCreatedAsync` with RBAC. ### Synchronous I/O is now blocked by default From 0214bec0a59f8c76ea603d0f2b8867955aa7eb6e Mon Sep 17 00:00:00 2001 From: Justine Cocchi Date: Tue, 1 Oct 2024 13:05:36 -0700 Subject: [PATCH 042/224] update cosmos ef docs (#4820) --- .../core/providers/cosmos/index.md | 2 +- .../core/providers/cosmos/limitations.md | 12 +++--- .../core/providers/cosmos/modeling.md | 26 ++++++------ .../core/providers/cosmos/querying.md | 24 +++++------ .../core/providers/cosmos/vector-search.md | 4 +- .../ef-core-9.0/breaking-changes.md | 34 ++++++++-------- .../core/what-is-new/ef-core-9.0/whatsnew.md | 40 +++++++++---------- 7 files changed, 71 insertions(+), 71 deletions(-) diff --git a/entity-framework/core/providers/cosmos/index.md b/entity-framework/core/providers/cosmos/index.md index f318c7c96e..a6eca38b28 100644 --- a/entity-framework/core/providers/cosmos/index.md +++ b/entity-framework/core/providers/cosmos/index.md @@ -8,7 +8,7 @@ uid: core/providers/cosmos/index # EF Core Azure Cosmos DB Provider > [!WARNING] -> Extensive work has gone into the Cosmos DB provider in 9.0. In order to improve the provider, a number of high-impact breaking changes had to be made; if you are upgrading an existing application, please read the [breaking changes section](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-breaking-changes) carefully. +> Extensive work has gone into the Azure Cosmos DB provider in 9.0. In order to improve the provider, a number of high-impact breaking changes had to be made; if you are upgrading an existing application, please read the [breaking changes section](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-breaking-changes) carefully. This database provider allows Entity Framework Core to be used with Azure Cosmos DB. The provider is maintained as part of the [Entity Framework Core Project](https://github.com/dotnet/efcore). diff --git a/entity-framework/core/providers/cosmos/limitations.md b/entity-framework/core/providers/cosmos/limitations.md index 8312ba552b..26cc0f153c 100644 --- a/entity-framework/core/providers/cosmos/limitations.md +++ b/entity-framework/core/providers/cosmos/limitations.md @@ -7,18 +7,18 @@ uid: core/providers/cosmos/limitations --- # EF Core Azure Cosmos DB Provider Limitations -The Azure Cosmos DB database provider targets the Azure Cosmos DB NoSQL store, which is a [document database](https://en.wikipedia.org/wiki/Document-oriented_database). Most EF Core providers target [relational databases](https://en.wikipedia.org/wiki/Relational_database). Document databases and relational databases behave in fundamentally different ways. EF Core does not attempt to hide these differences; rather EF Core provides common patterns that can be used successfully across both kinds of database, together with features tailed to a particular provider that follow best practices for a given type of database. If a feature of EF Core is a pit-of-failure for a certain kind of database, then typically the database provider will not implement that feature, and instead help steer uses towards a [pit-of-success](/archive/blogs/brada/the-pit-of-success) approach. +The Azure Cosmos DB database provider targets the Azure Cosmos DB NoSQL store, which is a [document database](https://en.wikipedia.org/wiki/Document-oriented_database). Most EF Core providers target [relational databases](https://en.wikipedia.org/wiki/Relational_database). Document databases and relational databases behave in fundamentally different ways. EF Core does not attempt to hide these differences; rather EF Core provides common patterns that can be used successfully across both kinds of database, together with features tailored to a particular provider that follow best practices for a given type of database. If a feature of EF Core is a pit-of-failure for a certain kind of database, then typically the database provider will not implement that feature, and instead help steer uses towards a [pit-of-success](/archive/blogs/brada/the-pit-of-success) approach. Common EF Core patterns that either do not apply, or are a pit-of-failure, when using a document database include: -- Schema migration is not supported, since there is no defined schema for the documents. However, there could be other mechanisms for dealing with evolving data shapes that do make sense with Azure Cosmos DB NoSQL, For example, [Schema versioning pattern with Cosmos DB](https://github.com/dotnet/efcore/issues/23753), and [Cosmos data migration](https://github.com/dotnet/efcore/issues/11099). -- Reverse-engineering (scaffolding) a model from an existing database is not supported. Again, this is not supported because there is no defined database schema to scaffold from. However, see [Use shape of documents in the Cosmos database to scaffold a schema](https://github.com/dotnet/efcore/issues/30290). +- Schema migration is not supported, since there is no defined schema for the documents. However, there could be other mechanisms for dealing with evolving data shapes that do make sense with Azure Cosmos DB NoSQL, For example, [Schema versioning pattern with Azure Cosmos DB](https://github.com/dotnet/efcore/issues/23753), and [Azure Cosmos DB data migration](https://github.com/dotnet/efcore/issues/11099). +- Reverse-engineering (scaffolding) a model from an existing database is not supported. Again, this is not supported because there is no defined database schema to scaffold from. However, see [Use shape of documents in the Azure Cosmos DB database to scaffold a schema](https://github.com/dotnet/efcore/issues/30290). - Schema concepts defined on the EF model, like indexes and constraints, are ignored when using a document database, since there is no schema. Note that Azure Cosmos DB NoSQL performs [automatic indexing of documents](/azure/cosmos-db/index-overview). -- Loading graphs of related entities from different documents is not supported. Document databases are not designed to perform joins across many documents; doing so would be very inefficient. Instead, it is more common to denormalize data so that everything needed is in one, or a small number, of documents. However, there are some forms of cross-document relationships that could be handled--see [Limited Include support for Cosmos](https://github.com/dotnet/efcore/issues/16920#issuecomment-989721078). +- Loading graphs of related entities from different documents is not supported. Document databases are not designed to perform joins across many documents; doing so would be very inefficient. Instead, it is more common to denormalize data so that everything needed is in one, or a small number, of documents. However, there are some forms of cross-document relationships that could be handled--see [Limited Include support for Azure Cosmos DB](https://github.com/dotnet/efcore/issues/16920#issuecomment-989721078). > [!WARNING] -> The Cosmos SDK, which the EF provider uses, does not support synchronous I/O. As a result, synchronous EF APIs such as `ToList` or `SaveChanges` throw in version 9.0 and above; always use asynchronous +> The Azure Cosmos DB SDK, which the EF provider uses, does not support synchronous I/O. As a result, synchronous EF APIs such as `ToList` or `SaveChanges` throw in version 9.0 and above; always use asynchronous > methods when using EF. > Previous versions of EF supported the synchronous APIs by calling `.Wait()` on the returned `Task`; this is known as "sync over async", and is a highly discouraged technique that can lead to deadlocks. See the EF 9.0 [breaking change note](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-nosync) for more information. -Beyond the differences in relational and document databases, and limitations in the SDK, the EF Core provider for Azure Cosmos DB NoSQL does not include everything that _could_ be implemented using the combination of EF Core and the Cosmos SDK. Potential enhancements in this area are tracked by [issues in the EF Core GitHub repo marked with the label `area-cosmos`](https://github.com/dotnet/efcore/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-cosmos+sort%3Areactions-%2B1-desc+label%3Atype-enhancement) The best way to indicate the importance of an issue is to vote (👍) for it. This data will then feed into the [planning process](xref:core/what-is-new/release-planning) for the next release. +Beyond the differences in relational and document databases, and limitations in the SDK, the EF Core provider for Azure Cosmos DB NoSQL does not include everything that _could_ be implemented using the combination of EF Core and the Azure Cosmos DB SDK. Potential enhancements in this area are tracked by [issues in the EF Core GitHub repo marked with the label `area-cosmos`](https://github.com/dotnet/efcore/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-cosmos+sort%3Areactions-%2B1-desc+label%3Atype-enhancement) The best way to indicate the importance of an issue is to vote (👍) for it. This data will then feed into the [planning process](xref:core/what-is-new/release-planning) for the next release. diff --git a/entity-framework/core/providers/cosmos/modeling.md b/entity-framework/core/providers/cosmos/modeling.md index e90377ad63..2406943d1c 100644 --- a/entity-framework/core/providers/cosmos/modeling.md +++ b/entity-framework/core/providers/cosmos/modeling.md @@ -9,7 +9,7 @@ uid: core/providers/cosmos/modeling ## Containers and entity types -In Azure Cosmos DB, JSON documents are stored in containers. Unlike tables in relational databases, Cosmos DB containers can contain documents with different shapes - a container does not impose a uniform schema on its documents. However, various configuration options are defined at the container level, and therefore affect all documents contained within it. See the [Cosmos DB documentation on containers](/azure/cosmos-db/resource-model) for more information. +In Azure Cosmos DB, JSON documents are stored in containers. Unlike tables in relational databases, Azure Cosmos DB containers can contain documents with different shapes - a container does not impose a uniform schema on its documents. However, various configuration options are defined at the container level, and therefore affect all documents contained within it. See the [Azure Cosmos DB documentation on containers](/azure/cosmos-db/resource-model) for more information. By default, EF maps all entity types to the same container; this is usually a good default in terms of performance and pricing. The default container is named after the .NET context type (`OrderContext` in this case). To change the default container name, use : @@ -23,13 +23,13 @@ To map an entity type to a different container use ().ToContainer("Orders"); ``` -Before mapping entity types to different containers, make sure you understand the potential performance and pricing implications (e.g. with regards to dedicated and shared throughput); [see the Cosmos DB documentation to learn more](/azure/cosmos-db/resource-model). +Before mapping entity types to different containers, make sure you understand the potential performance and pricing implications (e.g. with regards to dedicated and shared throughput); [see the Azure Cosmos DB documentation to learn more](/azure/cosmos-db/resource-model). ## IDs and keys -Cosmos DB requires all documents to have an `id` JSON property which uniquely identifies them. Like other EF providers, the EF Cosmos provider will attempt to find a property named `Id` or `Id`, and configure that property as the key of your entity type, mapping it to the `id` JSON property. You can configure any property to be the key property by using ; see [the general EF documentation on keys](xref:core/modeling/keys) for more information. +Azure Cosmos DB requires all documents to have an `id` JSON property which uniquely identifies them. Like other EF providers, the EF Azure Cosmos DB provider will attempt to find a property named `Id` or `Id`, and configure that property as the key of your entity type, mapping it to the `id` JSON property. You can configure any property to be the key property by using ; see [the general EF documentation on keys](xref:core/modeling/keys) for more information. -Developers coming to Cosmos DB from other database sometimes expect the key (`Id`) property to be generated automatically. For example, on SQL Server, EF configures numeric key properties to be IDENTITY columns, where auto-incrementing values are generated in the database. In contrast, Cosmos DB does not support automatic generation of properties, and so key properties must be explicitly set. Inserting an entity type with an unset key property will simply insert the CLR default value for that property (e.g. 0 for `int`), and a second insert will fail; EF issues a warning if you attempt to do this. +Developers coming to Azure Cosmos DB from other databases sometimes expect the key (`Id`) property to be generated automatically. For example, on SQL Server, EF configures numeric key properties to be IDENTITY columns, where auto-incrementing values are generated in the database. In contrast, Azure Cosmos DB does not support automatic generation of properties, and so key properties must be explicitly set. Inserting an entity type with an unset key property will simply insert the CLR default value for that property (e.g. 0 for `int`), and a second insert will fail; EF issues a warning if you attempt to do this. If you'd like to have a GUID as your key property, you can configure EF to generate unique, random values at the client: @@ -39,9 +39,9 @@ modelBuilder.Entity().Property(b => b.Id).HasValueGenerator().HasPartitionKey(o => o.PartitionKey); @@ -49,13 +49,13 @@ modelBuilder.Entity().HasPartitionKey(o => o.PartitionKey); Any property can be made into a partition key as long as it is [converted to string](xref:core/modeling/value-conversions). Once configured, the partition key property should always have a non-null value; trying to insert a new entity type with an unset partition key property will result in an error. -Note that Cosmos allows two documents with the same `id` property to exist in a container, as long as they're in different partitions; this means that in order to uniquely identify a document within a container, both the `id` and the partition key properties must all be provided. Because of this, EF's internal notion of the entity primary key contains both of these elements by convention, unlike e.g. relational databases where there is no partition key concept. This means e.g. that [`FindAsync`](xref:core/change-tracking/entity-entries#find-and-findasync) requires both key and partition key properties ([see further docs](xref:core/providers/cosmos/querying#findasync)), and a query must specify these in its `Where` clause to benefit from efficient and cost-effective [`point reads`](xref:core/providers/cosmos/querying#point-reads). +Note that Azure Cosmos DB allows two documents with the same `id` property to exist in a container, as long as they're in different partitions; this means that in order to uniquely identify a document within a container, both the `id` and the partition key properties must all be provided. Because of this, EF's internal notion of the entity primary key contains both of these elements by convention, unlike e.g. relational databases where there is no partition key concept. This means e.g. that [`FindAsync`](xref:core/change-tracking/entity-entries#find-and-findasync) requires both key and partition key properties ([see further docs](xref:core/providers/cosmos/querying#findasync)), and a query must specify these in its `Where` clause to benefit from efficient and cost-effective [`point reads`](xref:core/providers/cosmos/querying#point-reads). -Note that the partition key is defined at the container level. This notably means that it's not possible to map multiple entity types to the same container, and for those entity types to have different partition keys. If you need to define different partition keys, map the relevant entity types to different containers. +Note that the partition key is defined at the container level. This notably means that it's not possible for multiple entity types in the same container to have different partition key properties. If you need to define different partition keys, map the relevant entity types to different containers. ### Hierarchical partition keys -Cosmos DB also supports _hierarchical_ partition keys to optimize data distribution even further; [see the Cosmos DB documentation for more details](/azure/cosmos-db/hierarchical-partition-keys). EF 9.0 added support for hierarchical partition keys; to configure these, simply pass up to 3 properties to [HasPartitionKey](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosEntityTypeBuilderExtensions.HasPartitionKey): +Azure Cosmos DB also supports _hierarchical_ partition keys to optimize data distribution even further; [see the documentation for more details](/azure/cosmos-db/hierarchical-partition-keys). EF 9.0 added support for hierarchical partition keys; to configure these, simply pass up to 3 properties to [HasPartitionKey](/dotnet/api/Microsoft.EntityFrameworkCore.CosmosEntityTypeBuilderExtensions.HasPartitionKey): ```csharp modelBuilder.Entity().HasPartitionKey(o => new { e.TenantId, e.UserId, e.SessionId }); @@ -63,13 +63,13 @@ modelBuilder.Entity().HasPartitionKey(o => new { e.TenantId, e.UserId, e. With such a hierarchical partition key, queries can be easily sent only to the a relevant subset of sub-partitions. For example, if you query for the Orders of a specific tenant, those queries will only be executed against the sub-partitions for that tenant. -If you don't configure a partition key with EF, a warning will be logged at startup; EF Core will create containers with the partition key set to `__partitionKey`, and won't supply any value for it when inserting items. While this can work and may be a good way to start as you're exploring Cosmos DB and your data modeling, it is highly discouraged to deploy a production application without a well-configured partition key strategy. +If you don't configure a partition key with EF, a warning will be logged at startup; EF Core will create containers with the partition key set to `__partitionKey`, and won't supply any value for it when inserting items. When no partition key is set, your container will be limited to 20 GB of data, which is the maximum storage for a single [logical partition](/azure/cosmos-db/partitioning-overview). While this can work for small dev/ test applications, it is highly discouraged to deploy a production application without a well-configured partition key strategy. -Once your partition keys properties are properly configured, you can provide values for them in queries; see [Querying with partition keys](xref:core/providers/cosmos/querying#partition-keys) for more information. +Once your partition key properties are properly configured, you can provide values for them in queries; see [Querying with partition keys](xref:core/providers/cosmos/querying#partition-keys) for more information. ## Discriminators -Since multiple entity types may be mapped to the same container, EF Core always adds a `$type` discriminator property to all JSON documents you save (this property was called `Discriminator` before EF 9.0); this allows EF to recognize documents being loaded from the database, and materialize the right .NET type. Developers coming from relational databases may be familiar with discriminators in the context of [table-per-hierarchy inheritance (TPH)](xref:core/modeling/inheritance#table-per-hierarchy-and-discriminator-configuration); in Cosmos, discriminators are used not just in inheritance mapping scenarios, but also because the same container can contain completely different document types. +Since multiple entity types may be mapped to the same container, EF Core always adds a `$type` discriminator property to all JSON documents you save (this property was called `Discriminator` before EF 9.0); this allows EF to recognize documents being loaded from the database, and materialize the right .NET type. Developers coming from relational databases may be familiar with discriminators in the context of [table-per-hierarchy inheritance (TPH)](xref:core/modeling/inheritance#table-per-hierarchy-and-discriminator-configuration); in Azure Cosmos DB, discriminators are used not just in inheritance mapping scenarios, but also because the same container can contain completely different document types. The discriminator property name and values can be configured with the standard EF APIs, [see these docs for more information](xref:core/modeling/inheritance). If you're mapping a single entity type to a container, are confident that you'll never be mapping another one, and would like to get rid of the discriminator property, call [HasNoDiscriminator](/dotnet/api/Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder.HasNoDiscriminator): @@ -77,7 +77,7 @@ The discriminator property name and values can be configured with the standard E modelBuilder.Entity().HasNoDiscriminator(); ``` -Since the same container can contain entity types of different types, and the JSON `id` property must be unique within a container partition, you cannot have the same `id` value for entities of different types in the same container partition. Compare this to relational databases, where each entity type is mapped to a different table, and therefore has its own, separate key space. It is therefore your responsibility to ensure the `id` uniqueness of documents you insert into a container. If you need to have different entity types with the same primary key values, you can instruct EF to automatically insert the discriminator into the `id` property as follows: +Since the same container can contain different entity types, and the JSON `id` property must be unique within a container partition, you cannot have the same `id` value for entities of different types in the same container partition. Compare this to relational databases, where each entity type is mapped to a different table, and therefore has its own, separate key space. It is therefore your responsibility to ensure the `id` uniqueness of documents you insert into a container. If you need to have different entity types with the same primary key values, you can instruct EF to automatically insert the discriminator into the `id` property as follows: ```csharp modelBuilder.Entity().HasDiscriminatorInJsonId(); diff --git a/entity-framework/core/providers/cosmos/querying.md b/entity-framework/core/providers/cosmos/querying.md index 76aed28617..33a8b8f014 100644 --- a/entity-framework/core/providers/cosmos/querying.md +++ b/entity-framework/core/providers/cosmos/querying.md @@ -32,7 +32,7 @@ var stringResults = await context.Sessions > [!NOTE] > The Azure Cosmos DB provider does not translate the same set of LINQ queries as other providers. -> For example, the EF `Include()` operator isn't supported on Cosmos, since cross-document queries aren't supported in the database. +> For example, the EF `Include()` operator isn't supported on Azure Cosmos DB, since cross-document queries aren't supported in the database. ## Partition keys @@ -90,7 +90,7 @@ This executes in the same way as the above query, and can be preferable if you w ## Point reads -While Azure Cosmos DB allows for powerful querying via SQL, such queries can be quite expensive. Cosmos DB also supports _point reads_, which can be used when both the `id` property and the entire partition key are known. Such point reads directly identify a specific document in a specific partition, and execute extremely efficiently and with reduced costs. If at all possible, it's worth designing your system in a way which leverages point reads as much as possible. To read more, see the [Cosmos DB documentation](/azure/cosmos-db/nosql/how-to-dotnet-read-item). +While Azure Cosmos DB allows for powerful querying via SQL, such queries can be quite expensive. Azure Cosmos DB also supports _point reads_, which should be used when retrieving a single document if both the `id` property and the entire partition key are known. Point reads directly identify a specific document in a specific partition, and execute extremely efficiently and with reduced costs compared to retrieving the same document with a query. It's recommended to design your system to leverage point reads as often as possible. To read more, see the [Azure Cosmos DB documentation](/azure/cosmos-db/nosql/how-to-dotnet-read-item). In the previous section, we saw EF identifying and extracting partition key comparisons from the `Where` clause for more efficient querying, restricting processing only to the relevant partitions. It's possible to go a step further, and provide the `id` property in the query as well. Let's examine the following query: @@ -102,7 +102,7 @@ var session = await context.Sessions.SingleAsync( && e.SessionId == sessionId); ``` -In this query, a value for the `Id` property is provided (which is mapped to the Cosmos DB `id` property), as well as values for all the partition key properties. Furthermore, there are no additional components to the query. When all these conditions are met, EF is able to execute the query as a point read: +In this query, a value for the `Id` property is provided (which is mapped to the Azure Cosmos DB `id` property), as well as values for all the partition key properties. Furthermore, there are no additional components to the query. When all these conditions are met, EF is able to execute the query as a point read: ```console Executed ReadItem (46 ms, 1 RU) ActivityId='d7391311-2266-4811-ae2d-535904c42c43', Container='test', Id='9', Partition='["Microsoft","99a410d7-e467-4cc5-92de-148f3fc53f4c",10.0]' @@ -115,7 +115,7 @@ Note that as with partition key extraction, significant improvements have been m ## Pagination > [!NOTE] -> This feature was introduced in EF Core 9.0 and is stil experimental. Please let us know how it works for you and if you have any feedback. +> This feature was introduced in EF Core 9.0 and is still experimental. Please let us know how it works for you and if you have any feedback. Pagination refers to retrieving results in pages, rather than all at once; this is typically done for large resultsets, where a user interface is displayed, allowing users to navigate through pages of the results. @@ -130,7 +130,7 @@ var nextPage = context.Session .ToList(); ``` -Unfortunately, this technique is quite inefficient and can considerably increase querying costs. Cosmos DB provides a special mechanism for paginating through the result of a query, via the use of _continuation tokens_: +Unfortunately, this technique is quite inefficient and can considerably increase querying costs. Azure Cosmos DB provides a special mechanism for paginating through the result of a query, via the use of _continuation tokens_: ```csharp CosmosPage firstPage = await context.Sessions @@ -157,20 +157,20 @@ foreach (var session in nextPage.Values) } ``` -We execute the same query, but this time we pass in the continuation token received from the first execution; this instructs Cosmos DB to continue the query where it left off, and fetch the next 10 items. Once we fetch the last page and there are no more results, the continuation token will be `null`, and the "Next" button can be grayed out. This method of paginating is extremely efficient and cost-effective compared to using `Skip` and `Take`. +We execute the same query, but this time we pass in the continuation token received from the first execution; this instructs the query engine to continue the query where it left off, and fetch the next 10 items. Once we fetch the last page and there are no more results, the continuation token will be `null`, and the "Next" button can be grayed out. This method of paginating is extremely efficient and cost-effective compared to using `Skip` and `Take`. -To learn more about pagination in Cosmos DB, [see this page](/azure/cosmos-db/nosql/query/pagination). +To learn more about pagination in Azure Cosmos DB, [see this page](/azure/cosmos-db/nosql/query/pagination). > [!NOTE] -> Cosmos DB does not support backwards pagination, and does not provide a count of the total pages or items. +> Azure Cosmos DB does not support backwards pagination, and does not provide a count of the total pages or items. > -> `ToPageAsync` is currently annotated as experimental, since it may be replaced with a more general EF pagination API that isn't Cosmos-specific. Although using the current API will generate a compilation warning (`EF9102`), doing so should be safe - future changes may require minor tweaks in the API shape. +> `ToPageAsync` is currently annotated as experimental, since it may be replaced with a more generic EF pagination API that isn't Azure Cosmos DB specific. Although using the current API will generate a compilation warning (`EF9102`), doing so should be safe - future changes may require minor tweaks in the API shape. ## `FindAsync` [`FindAsync`](xref:core/change-tracking/entity-entries#find-and-findasync) is a useful API for getting an entity by its primary key, and avoiding a database roundtrip when the entity has already been loaded and is tracked by the context. -Developers familiar with relational databases are used to the primary key of an entity type consisting e.g. of an `Id` property. When using the EF Cosmos DB provider, the primary key contains the partition key properties in addition to the property mapped to the JSON `id` property; this is the case since Cosmos DB allows different partitions to contain documents with the same JSON `id` property, and so only the combined `id` and partition key uniquely identify a single document in a container: +Developers familiar with relational databases are used to the primary key of an entity type consisting e.g. of an `Id` property. When using the EF Azure Cosmos DB provider, the primary key contains the partition key properties in addition to the property mapped to the JSON `id` property; this is the case since Azure Cosmos DB allows different partitions to contain documents with the same JSON `id` property, and so only the combined `id` and partition key uniquely identify a single document in a container: ```csharp public class Session @@ -211,7 +211,7 @@ FROM ( Note that `FromSql` was introduced in EF 9.0. In previous versions, `FromSqlRaw` can be used instead, although note that that method is vulnerable to SQL injection attacks. -For more information on SQL querying, see the [relational documentation on SQL queries](xref:core/querying/sql-queries); most of that content is relevant for the Cosmos provider as well. +For more information on SQL querying, see the [relational documentation on SQL queries](xref:core/querying/sql-queries); most of that content is relevant for the Azure Cosmos DB provider as well. ## Function mappings @@ -309,4 +309,4 @@ EF.Functions.VectorDistance(vector1, vector2, bruteForce, distanceFunction) 1 Note that `EF.Functions.CoalesceUndefined` coalesces `undefined`, not `null`. To coalesce `null`, use the regular C# `??` operator. -2 [See the documentation](xref:core/providers/cosmos/vector-search) for information on using vector search in Azure Cosmos DB. Cosmos DB vector searching is experimental and the APIs are subject to change. +2 [See the documentation](xref:core/providers/cosmos/vector-search) for information on using vector search in Azure Cosmos DB, which is experimental. The APIs are subject to change. diff --git a/entity-framework/core/providers/cosmos/vector-search.md b/entity-framework/core/providers/cosmos/vector-search.md index 5027b5f27d..21f855668d 100644 --- a/entity-framework/core/providers/cosmos/vector-search.md +++ b/entity-framework/core/providers/cosmos/vector-search.md @@ -10,9 +10,9 @@ uid: core/providers/cosmos/vector-search > [!WARNING] > Azure Cosmos DB vector search is currently in preview. As a result, using EF's vector search APIs will generate an "experimental API" warning (`EF9103`) which must be suppressed. The APIs and capabilities may change in breaking ways in the future. -Azure Cosmos DB now offers preview support for vector similarity search. Vector search is a fundamental part of some application types, include AI, semantic search and others. The Cosmos DB support for vector search allows storing your data and vectors, and performing your queries in a single database, which can considerably simplify your architecture and remove the need for an additional, dedicated vector database solution in your stack. To learn more about Cosmos DB vector search, [see the documentation](/azure/cosmos-db/nosql/vector-search). +Azure Cosmos DB now offers preview support for vector similarity search. Vector search is a fundamental part of some application types, including AI, semantic search and others. Azure Cosmos DB allows you to store vectors directly in your documents alongside the rest of your data, meaning you can perform all of your queries against a single database. This can considerably simplify your architecture and remove the need for an additional, dedicated vector database solution in your stack. To learn more about Azure Cosmos DB vector search, [see the documentation](/azure/cosmos-db/nosql/vector-search). -To use vector search, you must first [enroll in the preview feature](/azure/cosmos-db/nosql/vector-search#enroll-in-the-vector-search-preview-feature). Then, [define the vector policies on your container](/azure/cosmos-db/nosql/vector-search#container-vector-policies), which determine which JSON property in your documents contain vectors, various vector-related information for those properties (dimensions, data type, distance function). +To use vector search, you must first [enroll in the preview feature](/azure/cosmos-db/nosql/vector-search#enroll-in-the-vector-search-preview-feature). Then, [define vector policies on your container](/azure/cosmos-db/nosql/vector-search#container-vector-policies) to identify which JSON properties in your documents contain vectors and vector-related information for those properties (dimensions, data type, distance function). Once your container is properly set up, add a vector property to your model in the path you defined in the container policy, and configure it with EF as a vector: diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index a237e6e06a..9cccd7dc5f 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -21,7 +21,7 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET ## Summary > [!NOTE] -> If you are using Azure Cosmos DB, please see the [separate section below on Cosmos DB breaking changes](#cosmos-breaking-changes). +> If you are using Azure Cosmos DB, please see the [separate section below on Azure Cosmos DB breaking changes](#azure-cosmos-db-breaking-changes). | **Breaking change** | **Impact** | |:-----------------------------------------------------------------------------------------------------|------------| @@ -80,9 +80,9 @@ Not having matching number of arguments and nullability propagation arguments ca Make sure the `argumentsPropagateNullability` has same number of elements as the `arguments`. When in doubt use `false` for nullability argument. -## Cosmos breaking changes +## Azure Cosmos DB breaking changes -Extensive work has gone into making the Cosmos DB provider better in 9.0. The changes include a number of high-impact breaking changes; if you are upgrading an existing application, please read the following carefully. +Extensive work has gone into making the Azure Cosmos DB provider better in 9.0. The changes include a number of high-impact breaking changes; if you are upgrading an existing application, please read the following carefully. | **Breaking change** | **Impact** | |:---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | @@ -109,7 +109,7 @@ EF automatically adds a discriminator property to JSON documents to identify the ##### New behavior -Starting with EF Core 9.0, the discriminator property is now called `$type` by default. If you have existing documents in Cosmos DB from previous versions of EF, these use the old `Discriminator` naming, and after upgrading to EF 9.0, queries against those documents will fail. +Starting with EF Core 9.0, the discriminator property is now called `$type` by default. If you have existing documents in Azure Cosmos DB from previous versions of EF, these use the old `Discriminator` naming, and after upgrading to EF 9.0, queries against those documents will fail. ##### Why @@ -139,13 +139,13 @@ Previously, EF inserted the discriminator value of your entity type into the `id ##### New behavior -Starting with EF Core 9.0, the JSON `id` property no longer contains the discriminator value, and only contains the avlue of your key property. For the above example, the JSON `id` property would simply be `8`. If you have existing documents in Cosmos DB from previous versions of EF, these have the discriminator value in the JSON `id` property, and after upgrading to EF 9.0, queries against those documents will fail. +Starting with EF Core 9.0, the JSON `id` property no longer contains the discriminator value, and only contains the value of your key property. For the above example, the JSON `id` property would simply be `8`. If you have existing documents in Azure Cosmos DB from previous versions of EF, these have the discriminator value in the JSON `id` property, and after upgrading to EF 9.0, queries against those documents will fail. ##### Why -Since the JSON `id` property must be unique, the discriminator was previously added to it so as to allow different entities to exist with the same key value; for example, this allowed having both a `Blog` and a `Post` with an `Id` property containing 8 within the same container and partition. This was assumed to be expected by developers used to relational databases, where each entity type is mapped its own table, and therefore has its own key-space. +Since the JSON `id` property must be unique, the discriminator was previously added to it to allow different entities with the same key value to exist. For example, this allowed having both a `Blog` and a `Post` with an `Id` property containing the value 8 within the same container and partition. This aligned better with relational database data modeling patterns, where each entity type is mapped to its own table, and therefore has its own key-space. -EF 9.0 generally changed the mapping to be more aligned with common Cosmos DB practices and expectations, rather than to correspond to the expectations of users coming from relational databases. In addition, having the discriminator value in the `id` property made it more difficult for external tools and systems to interact with EF-generated JSON documents; such external systems aren't generally aware of the EF discriminator values, which are by default derived from .NET types. +EF 9.0 generally changed the mapping to be more aligned with common Azure Cosmos DB NoSQL practices and expectations, rather than to correspond to the expectations of users coming from relational databases. In addition, having the discriminator value in the `id` property made it more difficult for external tools and systems to interact with EF-generated JSON documents; such external systems aren't generally aware of the EF discriminator values, which are by default derived from .NET types. ##### Mitigations @@ -206,7 +206,7 @@ Previously, EF generated queries such as the following: SELECT c["City"] FROM root c ``` -Such queries cause Cosmos DB to wrap each result in a JSON object, as follows: +Such queries cause Azure Cosmos DB to wrap each result in a JSON object, as follows: ```json [ @@ -227,7 +227,7 @@ Starting with EF Core 9.0, EF now adds the `VALUE` modifier to queries as follow SELECT VALUE c["City"] FROM root c ``` -Such queries cause Cosmos DB to return the values directly, without being wrapped: +Such queries cause Azure Cosmos DB to return the values directly, without being wrapped: ```json [ @@ -240,7 +240,7 @@ If your application makes use of [SQL queries](xref:core/providers/cosmos/queryi ##### Why -Wrapping each result in an additional JSON object can cause performance degradation in some scenarios, bloats the JSON result payload, and isn't the natural way to work with Cosmos DB. +Wrapping each result in an additional JSON object can cause performance degradation in some scenarios, bloats the JSON result payload, and isn't the natural way to work with Azure Cosmos DB. ##### Mitigations @@ -260,7 +260,7 @@ Previously, EF generated queries such as the following: SELECT c["City"] FROM root c ``` -Such queries cause Cosmos DB to wrap each result in a JSON object, as follows: +Such queries cause Azure Cosmos DB to wrap each result in a JSON object, as follows: ```json [ @@ -283,7 +283,7 @@ Starting with EF Core 9.0, EF now adds the `VALUE` modifier to queries as follow SELECT VALUE c["City"] FROM root c ``` -Such queries cause Cosmos DB to return the values directly, without being wrapped: +Such queries cause Azure Cosmos DB to return the values directly, without being wrapped: ```json [ @@ -292,11 +292,11 @@ Such queries cause Cosmos DB to return the values directly, without being wrappe ] ``` -The Cosmos DB behavior is to automatically filter `undefined` values out of results; this means that if one of the `City` properties is absent from the document, the query would return just a single result, rather than two results, with one being `null`. +The Azure Cosmos DB behavior is to automatically filter `undefined` values out of results; this means that if one of the `City` properties is absent from the document, the query would return just a single result, rather than two results, with one being `null`. ##### Why -Wrapping each result in an additional JSON object can cause performance degradation in some scenarios, bloats the JSON result payload, and isn't the natural way to work with Cosmos DB. +Wrapping each result in an additional JSON object can cause performance degradation in some scenarios, bloats the JSON result payload, and isn't the natural way to work with Azure Cosmos DB. ##### Mitigations @@ -355,7 +355,7 @@ var sessions = await context.Sessions .ToListAsync(); ``` -Unfortunately, Cosmos does not currently support the `OFFSET` and `LIMIT` clauses in SQL subqueries, which is what the proper translation of the original LINQ query requires. +Unfortunately, Azure Cosmos DB does not currently support the `OFFSET` and `LIMIT` clauses in SQL subqueries, which is what the proper translation of the original LINQ query requires. ### Low-impact changes @@ -375,7 +375,7 @@ The provider now throws if calls weren't doing anything, they are no longer allowed. +In Azure Cosmos DB, all properties are indexed by default, and no indexing needs to be specified. While it's possible to define a custom indexing policy, this isn't currently supported by EF, and can be done via the Azure Portal without EF support. Since calls weren't doing anything, they are no longer allowed. ##### Mitigations @@ -389,7 +389,7 @@ Remove any calls to [!WARNING] > As part of the improvements going into the provider, a number of high-impact breaking changes had to be made; if you are upgrading an existing application, please read the [breaking changes section](xref:core/what-is-new/ef-core-9.0/breaking-changes#cosmos-breaking-changes) carefully. ### Improvements querying with partition keys and document IDs -Each document stored in the Cosmos database has a unique resource ID. In addition, each document can contain a "partition key" which determines the logical partitioning of data such that the database can be effectively scaled. More information on choosing partition keys can be found in [_Partitioning and horizontal scaling in Azure Cosmos DB_](/azure/cosmos-db/partitioning-overview). +Each document stored in an Azure Cosmos DB database has a unique resource ID. In addition, each document can contain a "partition key" which determines the logical partitioning of data such that the database can be effectively scaled. More information on choosing partition keys can be found in [_Partitioning and horizontal scaling in Azure Cosmos DB_](/azure/cosmos-db/partitioning-overview). -In EF 9.0, the Cosmos DB provider is significantly better at identifying partition key comparisons in your LINQ queries, and extracting them out to make your queries are only sent to the relevant partition; this can greatly improve the performance of your queries and reduce costs. For example: +In EF 9.0, the Azure Cosmos DB provider is significantly better at identifying partition key comparisons in your LINQ queries, and extracting them out to ensure your queries are only sent to the relevant partition; this can greatly improve the performance of your queries and reduce RU charges. For example: ```csharp var sessions = await context.Sessions @@ -68,7 +68,7 @@ The logs show the following for this query: Executed ReadItem (73 ms, 1 RU) ActivityId='13f0f8b8-d481-47f0-bf41-67f7deb008b2', Container='test', Id='8', Partition='["someValue"]' ``` -Here, no SQL query is sent at all. Instead, the provider performs an an extremely efficient _point read_ (`ReadItem` API), which directly fetches the document given the partition key and ID. This is the most efficient and cost-effective kind of read you can perform in Cosmos DB; [see the Cosmos DB documentation](/azure/cosmos-db/nosql/how-to-dotnet-read-item) for more information about point reads. +Here, no SQL query is sent at all. Instead, the provider performs an an extremely efficient _point read_ (`ReadItem` API), which directly fetches the document given the partition key and ID. This is the most efficient and cost-effective kind of read you can perform in Azure Cosmos DB; [see the Azure Cosmos DB documentation](/azure/cosmos-db/nosql/how-to-dotnet-read-item) for more information about point reads. To learn more about querying with partition keys and point reads, [see the querying documentation page](xref:core/providers/cosmos/querying). @@ -77,7 +77,7 @@ To learn more about querying with partition keys and point reads, [see the query > [!TIP] > The code shown here comes from [HierarchicalPartitionKeysSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs). -Azure Cosmos DB originally supported a single partition key, but has since expanded partitioning capabilities to support [subpartitioning through the specification of up to three levels of hierarchy in the partition key](/azure/cosmos-db/hierarchical-partition-keys). EF Core 9 brings full support for hierarchical partition keys, allowing you take advantage of the better performance and cost savings associated with this feature. +Azure Cosmos DB originally supported a single partition key, but has since expanded partitioning capabilities to also support [subpartitioning through the specification of up to three levels of hierarchy in the partition key](/azure/cosmos-db/hierarchical-partition-keys). EF Core 9 brings full support for hierarchical partition keys, allowing you take advantage of the better performance and cost savings associated with this feature. Partition keys are specified using the model building API, typically in . There must be a mapped property in the entity type for each level of the partition key. For example, consider a `UserSession` entity type: @@ -112,7 +112,7 @@ The following code specifies a three-level partition key using the `TenantId`, ` Notice how, starting with EF Core 9, properties of any mapped type can be used in the partition key. For `bool` and numeric types, like the `int SessionId` property, the value is used directly in the partition key. Other types, like the `Guid UserId` property, are automatically converted to strings. -When querying, EF automatically extracts the partition key values from queries and applies them to the Cosmos query API to ensure the queries are constrained appropriately to the fewest number of partitions possible. For example, consider the following LINQ query that supplies the partition key values: +When querying, EF automatically extracts the partition key values from queries and applies them to the Azure Cosmos DB query API to ensure the queries are constrained appropriately to the fewest number of partitions possible. For example, consider the following LINQ query that supplies all three partition key values in the hierarchy: [!code-csharp[FullPartitionKey](../../../../samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs?name=FullPartitionKey)] -When executing this query, EF Core will extract the values of the `tenantId`, `userId`, and `sessionId` parameters, and pass them to the Cosmos query API as the partition key value. For example, see the logs from executing the query above: +When executing this query, EF Core will extract the values of the `tenantId`, `userId`, and `sessionId` parameters, and pass them to the Azure Cosmos DB query API as the partition key value. For example, see the logs from executing the query above: ```output info: 6/10/2024 19:06:00.017 CosmosEventId.ExecutingSqlQuery[30100] (Microsoft.EntityFrameworkCore.Database.Command) @@ -145,22 +145,22 @@ For more information, see the documentation on [querying with partition keys](xr ### Significantly improved LINQ querying capabilities -In EF 9.0, the LINQ translation capabilities of the the Cosmos DB provider have been greatly expanded, and the provider can now execute significantly more query types. The full list of query improvements is too long to list, but here are the main highlights: +In EF 9.0, the LINQ translation capabilities of the the Azure Cosmos DB provider have been greatly expanded, and the provider can now execute significantly more query types. The full list of query improvements is too long to list, but here are the main highlights: -* The Cosmos provider now fully supports EF's primitive collections, allowing you to perform LINQ querying on collections of e.g. ints or strings. See [What's new in EF8: primitive collections](xref:core/what-is-new/ef-core-8.0/whatsnew#primitive-collections) for more information. -* Support for arbitrary querying over non-primitive collections has been added as well. +* Full support for EF's primitive collections, allowing you to perform LINQ querying on collections of e.g. ints or strings. See [What's new in EF8: primitive collections](xref:core/what-is-new/ef-core-8.0/whatsnew#primitive-collections) for more information. +* Support for arbitrary querying over non-primitive collections. * Lots of additional LINQ operators are now supported: indexing into collections, `Length`/`Count`, `ElementAt`, `Contains`, and many others. -* Support for aggregate operators such as `Count` and `Sum` has been added. -* Many function translations have added (see the [function mappings documentation](xref:core/providers/cosmos/querying#function-mappings) for the full list of supported translations): - * Translations for `DateTime` and `DateTimeOffset` component members (`DateTime.Year`, `DateTimeOffset.Month`...) have been added. +* Support for aggregate operators such as `Count` and `Sum`. +* Additional function translations (see the [function mappings documentation](xref:core/providers/cosmos/querying#function-mappings) for the full list of supported translations): + * Translations for `DateTime` and `DateTimeOffset` component members (`DateTime.Year`, `DateTimeOffset.Month`...). * `EF.Functions.IsDefined` and `EF.Functions.CoalesceUndefined` now allow dealing with `undefined` values. * `string.Contains`, `StartsWith` and `EndsWith` now support `StringComparison.OrdinalIgnoreCase`. For the full list of querying improvements, see [this issue](https://github.com/dotnet/efcore/issues/33033): -### Improved modeling aligned to Cosmos and JSON standards +### Improved modeling aligned to Azure Cosmos DB and JSON standards -EF 9.0 maps to Cosmos DB documents in ways which are more natural for a JSON-based document database, and help interoperate with other systems accessing your documents. Although this entails breaking changes, APIs exist which allow reverting back to the pre-9.0 behavior in all cases. +EF 9.0 maps to Azure Cosmos DB documents in more natural ways for a JSON-based document database, and helps interoperate with other systems accessing your documents. Although this entails breaking changes, APIs exist which allow reverting back to the pre-9.0 behavior in all cases. #### Simplified `id` properties without discriminators @@ -204,9 +204,9 @@ Note this is a breaking change, since EF will no longer be able to query existin ### Vector similarity search (preview) -Azure Cosmos DB now offers preview support for vector similarity search. Vector search is a fundamental part of some application types, include AI, semantic search and others. The Cosmos DB support for vector search allows storing your data and vectors and performing your queries in a single database, which can considerably simplify your architecture and remove the need for an additional, dedicated vector database solution in your stack. To learn more about Cosmos DB vector search, [see the documentation](/azure/cosmos-db/nosql/vector-search). +Azure Cosmos DB now offers preview support for vector similarity search. Vector search is a fundamental part of some application types, including AI, semantic search and others. Azure Cosmos DB allows you to store vectors directly in your documents alongside the rest of your data, meaning you can perform all of your queries against a single database. This can considerably simplify your architecture and remove the need for an additional, dedicated vector database solution in your stack. To learn more about Azure Cosmos DB vector search, [see the documentation](/azure/cosmos-db/nosql/vector-search). -Once your Cosmos DB container is properly set up, using vector search via EF is a simple matter of adding a vector property and configuring it: +Once your Azure Cosmos DB container is properly set up, using vector search via EF is a simple matter of adding a vector property and configuring it: ```c# public class Blog @@ -242,14 +242,14 @@ For more information, see the [documentation on vector search](xref:core/provide ### Pagination support -The Cosmos DB provider now allows for paginating through query results via _continuation tokens_, which is far more efficient and cost-effective than the traditional use of `Skip` and `Take`: +The Azure Cosmos DB provider now allows for paginating through query results via _continuation tokens_, which is far more efficient and cost-effective than the traditional use of `Skip` and `Take`: ```c# var firstPage = await context.Posts .OrderBy(p => p.Id) .ToPageAsync(pageSize: 10, continuationToken: null); -var continuationToken = page.ContinuationToken; +var continuationToken = firstPage.ContinuationToken; foreach (var post in page.Values) { // Display/send the posts to the user @@ -266,7 +266,7 @@ For more information, [see the documentation section on pagination](xref:core/pr ### FromSql for safer SQL querying -The Cosmos DB provider has allowed SQL querying via . However, that API can be susceptible to SQL injection attacks when user-provided data is interpolated or concatenated into the SQL. In EF 9.0, you can now use the new `FromSql` method, which always integrates parameterized data as a parameter outside the SQL: +The Azure Cosmos DB provider has allowed SQL querying via . However, that API can be susceptible to SQL injection attacks when user-provided data is interpolated or concatenated into the SQL. In EF 9.0, you can now use the new `FromSql` method, which always integrates parameterized data as a parameter outside the SQL: ```c# var maxAngle = 8; From 9395fffd5568d33c277fd811e496b686d26be063 Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Wed, 2 Oct 2024 13:36:54 -0700 Subject: [PATCH 043/224] - Whats new in EF9 docs (#4823) - Breaking change note for https://github.com/dotnet/efcore/issues/33942 - Update function mappings Fixes #4765 Fixes #4805 --- .../core/providers/sql-server/functions.md | 3 + .../core/providers/sqlite/functions.md | 2 + .../ef-core-9.0/breaking-changes.md | 30 ++- .../core/what-is-new/ef-core-9.0/whatsnew.md | 192 +++++++++++++++++- .../Miscellaneous/NewInEFCore9/QuerySample.cs | 124 ++++++++++- 5 files changed, 343 insertions(+), 8 deletions(-) diff --git a/entity-framework/core/providers/sql-server/functions.md b/entity-framework/core/providers/sql-server/functions.md index 632315c014..ce0835a31b 100644 --- a/entity-framework/core/providers/sql-server/functions.md +++ b/entity-framework/core/providers/sql-server/functions.md @@ -172,6 +172,8 @@ Math.Floor(d) | FLOOR(@d) Math.Log(d) | LOG(@d) Math.Log(a, newBase) | LOG(@a, @newBase) Math.Log10(d) | LOG10(@d) +Math.Max(x, y) | GREATEST(@x, @y) | EF Core 9.0 +Math.Min(x, y) | LEAST(@x, @y) | EF Core 9.0 Math.Pow(x, y) | POWER(@x, @y) Math.Round(d) | ROUND(@d, 0) Math.Round(d, decimals) | ROUND(@d, @decimals) @@ -202,6 +204,7 @@ string.Compare(strA, strB) | CASE W string.Concat(str0, str1) | @str0 + @str1 string.IsNullOrEmpty(value) | @value IS NULL OR @value LIKE N'' string.IsNullOrWhiteSpace(value) | @value IS NULL OR @value = N'' +string.Join(", ", new [] { x, y, z}) | CONCAT_WS(N', ', @x, @y, @z) | EF Core 9.0 stringValue.CompareTo(strB) | CASE WHEN @stringValue = @strB THEN 0 ... END stringValue.Contains(value) | @stringValue LIKE N'%' + @value + N'%' stringValue.EndsWith(value) | @stringValue LIKE N'%' + @value diff --git a/entity-framework/core/providers/sqlite/functions.md b/entity-framework/core/providers/sqlite/functions.md index 49037b8673..1105a25299 100644 --- a/entity-framework/core/providers/sqlite/functions.md +++ b/entity-framework/core/providers/sqlite/functions.md @@ -14,11 +14,13 @@ This page shows which .NET members are translated into which SQL functions when .NET | SQL | Added in ----------------------------------------------------- | ---------------------------------- | -------- group.Average(x => x.Property) | AVG(Property) +group.Average(x => x.DecimalProperty) | ef_avg(DecimalProperty) | EF Core 9.0 group.Count() | COUNT(*) group.LongCount() | COUNT(*) group.Max(x => x.Property) | MAX(Property) group.Min(x => x.Property) | MIN(Property) group.Sum(x => x.Property) | SUM(Property) +group.Sum(x => x.DecimalProperty) | ef_sum(DecimalProperty) | EF Core 9.0 string.Concat(group.Select(x => x.Property)) | group_concat(Property, '') | EF Core 7.0 string.Join(separator, group.Select(x => x.Property)) | group_concat(Property, @separator) | EF Core 7.0 diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index 9cccd7dc5f..7ce2811e34 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -25,8 +25,9 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET | **Breaking change** | **Impact** | |:-----------------------------------------------------------------------------------------------------|------------| -| [`EF.Functions.Unhex()` now returns `byte[]?`](#unhex) | Low | +| [`EF.Functions.Unhex()` now returns `byte[]?`](#unhex) | Low | | [SqlFunctionExpression's nullability arguments' arity validated](#sqlfunctionexpression-nullability) | Low | +| [`ToString()` method now returns empty string for `null` instances](#nullable-tostring) | Low | ## Low-impact changes @@ -80,6 +81,33 @@ Not having matching number of arguments and nullability propagation arguments ca Make sure the `argumentsPropagateNullability` has same number of elements as the `arguments`. When in doubt use `false` for nullability argument. + + +### `ToString()` method now returns empty string for `null` instances + +[Tracking Issue #33941](https://github.com/dotnet/efcore/issues/33941) + +#### Old behavior + +Previously EF returned inconsistent results for the `ToString()` method when the argument value was `null`. E.g. `ToString()` on `bool?` property with `null` value returned `null`, but for non-property `bool?` expressions whose value was `null` it returned `True`. The behavior was also incosistent for other data types, e.g. `ToString()` on `null` value enum returned empty string. + +#### New behavior + +Starting with EF Core 9.0, the `ToString()` method now consistently returns empty string in all cases when the argument value is `null`. + +#### Why + +The old behavior was inconsistent across different data types and situations, as well as not aligned with the [C# behavior](/dotnet/api/system.nullable-1.tostring#returns). + +#### Mitigations + +To revert to the old behavior, rewrite the query accordingly: + +```csharp +var newBehavior = context.Entity.Select(x => x.NullableBool.ToString()); +var oldBehavior = context.Entity.Select(x => x.NullableBool == null ? null : x.NullableBool.ToString()); +``` + ## Azure Cosmos DB breaking changes Extensive work has gone into making the Azure Cosmos DB provider better in 9.0. The changes include a number of high-impact breaking changes; if you are upgrading an existing application, please read the following carefully. 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 fdc0cfc524..a0d4b30c6c 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 @@ -615,6 +615,8 @@ FROM [Posts] AS [p] WHERE [p].[Title] = N'.NET Blog' AND [p].[Id] = 1 ``` +#### The `EF.Parameter` method + EF9 introduces the `EF.Parameter` method to do the opposite. That is, force EF to use a parameter even if the value is a constant in code. For example: +[!code-csharp[ForceParameter](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=DefaultParameterizationPrimitiveCollection)] + +This will result in the following translation on SQL Server: + +```output +Executed DbCommand (5ms) [Parameters=[@__ids_0='[1,2,3]' (Size = 4000)], CommandType='Text', CommandTimeout='30'] +SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Rating], [p].[Title], [p].[PromoText], [p].[Metadata] +FROM [Posts] AS [p] +WHERE [p].[Title] = N'.NET Blog' AND [p].[Id] IN ( + SELECT [i].[value] + FROM OPENJSON(@__ids_0) WITH ([value] int '$') AS [i] +) +``` + +This allows having the same SQL query for different parameterized collections (only the parameter value changes), but in some situations it can lead to performance issues as the database isn't able to optimally plan for the query. The `EF.Constant` method can be used to revert to the previous translation. + +The following query uses `EF.Constant` to that effect: + + +[!code-csharp[ForceParameter](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=ForceConstantPrimitiveCollection)] + +The resulting SQL is as follows: + +```sql +SELECT [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Rating], [p].[Title], [p].[PromoText], [p].[Metadata] +FROM [Posts] AS [p] +WHERE [p].[Title] = N'.NET Blog' AND [p].[Id] IN (1, 2, 3) +``` + +Moreover, EF9 introduces `TranslateParameterizedCollectionsToConstants` [context option](/ef/core/dbcontext-configuration/#dbcontextoptions) that can be used to prevent primitive collection parameterization for all queries. We also added a complementing `TranslateParameterizedCollectionsToParameters` which forces parameterization of primitive collections explicitly (this is the default behavior). + +> [!TIP] +> The `EF.Parameter` method overrides the context option. If you want to prevent parameterization of primitive collections for most of your queries (but not all), you can set the context option `TranslateParameterizedCollectionsToConstants` and use `EF.Parameter` for the queries or individual variables that you want to parameterize. + ### Inlined uncorrelated subqueries @@ -685,7 +740,71 @@ ORDER BY (SELECT 1) OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY ``` - + + +### Aggregate functions over subqueries and aggregates on SQL Server + +EF9 improves the translation of some complex queries using aggregate functions composed over subqueries or other aggregate functions. +Below is an example of such query: + + +[!code-csharp[AggregateOverSubquery](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=AggregateOverSubquery)] + +First, `Select` computes `LatestPostRating` for each `Post` which requires a subquery when translating to SQL. Later in the query these results are aggregated using `Average` operation. The resulting SQL looks as follows when run on SQL Server: + +```sql +SELECT AVG([s].[Rating]) +FROM [Blogs] AS [b] +OUTER APPLY ( + SELECT TOP(1) [p].[Rating] + FROM [Posts] AS [p] + WHERE [b].[Id] = [p].[BlogId] + ORDER BY [p].[PublishedOn] DESC +) AS [s] +GROUP BY [b].[Language] +``` + +In previous versions EF Core would generate invalid SQL for similar queries, trying to apply the aggregate operation directly over the subquery. This is not allowed on SQL Server and results in an exception. +Same principle applies to queries using aggregate over another aggregate: + + +[!code-csharp[AggregateOverAggregate](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=AggregateOverAggregate)] + +> [!NOTE] +> This change doesn't affect Sqlite, which supports aggregates over subqueries (or other aggregates) and it does not support `LATERAL JOIN` (`APPLY`). Below is the SQL for the first query running on Sqlite: +> +> ```sql +> SELECT ef_avg(( +> SELECT "p"."Rating" +> FROM "Posts" AS "p" +> WHERE "b"."Id" = "p"."BlogId" +> ORDER BY "p"."PublishedOn" DESC +> LIMIT 1)) +> FROM "Blogs" AS "b" +> GROUP BY "b"."Language" +> ``` + + ### Queries using Count != 0 are optimized @@ -712,6 +831,8 @@ WHERE EXISTS ( WHERE "b"."Id" = "p"."BlogId") ``` + + ### C# semantics for comparison operations on nullable values In EF8 comparisons between nullable elements were not performed correctly for some scenarios. In C#, if one or both operands are null, the result of a comparison operation is false; otherwise, the contained values of operands are compared. In EF8 we used to translate comparisons using database null semantics. This would produce results different than similar query using LINQ to Objects. @@ -782,6 +903,59 @@ EF9 now properly handles these scenarios, producing results consistent with LINQ This enhancement was contributed by [@ranma42](https://github.com/ranma42). Many thanks! + + +### Translation of `Order` and `OrderDescending` LINQ operators + +EF9 enables the translation of LINQ simplified ordering operations (`Order` and `OrderDescending`). These work similar to `OrderBy`/`OrderByDescending` but don't require an argument. Instead, they apply default ordering - for entities this means ordering based on primary key values and for other types, ordering based on the values themselves. + +Below is an example query which takes advantage of the simplified ordering operators: + + +[!code-csharp[OrderOrderDescending](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=OrderOrderDescending)] + +This query is equivalent to the following: + + +[!code-csharp[OrderByEquivalent](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=OrderByEquivalent)] + +and produces the following SQL: + +```sql +SELECT [b].[Name], [b].[Id], [p].[Id], [p].[Archived], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Discriminator], [p].[PublishedOn], [p].[Rating], [p].[Title], [p].[PromoText], [p].[Metadata], [p0].[Title], [p0].[Id] +FROM [Blogs] AS [b] +LEFT JOIN [Posts] AS [p] ON [b].[Id] = [p].[BlogId] +LEFT JOIN [Posts] AS [p0] ON [b].[Id] = [p0].[BlogId] +ORDER BY [b].[Id], [p].[Id] DESC, [p0].[Title] +``` + +> [!NOTE] +> `Order` and `OrderDescending` methods are only supported for collections of entities, complex types or scalars - they will not work on more complex projections, e.g. collections of anonymous types containing multiple properties. + +This enhancement was contributed by the EF Team alumnus [@bricelam](https://github.com/bricelam). Many thanks! + + + ### Improved translation of logical negation operator (!) EF9 brings many optimizimations around SQL `CASE/WHEN`, `COALESCE`, negation, and various other constructs; most of these were contributed by Andrea Canciani ([@ranma42](https://github.com/ranma42)) - many thanks for all of these! Below, we'll detail just a few of these optimizations around logical negation. @@ -848,7 +1022,7 @@ On SQL Server, when projecting a negated bool property: -[!code-csharp[XorBoolProjection](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=XorBoolProjection)] +[!code-csharp[NegatedBoolProjection](../../../../samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs?name=NegatedBoolProjection)] EF8 would generate a `CASE` block because comparisons can't appear in the projection directly in SQL Server queries: @@ -860,13 +1034,20 @@ END AS [Active] FROM [Posts] AS [p] ``` -In EF9 this translation has been simplified and now uses exclusive or (`^`): +In EF9, this translation has been simplified and now uses bitwise NOT (`~`): ```sql -SELECT [p].[Title], [p].[Archived] ^ CAST(1 AS bit) AS [Active] +SELECT [p].[Title], ~[p].[Archived] AS [Active] FROM [Posts] AS [p] ``` + + +### Better support for Azure SQL and Azure Synapse + +EF9 allows for more flexibility when specifying the type of SQL Server which is being targeted. Instead of configuring EF with `UseSqlServer`, you can now specify `UseAzureSql` or `UseAzureSynapse`. +This allows EF to produce better SQL when using Azure SQL or Azure Synapse. EF can take advantage of the database specific features (e.g. [dedicated type for JSON on Azure SQL](/sql/t-sql/data-types/json-data-type)), or work around its limitations (e.g. [`ESCAPE` clause is not available when using `LIKE` on Azure Synapse](/sql/t-sql/language-elements/like-transact-sql#syntax)). + ### Other query improvements * The primitive collections querying support [introduced in EF8](xref:core/what-is-new/ef-core-8.0/whatsnew#queries-with-primitive-collections) has been extended to support all `ICollection` types. Note that this applies only to parameter and inline collections - primitive collections that are part of entities are still limited to arrays, lists and [in EF9 also read-only arrays/lists](#read-only-primitive-collections). @@ -878,6 +1059,9 @@ FROM [Posts] AS [p] * `Sum` and `Average` now work for decimals on SQLite ([#33721](https://github.com/dotnet/efcore/pull/33721), contributed by [@ranma42](https://github.com/ranma42)). * Fixes and optimizations to `string.StartsWith` and `EndsWith` ([#31482](https://github.com/dotnet/efcore/pull/31482)). * `Convert.To*` methods can now accept argument of type `object` ([#33891](https://github.com/dotnet/efcore/pull/33891), contributed by [@imangd](https://github.com/imangd)). +* Exclusive-Or (XOR) operation is now translated on SQL Server ([#34071](https://github.com/dotnet/efcore/pull/34071), contributed by [@ranma42](https://github.com/ranma42)). +* Optimizations around nullability for `COLLATE` and `AT TIME ZONE` operations ([#34263](https://github.com/dotnet/efcore/pull/34263), contributed by [@ranma42](https://github.com/ranma42)). +* Optimizations for `DISTINCT` over `IN`, `EXISTS` and set operations ([#34381](https://github.com/dotnet/efcore/pull/34381), contributed by [@ranma42](https://github.com/ranma42)). The above were only some of the more important query improvements in EF9; see [this issue](https://github.com/dotnet/efcore/issues/34151) for a more complete listing. diff --git a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs index 0b6c434026..aaadd10ff4 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs @@ -38,6 +38,15 @@ async Task> GetPosts(int id) .ToListAsync(); #endregion + _ = await GetPostsPrimitiveCollection([1, 2, 3]); + + #region DefaultParameterizationPrimitiveCollection + async Task> GetPostsPrimitiveCollection(int[] ids) + => await context.Posts + .Where(e => e.Title == ".NET Blog" && ids.Contains(e.Id)) + .ToListAsync(); + #endregion + Console.WriteLine(); Console.WriteLine("Force parameterization of a constant:"); Console.WriteLine(); @@ -64,6 +73,20 @@ async Task> GetPostsForceConstant(int id) .ToListAsync(); #endregion + Console.WriteLine(); + Console.WriteLine("Force constant primitive collection:"); + Console.WriteLine(); + + _ = await GetPostsForceConstantCollection([1, 2, 3]); + + #region ForceConstantPrimitiveCollection + async Task> GetPostsForceConstantCollection(int[] ids) + => await context.Posts + .Where( + e => e.Title == ".NET Blog" && EF.Constant(ids).Contains(e.Id)) + .ToListAsync(); + #endregion + Console.WriteLine(); Console.WriteLine("Inline subquery:"); Console.WriteLine(); @@ -115,12 +138,20 @@ async Task> GetPostsForceConstant(int id) #endregion } + Console.WriteLine(); + Console.WriteLine("Case translation improvements:"); + Console.WriteLine(); + #region CaseTranslationImprovements var caseSimplification = await context.Blogs .Select(b => !(b.Id > 5 ? false : true)) .ToListAsync(); #endregion + Console.WriteLine(); + Console.WriteLine("Negated bool improvements:"); + Console.WriteLine(); + if (context.UseSqlite) { #region NegatedContainsImprovements @@ -130,16 +161,24 @@ async Task> GetPostsForceConstant(int id) #endregion } - #region XorBoolProjection + #region NegatedBoolProjection var negatedBoolProjection = await context.Posts.Select(x => new { x.Title, Active = !x.Archived }).ToListAsync(); #endregion + Console.WriteLine(); + Console.WriteLine("Enum to string translation:"); + Console.WriteLine(); + #region EnumToString var englishAndSpanishBlogs = await context.Blogs .Where(x => x.Language.ToString().EndsWith("ish")) .Select(x => x.Name).ToListAsync(); #endregion + Console.WriteLine(); + Console.WriteLine("Average on decimal:"); + Console.WriteLine(); + #region AverageOnDecimal var averagePostRating = await context.Blogs.Select(x => new { @@ -148,10 +187,89 @@ async Task> GetPostsForceConstant(int id) }).ToListAsync(); #endregion - #region ConvertFromObject - var blogWithConversion = await context.Blogs + Console.WriteLine(); + Console.WriteLine("Convert from object:"); + Console.WriteLine(); + + if (!context.UseSqlite) + { + #region ConvertFromObject + var blogWithConversion = await context.Blogs .Where(x => Convert.ToDecimal((object)Convert.ToString(x.Id)) == 1.0M) .ToListAsync(); + #endregion + } + + Console.WriteLine(); + Console.WriteLine("Xor support:"); + Console.WriteLine(); + + if (!context.UseSqlite) + { + #region XorSupport + var xorSupportBool = await context.Posts.CountAsync(x => x.Archived ^ (x.Rating > 3.5M)); + var xorSupportInt = await context.Posts.Where(x => (x.Id ^ 7) > 10).ToListAsync(); + #endregion + } + + Console.WriteLine(); + Console.WriteLine("Aggregate over subquery/aggregate:"); + Console.WriteLine(); + + #region AggregateOverSubquery + var latestPostsAverageRatingByLanguage = await context.Blogs. + Select(x => new + { + x.Language, + LatestPostRating = x.Posts.OrderByDescending(xx => xx.PublishedOn).FirstOrDefault().Rating + }) + .GroupBy(x => x.Language) + .Select(x => x.Average(xx => xx.LatestPostRating)) + .ToListAsync(); + #endregion + + // Max over decimal is not supported on Sqlite + if (!context.UseSqlite) + { + #region AggregateOverAggregate + var topRatedPostsAverageRatingByLanguage = await context.Blogs. + Select(x => new + { + x.Language, + TopRating = x.Posts.Max(x => x.Rating) + }) + .GroupBy(x => x.Language) + .Select(x => x.Average(xx => xx.TopRating)) + .ToListAsync(); + #endregion + } + + Console.WriteLine(); + Console.WriteLine("Order and OrderDescending:"); + Console.WriteLine(); + + #region OrderOrderDescending + var orderOperation = await context.Blogs + .Order() + .Select(x => new + { + x.Name, + OrderedPosts = x.Posts.OrderDescending().ToList(), + OrderedTitles = x.Posts.Select(xx => xx.Title).Order().ToList() + }) + .ToListAsync(); + #endregion + + #region OrderByEquivalent + var orderByEquivalent = await context.Blogs + .OrderBy(x => x.Id) + .Select(x => new + { + x.Name, + OrderedPosts = x.Posts.OrderByDescending(xx => xx.Id).ToList(), + OrderedTitles = x.Posts.Select(xx => xx.Title).OrderBy(xx => xx).ToList() + }) + .ToListAsync(); #endregion } From 32b88aad8388d0fc559d2e171bb032c4cdee2048 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Mon, 7 Oct 2024 08:52:30 +0200 Subject: [PATCH 044/224] Fix some auto-detected typos (#4826) --- entity-framework/core/extensions/index.md | 2 +- entity-framework/core/modeling/owned-entities.md | 2 +- .../core/providers/cosmos/planetary-docs-sample.md | 2 +- entity-framework/core/querying/sql-queries.md | 2 +- .../core/saving/execute-insert-update-delete.md | 2 +- .../core/what-is-new/ef-core-3.x/breaking-changes.md | 4 ++-- entity-framework/core/what-is-new/ef-core-3.x/index.md | 2 +- .../core/what-is-new/ef-core-6.0/breaking-changes.md | 2 +- entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md | 2 +- .../core/what-is-new/ef-core-7.0/breaking-changes.md | 2 +- entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md | 2 +- entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md | 2 +- .../core/what-is-new/ef-core-9.0/breaking-changes.md | 2 +- entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md | 6 +++--- .../ef6/fundamentals/configuring/dependency-resolution.md | 4 ++-- .../ef6/fundamentals/providers/provider-model.md | 4 ++-- .../ef6/fundamentals/testing/writing-test-doubles.md | 2 +- .../ef6/modeling/code-first/data-annotations.md | 2 +- .../ef6/modeling/designer/stored-procedures/query.md | 2 +- entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md | 2 +- entity-framework/ef6/what-is-new/past-releases.md | 2 +- 21 files changed, 26 insertions(+), 26 deletions(-) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index 979cbf80ea..7077b8b051 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -339,7 +339,7 @@ The Dynamic LINQ library let you execute query with dynamic string and provide s ### EfCoreNexus.Framework -EfCoreNexus helps integrating the entity framework core into blazor apps. Via reflection it adds the entitiy classes automatically and provides you with basic crud functionality for them without writing additional code. +EfCoreNexus helps integrating the entity framework core into blazor apps. Via reflection it adds the entity classes automatically and provides you with basic crud functionality for them without writing additional code. For EF Core: 8. diff --git a/entity-framework/core/modeling/owned-entities.md b/entity-framework/core/modeling/owned-entities.md index 2a067aa1bf..b0b9817afd 100644 --- a/entity-framework/core/modeling/owned-entities.md +++ b/entity-framework/core/modeling/owned-entities.md @@ -69,7 +69,7 @@ To configure a different primary key call `HasKey`. The model above is mapped to the following database schema: -![Sceenshot of the database model for entity containing owned collection](_static/owned-entities-ownsmany.png) +![Screenshot of the database model for entity containing owned collection](_static/owned-entities-ownsmany.png) ## Mapping owned types with table splitting diff --git a/entity-framework/core/providers/cosmos/planetary-docs-sample.md b/entity-framework/core/providers/cosmos/planetary-docs-sample.md index 71fd6f8d56..2225fe864c 100644 --- a/entity-framework/core/providers/cosmos/planetary-docs-sample.md +++ b/entity-framework/core/providers/cosmos/planetary-docs-sample.md @@ -16,7 +16,7 @@ Here's how to get started in a few easy steps. ### Clone this repo -Using your preferred tools, clone the repository. The `git` commmand looks like this: +Using your preferred tools, clone the repository. The `git` command looks like this: ```bash git clone https://github.com/dotnet/EntityFramework.Docs diff --git a/entity-framework/core/querying/sql-queries.md b/entity-framework/core/querying/sql-queries.md index d059b526e2..743f7c0e70 100644 --- a/entity-framework/core/querying/sql-queries.md +++ b/entity-framework/core/querying/sql-queries.md @@ -84,7 +84,7 @@ On the other hand, the column value is sent via a `DbParameter`, and is therefor > [!WARNING] > -> Be very careful when using , and always make sure values are either from a safe origin, or are properly sanitized. SQL injection attacks can have disasterous consequences for your application. +> Be very careful when using , and always make sure values are either from a safe origin, or are properly sanitized. SQL injection attacks can have disastrous consequences for your application. ## Composing with LINQ diff --git a/entity-framework/core/saving/execute-insert-update-delete.md b/entity-framework/core/saving/execute-insert-update-delete.md index 66aa999d02..ba93387744 100644 --- a/entity-framework/core/saving/execute-insert-update-delete.md +++ b/entity-framework/core/saving/execute-insert-update-delete.md @@ -94,7 +94,7 @@ context.Blogs .ExecuteUpdate(setters => setters.SetProperty(b => b.Rating, b => b.Rating + 1)); ``` -Note that the second argument to `SetProperty` is now a lambda function, and not a constant as before. Its `b` parameter represents the Blog being updated; within that lambda, `b.Rating` thus contains the rating before any change occured. This executes the following SQL: +Note that the second argument to `SetProperty` is now a lambda function, and not a constant as before. Its `b` parameter represents the Blog being updated; within that lambda, `b.Rating` thus contains the rating before any change occurred. This executes the following SQL: ```sql UPDATE [b] diff --git a/entity-framework/core/what-is-new/ef-core-3.x/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-3.x/breaking-changes.md index e5ca3ddd94..87c84b8790 100644 --- a/entity-framework/core/what-is-new/ef-core-3.x/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-3.x/breaking-changes.md @@ -688,7 +688,7 @@ Starting with 3.0, EF Core only creates one column for `ShippingAddress`. #### Why -The old behavoir was unexpected. +The old behavior was unexpected. #### Mitigations @@ -1421,7 +1421,7 @@ Microsoft.Data.Sqlite remains capable of reading Guid values from both BLOB and #### Old behavior -Char values were previously sored as INTEGER values on SQLite. For example, a char value of _A_ was stored as the integer value 65. +Char values were previously stored as INTEGER values on SQLite. For example, a char value of _A_ was stored as the integer value 65. #### New behavior diff --git a/entity-framework/core/what-is-new/ef-core-3.x/index.md b/entity-framework/core/what-is-new/ef-core-3.x/index.md index c8018b359f..a819209589 100644 --- a/entity-framework/core/what-is-new/ef-core-3.x/index.md +++ b/entity-framework/core/what-is-new/ef-core-3.x/index.md @@ -58,7 +58,7 @@ Similarly to client evaluation, if EF Core 3.x can't translate a LINQ query into ## Azure Cosmos DB support -The Azure Cosmos DB provider for EF Core enables developers familiar with the EF programing model to easily target Azure Cosmos DB as an application database. The goal is to make some of the advantages of Azure Cosmos DB, like global distribution, "always on" availability, elastic scalability, and low latency, even more accessible to .NET developers. The provider enables most EF Core features, like automatic change tracking, LINQ, and value conversions, against Azure Cosmos DB for NoSQL. +The Azure Cosmos DB provider for EF Core enables developers familiar with the EF programming model to easily target Azure Cosmos DB as an application database. The goal is to make some of the advantages of Azure Cosmos DB, like global distribution, "always on" availability, elastic scalability, and low latency, even more accessible to .NET developers. The provider enables most EF Core features, like automatic change tracking, LINQ, and value conversions, against Azure Cosmos DB for NoSQL. See the [Azure Cosmos DB provider documentation](xref:core/providers/cosmos/index) for more details. diff --git a/entity-framework/core/what-is-new/ef-core-6.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-6.0/breaking-changes.md index 475f1a1abb..19186218f1 100644 --- a/entity-framework/core/what-is-new/ef-core-6.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-6.0/breaking-changes.md @@ -315,7 +315,7 @@ OnDelete() | ON DELETE NoAction | NO ACTION ClientNoAction | NO ACTION Restrict | RESTRICT -Cascasde | CASCADE +Cascade | CASCADE ClientCascade | ~~RESTRICT~~ **NO ACTION** SetNull | SET NULL ClientSetNull | ~~RESTRICT~~ **NO ACTION** diff --git a/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md index efa51c05b5..8e8976f293 100644 --- a/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md @@ -944,7 +944,7 @@ The Azure Cosmos DB provider now translates more Base Class Library (BCL) method | `+` operator | `CONCAT` | | | `String.IndexOf` | `INDEX_OF` | | | `String.Replace` | `REPLACE` | | -| `String.Equals` | `STRINGEQUAL` | Only case-insensitive calls | +| `String.Equals` | `STRINGEQUALS` | Only case-insensitive calls | Translations for `LOWER`, `LTRIM`, `RTRIM`, `TRIM`, `UPPER`, and `SUBSTRING` were contributed by [@Marusyk](https://github.com/Marusyk). Many thanks! diff --git a/entity-framework/core/what-is-new/ef-core-7.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-7.0/breaking-changes.md index 4328402217..135220137d 100644 --- a/entity-framework/core/what-is-new/ef-core-7.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-7.0/breaking-changes.md @@ -68,7 +68,7 @@ This change was made to ensure that, by default, either the connection is secure There are three ways to proceed: 1. [Install a valid certificate on the server](/sql/database-engine/configure-windows/enable-encrypted-connections-to-the-database-engine). Note that this is an involved process and requires obtaining a certificate and ensuring it is signed by an authority trusted by the client. -2. If the server has a certificate, but it is not trusted by the client, then `TrustServerCertificate=True` to allow bypassing the normal trust mechanims. +2. If the server has a certificate, but it is not trusted by the client, then `TrustServerCertificate=True` to allow bypassing the normal trust mechanism. 3. Explicitly add `Encrypt=False` to the connection string. > [!WARNING] diff --git a/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md index bd68018d77..f0ddb94f56 100644 --- a/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md @@ -1991,7 +1991,7 @@ Model: _id PK ``` -Notice that normally, `IsClean` would have been mapped, but since it is not marked with `[Perist]` (presumably because cleanliness is not a persistent property of laundry), it is now treated as an un-mapped property. +Notice that normally, `IsClean` would have been mapped, but since it is not marked with `[Persist]` (presumably because cleanliness is not a persistent property of laundry), it is now treated as an un-mapped property. > [!TIP] > This convention could not be implemented as a model finalizing convention because mapping a property triggers many other conventions to run to further configure the mapped property. diff --git a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md index 7ebe826557..d75d3a1f7b 100644 --- a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md @@ -2248,7 +2248,7 @@ You can also perform this check programmatically in your application or tests us ## Enhancements to SQLite scaffolding -SQLite only supports four primitive data types--INTEGER, REAL, TEXT, and BLOB. Previously, this meant that when you reverse engineerd a SQLite database to [scaffold an EF Core model](xref:core/managing-schemas/scaffolding), the resulting entity types would only included properties of type `long`, `double`, `string`, and `byte[]`. Additional .NET types are supported by the EF Core SQLite provider by converting between them and one of the four primitive SQLite types. +SQLite only supports four primitive data types--INTEGER, REAL, TEXT, and BLOB. Previously, this meant that when you reverse engineered a SQLite database to [scaffold an EF Core model](xref:core/managing-schemas/scaffolding), the resulting entity types would only included properties of type `long`, `double`, `string`, and `byte[]`. Additional .NET types are supported by the EF Core SQLite provider by converting between them and one of the four primitive SQLite types. In EF Core 8, we now use the data format and column type name in addition to the SQLite type in order to determine a more appropriate .NET type to use in the model. The following tables show some of the cases where the additional information leads to better property types in the model. diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index 7ce2811e34..bc780f3895 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -89,7 +89,7 @@ Make sure the `argumentsPropagateNullability` has same number of elements as the #### Old behavior -Previously EF returned inconsistent results for the `ToString()` method when the argument value was `null`. E.g. `ToString()` on `bool?` property with `null` value returned `null`, but for non-property `bool?` expressions whose value was `null` it returned `True`. The behavior was also incosistent for other data types, e.g. `ToString()` on `null` value enum returned empty string. +Previously EF returned inconsistent results for the `ToString()` method when the argument value was `null`. E.g. `ToString()` on `bool?` property with `null` value returned `null`, but for non-property `bool?` expressions whose value was `null` it returned `True`. The behavior was also inconsistent for other data types, e.g. `ToString()` on `null` value enum returned empty string. #### New behavior 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 a0d4b30c6c..95c5777e25 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 @@ -836,7 +836,7 @@ WHERE EXISTS ( ### C# semantics for comparison operations on nullable values In EF8 comparisons between nullable elements were not performed correctly for some scenarios. In C#, if one or both operands are null, the result of a comparison operation is false; otherwise, the contained values of operands are compared. In EF8 we used to translate comparisons using database null semantics. This would produce results different than similar query using LINQ to Objects. -Moreover, we would produce different results when comparison was done in filter vs projection. Some queris would also produce differet results between Sql Server and Sqlite/Postgres. +Moreover, we would produce different results when comparison was done in filter vs projection. Some queries would also produce different results between Sql Server and Sqlite/Postgres. For example, the query: @@ -958,7 +958,7 @@ This enhancement was contributed by the EF Team alumnus [@bricelam](https://gith ### Improved translation of logical negation operator (!) -EF9 brings many optimizimations around SQL `CASE/WHEN`, `COALESCE`, negation, and various other constructs; most of these were contributed by Andrea Canciani ([@ranma42](https://github.com/ranma42)) - many thanks for all of these! Below, we'll detail just a few of these optimizations around logical negation. +EF9 brings many optimizations around SQL `CASE/WHEN`, `COALESCE`, negation, and various other constructs; most of these were contributed by Andrea Canciani ([@ranma42](https://github.com/ranma42)) - many thanks for all of these! Below, we'll detail just a few of these optimizations around logical negation. Let's examine the following query: @@ -1570,7 +1570,7 @@ To create a node between these two children, an additional sub-level can be used --> [!code-csharp[HierarchyIdParse2](../../../../samples/core/Miscellaneous/NewInEFCore9/HierarchyIdSample.cs?name=HierarchyIdParse2)] -This creates a node with a `HierarchyId` of `/4/1/3/1/1.5/`, putting it bteween `child1` and `child2`. +This creates a node with a `HierarchyId` of `/4/1/3/1/1.5/`, putting it between `child1` and `child2`. This enhancement was contributed by [@Rezakazemi890](https://github.com/Rezakazemi890). Many thanks! diff --git a/entity-framework/ef6/fundamentals/configuring/dependency-resolution.md b/entity-framework/ef6/fundamentals/configuring/dependency-resolution.md index f2aabe2f1a..28e48f3674 100644 --- a/entity-framework/ef6/fundamentals/configuring/dependency-resolution.md +++ b/entity-framework/ef6/fundamentals/configuring/dependency-resolution.md @@ -97,7 +97,7 @@ This article does not contain full details on how to implement IDbDependencyReso **Object returned**: An EF spatial provider that adds support to the basic EF provider for geography and geometry spatial types. -**Key**: DbSptialServices is asked for in two ways. First, provider-specific spatial services are requested using a DbProviderInfo object (which contains invariant name and manifest token) as the key. Second, DbSpatialServices can be asked for with no key. This is used to resolve the "global spatial provider" which is used when creating stand-alone DbGeography or DbGeometry types. +**Key**: DbSpatialServices is asked for in two ways. First, provider-specific spatial services are requested using a DbProviderInfo object (which contains invariant name and manifest token) as the key. Second, DbSpatialServices can be asked for with no key. This is used to resolve the "global spatial provider" which is used when creating stand-alone DbGeography or DbGeometry types. >[!NOTE] > For more details on provider-related services in EF6 see the [EF6 provider model](xref:ef6/fundamentals/providers/provider-model) section. @@ -190,7 +190,7 @@ This article does not contain full details on how to implement IDbDependencyReso **Version introduced**: EF6.1.0 -**Object returned**: A factory that will be used to create serializers for serialization of strongly-typed custom annotations such that they can be serialized and desterilized into XML for use in Code First Migrations. +**Object returned**: A factory that will be used to create serializers for serialization of strongly-typed custom annotations such that they can be serialized and deserialized into XML for use in Code First Migrations. **Key**: The name of the annotation that is being serialized or deserialized. diff --git a/entity-framework/ef6/fundamentals/providers/provider-model.md b/entity-framework/ef6/fundamentals/providers/provider-model.md index 426f272598..173ec362ee 100644 --- a/entity-framework/ef6/fundamentals/providers/provider-model.md +++ b/entity-framework/ef6/fundamentals/providers/provider-model.md @@ -49,7 +49,7 @@ This is an optional service that allows a provider to create DbConnection object ### DbSpatialServices -This is an optional services that allows a provider to add support for geography and geometry spatial types. An implementation of this service must be supplied in order for an application to use EF with spatial types. DbSptialServices is asked for in two ways. First, provider-specific spatial services are requested using a DbProviderInfo object (which contains invariant name and manifest token) as key. Second, DbSpatialServices can be asked for with no key. This is used to resolve the “global spatial provider” that is used when creating stand-alone DbGeography or DbGeometry types. +This is an optional services that allows a provider to add support for geography and geometry spatial types. An implementation of this service must be supplied in order for an application to use EF with spatial types. DbSpatialServices is asked for in two ways. First, provider-specific spatial services are requested using a DbProviderInfo object (which contains invariant name and manifest token) as key. Second, DbSpatialServices can be asked for with no key. This is used to resolve the “global spatial provider” that is used when creating stand-alone DbGeography or DbGeometry types. ### MigrationSqlGenerator @@ -97,7 +97,7 @@ public class MyConfiguration : DbConfiguration ## Resolving additional services -As mentioned above in the _Provider types overview_ section, a DbProviderServices class can also be used to resolve additional services. This is possible because DbProviderServices implements IDbDependencyResolver and each registered DbProviderServices type is added as a “default resolver”. The IDbDpendencyResolver mechanism is described in more detail in [Dependency Resolution](xref:ef6/fundamentals/configuring/dependency-resolution). However, it is not necessary to understand all the concepts in this specification to resolve additional services in a provider. +As mentioned above in the _Provider types overview_ section, a DbProviderServices class can also be used to resolve additional services. This is possible because DbProviderServices implements IDbDependencyResolver and each registered DbProviderServices type is added as a “default resolver”. The IDbDependencyResolver mechanism is described in more detail in [Dependency Resolution](xref:ef6/fundamentals/configuring/dependency-resolution). However, it is not necessary to understand all the concepts in this specification to resolve additional services in a provider. The most common way for a provider to resolve additional services is to call DbProviderServices.AddDependencyResolver for each service in the constructor of the DbProviderServices class. For example, SqlProviderServices (the EF provider for SQL Server) has code similar to this for initialization: diff --git a/entity-framework/ef6/fundamentals/testing/writing-test-doubles.md b/entity-framework/ef6/fundamentals/testing/writing-test-doubles.md index 859281ed5f..d486215df5 100644 --- a/entity-framework/ef6/fundamentals/testing/writing-test-doubles.md +++ b/entity-framework/ef6/fundamentals/testing/writing-test-doubles.md @@ -158,7 +158,7 @@ namespace TestingDemo Now that we have the real EF model and the service that can use it, it's time to create the in-memory test double that we can use for testing. We've created a TestContext test double for our context. In test doubles we get to choose the behavior we want in order to support the tests we are going to run. In this example we're just capturing the number of times SaveChanges is called, but you can include whatever logic is needed to verify the scenario you are testing. -We've also created a TestDbSet that provides an in-memory implementation of DbSet. We've provided a complete implemention for all the methods on DbSet (except for Find), but you only need to implement the members that your test scenario will use. +We've also created a TestDbSet that provides an in-memory implementation of DbSet. We've provided a complete implementation for all the methods on DbSet (except for Find), but you only need to implement the members that your test scenario will use. TestDbSet makes use of some other infrastructure classes that we've included to ensure that async queries can be processed. diff --git a/entity-framework/ef6/modeling/code-first/data-annotations.md b/entity-framework/ef6/modeling/code-first/data-annotations.md index 9ffeb2eefb..5d3aa47751 100644 --- a/entity-framework/ef6/modeling/code-first/data-annotations.md +++ b/entity-framework/ef6/modeling/code-first/data-annotations.md @@ -42,7 +42,7 @@ I’ll demonstrate Code First DataAnnotations with a simple pair of classes: Blo } ``` -As they are, the Blog and Post classes conveniently follow code first convention and require no tweaks to enable EF compatability. However, you can also use the annotations to provide more information to EF about the classes and the database to which they map. +As they are, the Blog and Post classes conveniently follow code first convention and require no tweaks to enable EF compatibility. However, you can also use the annotations to provide more information to EF about the classes and the database to which they map.   diff --git a/entity-framework/ef6/modeling/designer/stored-procedures/query.md b/entity-framework/ef6/modeling/designer/stored-procedures/query.md index 0916107d64..995f5b6724 100644 --- a/entity-framework/ef6/modeling/designer/stored-procedures/query.md +++ b/entity-framework/ef6/modeling/designer/stored-procedures/query.md @@ -44,7 +44,7 @@ To complete this walkthrough, you will need: ![Import Stored Procedures](~/ef6/media/import.jpg) - *Starting with Visual Studio 2012 the EF Designer supports bulk import of stored procedures. The **Import selected stored procedures and functions into theentity model** is checked by default.* + *Starting with Visual Studio 2012 the EF Designer supports bulk import of stored procedures. The **Import selected stored procedures and functions into the entity model** is checked by default.* - Click **Finish**. By default, the result shape of each imported stored procedure or function that returns more than one column will automatically become a new complex type. In this example we want to map the results of the **GetStudentGrades** function to the **StudentGrade** entity and the results of the **GetDepartmentName** to **none** (**none** is the default value). diff --git a/entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md b/entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md index 933d6630f7..45395a4a39 100644 --- a/entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md +++ b/entity-framework/ef6/what-is-new/microsoft-ef6-sqlserver.md @@ -13,7 +13,7 @@ This Entity Framework 6 provider is a replacement provider for the built-in SQL This provider depends on the modern [Microsoft.Data.SqlClient](https://github.com/dotnet/SqlClient) ADO.NET provider, which includes the following advantages over the currently used driver: - Current client receiving full support in contrast to `System.Data.SqlClient`, which is in maintenance mode -- Suports new SQL Server features, including support for the SQL Server 2022 enchanced client protocol (TDS8) +- Supports new SQL Server features, including support for the SQL Server 2022 enhanced client protocol (TDS8) - Supports most Azure Active Directory authentication methods - Supports Always Encrypted with .NET diff --git a/entity-framework/ef6/what-is-new/past-releases.md b/entity-framework/ef6/what-is-new/past-releases.md index 983e20c440..588a05283f 100644 --- a/entity-framework/ef6/what-is-new/past-releases.md +++ b/entity-framework/ef6/what-is-new/past-releases.md @@ -228,7 +228,7 @@ Here is a list of content we put together specifically for the EF 4.3 release, m ## EF 4.2 The EF 4.2.0 runtime was released to NuGet in November of 2011. This release includes bug fixes to the EF 4.1.1 release. -Because this release only included bug fixes it could have been the EF 4.1.2 patch release but we opted to move to 4.2 to allow us to move away from the date based patch version numbers we used in the 4.1.x releases and adopt the [Semantic Versionsing](https://semver.org) standard for semantic versioning. +Because this release only included bug fixes it could have been the EF 4.1.2 patch release but we opted to move to 4.2 to allow us to move away from the date based patch version numbers we used in the 4.1.x releases and adopt the [Semantic Versioning](https://semver.org) standard for semantic versioning. Here is a list of content we put together specifically for the EF 4.2 release, the content provided for EF 4.1 still applies to EF 4.2 as well: From cbe0130aa78f583db062deb8a4a09a59466eb4d8 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 8 Oct 2024 03:03:07 +0200 Subject: [PATCH 045/224] Add note to SQLite limitations page on concurrency tokens (#4829) Fixes #4827 --- entity-framework/core/providers/sqlite/limitations.md | 1 + 1 file changed, 1 insertion(+) diff --git a/entity-framework/core/providers/sqlite/limitations.md b/entity-framework/core/providers/sqlite/limitations.md index 2ad2f8e20f..c57cb4e361 100644 --- a/entity-framework/core/providers/sqlite/limitations.md +++ b/entity-framework/core/providers/sqlite/limitations.md @@ -15,6 +15,7 @@ The common relational library (shared by Entity Framework relational database pr * Schemas * Sequences +* Database-generated concurrency tokens ([see documentation](xref:core/saving/concurrency#native-database-generated-concurrency-tokens)) ## Query limitations From e27774bec495eaedf617ade7745fa08d97f4094c Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Wed, 9 Oct 2024 17:43:36 -0700 Subject: [PATCH 046/224] Add breaking change for the updated dependencies. (#4830) --- .../ef-core-9.0/breaking-changes.md | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index bc780f3895..b0a47e750b 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -2,7 +2,7 @@ title: Breaking changes in EF Core 9 (EF9) - EF Core description: List of breaking changes introduced in Entity Framework Core 9 (EF9) author: ajcvickers -ms.date: 03/25/2024 +ms.date: 10/07/2024 uid: core/what-is-new/ef-core-9.0/breaking-changes --- @@ -28,6 +28,7 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET | [`EF.Functions.Unhex()` now returns `byte[]?`](#unhex) | Low | | [SqlFunctionExpression's nullability arguments' arity validated](#sqlfunctionexpression-nullability) | Low | | [`ToString()` method now returns empty string for `null` instances](#nullable-tostring) | Low | +| [Shared framework dependencies were updated to 9.0.x](#shared-framework-dependencies) | Low | ## Low-impact changes @@ -108,6 +109,26 @@ var newBehavior = context.Entity.Select(x => x.NullableBool.ToString()); var oldBehavior = context.Entity.Select(x => x.NullableBool == null ? null : x.NullableBool.ToString()); ``` + + +### Shared framework dependencies were updated to 9.0.x + +#### Old behavior + +Apps using the `Microsoft.NET.Sdk.Web` SDK and targetting net8.0 would resolve packages like `System.Text.Json`, `Microsoft.Extensions.Caching.Memory`, `Microsoft.Extensions.Configuration.Abstractions`, `Microsoft.Extensions.Logging` and `Microsoft.Extensions.DependencyModel` from the shared framework, so these assemblies wouldn't normally be deployed with the app. + +#### New behavior + +While EF Core 9.0 still supports net8.0 it now references the 9.0.x versions of `System.Text.Json`, `Microsoft.Extensions.Caching.Memory`, `Microsoft.Extensions.Configuration.Abstractions`, `Microsoft.Extensions.Logging` and `Microsoft.Extensions.DependencyModel`. Apps targetting net8.0 will not be able to leverage the shared framework to avoid deploying these assemblies. + +#### Why + +The matching dependency versions contain the latest security fixes and using them simplifies the servicing model for EF Core. + +#### Mitigations + +Change your app to target net9.0 to get the previous behavior. + ## Azure Cosmos DB breaking changes Extensive work has gone into making the Azure Cosmos DB provider better in 9.0. The changes include a number of high-impact breaking changes; if you are upgrading an existing application, please read the following carefully. From 6e2e9d92377c4b5f4086bceeb09d940e559d5c37 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 10 Oct 2024 19:05:53 +0200 Subject: [PATCH 047/224] Limit the split query determinism warning to EF version prior to 10 (#4831) See https://github.com/dotnet/efcore/issues/26808 --- entity-framework/core/querying/single-split-queries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/querying/single-split-queries.md b/entity-framework/core/querying/single-split-queries.md index 48616d9434..a1a618ab4c 100644 --- a/entity-framework/core/querying/single-split-queries.md +++ b/entity-framework/core/querying/single-split-queries.md @@ -107,7 +107,7 @@ ORDER BY [b].[BlogId] ``` > [!WARNING] -> When using split queries with Skip/Take, pay special attention to making your query ordering fully unique; not doing so could cause incorrect data to be returned. For example, if results are ordered only by date, but there can be multiple results with the same date, then each one of the split queries could each get different results from the database. Ordering by both date and ID (or any other unique property or combination of properties) makes the ordering fully unique and avoids this problem. Note that relational databases do not apply any ordering by default, even on the primary key. +> When using split queries with Skip/Take on EF versions prior to 10, pay special attention to making your query ordering fully unique; not doing so could cause incorrect data to be returned. For example, if results are ordered only by date, but there can be multiple results with the same date, then each one of the split queries could each get different results from the database. Ordering by both date and ID (or any other unique property or combination of properties) makes the ordering fully unique and avoids this problem. Note that relational databases do not apply any ordering by default, even on the primary key. > [!NOTE] > One-to-one related entities are always loaded via JOINs in the same query, as it has no performance impact. From b7d1b165806690888403835eede1b6e3f4e0eff7 Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Sun, 13 Oct 2024 03:13:19 -0700 Subject: [PATCH 048/224] whats new in ef9 - migrations (#4828) --- .../managing-schemas/migrations/applying.md | 2 +- .../core/providers/sqlite/limitations.md | 6 ++++++ .../core/what-is-new/ef-core-9.0/whatsnew.md | 17 ++++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md index 7dd17cdfda..0539ffad76 100644 --- a/entity-framework/core/managing-schemas/migrations/applying.md +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -314,7 +314,7 @@ PS C:\local\AllTogetherNow\SixOh> It's possible for the application itself to apply migrations programmatically, typically during startup. While productive for local development and testing of migrations, this approach is inappropriate for managing production databases, for the following reasons: -* If multiple instances of your application are running, both applications could attempt to apply the migration concurrently and fail (or worse, cause data corruption). +* For versions of EF prior to 9, if multiple instances of your application are running, both applications could attempt to apply the migration concurrently and fail (or worse, cause data corruption). * Similarly, if an application is accessing the database while another application migrates it, this can cause severe issues. * The application must have elevated access to modify the database schema. It's generally good practice to limit the application's database permissions in production. * It's important to be able to roll back an applied migration in case of an issue. The other strategies provide this easily and out of the box. diff --git a/entity-framework/core/providers/sqlite/limitations.md b/entity-framework/core/providers/sqlite/limitations.md index c57cb4e361..b345fba441 100644 --- a/entity-framework/core/providers/sqlite/limitations.md +++ b/entity-framework/core/providers/sqlite/limitations.md @@ -90,6 +90,12 @@ Otherwise, we recommend using `dotnet ef database update` to apply migrations. Y dotnet ef database update --connection "Data Source=My.db" ``` +## Concurrent migrations protection + +EF9 introduced a locking mechanism when executing migrations. It aims to protect against multiple migration executions happening simultaneously, as that could leave the database in a corrupted state. This is one of the potential problems resulting from applying migrations at runtime using the [`DbContext.Database.Migrate()`](/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.migrate) method (see [Applying migrations](xref:core/managing-schemas/migrations/applying) for more information). To mitigate this, EF creates an exclusive lock on the database before any migration operations are applied. + +Unfortunately, SQLite does not have built-in locking mechanism, so EF creates a separate table (`__EFMigrationsLock`) and uses it for locking. The lock is released when the migration completes and the seeding code finishes execution. However, if for some reason migration fails in a non-recoverable way, the lock may not be released correctly. If this happens, consecutive migrations will be blocked from executing SQL and therefore never complete. You can manually unblock them by deleting the `__EFMigrationsLock` table in the database. + ## See also * [Microsoft.Data.Sqlite Async Limitations](/dotnet/standard/data/sqlite/async) 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 95c5777e25..c11f9aba04 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 @@ -1182,6 +1182,21 @@ protected override void Up(MigrationBuilder migrationBuilder) } ``` + + +### Protection against concurrent migrations + +EF9 introduces a locking mechanism to protect against multiple migration executions happening simultaneously, as that could leave the database in a corrupted state. This doesn't happen when migrations are deployed to the production environment using [recommended methods](/ef/core/managing-schemas/migrations/applying#sql-scripts), but can happen if migrations are applied at runtime using the [`DbContext.Database.Migrate()`](/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.migrate) method. We recommend applying migrations at deployment, rather than as part of application startup, but that can result in more complicated application architectures (e.g. [when using .NET Aspire projects](/dotnet/aspire/database/ef-core-migrations). + +> [!NOTE] +> If you are using Sqlite database, see [potential issues associated with this feature](/ef/core/providers/sqlite/limitations#concurrent-migrations-protection). + + + +### Warn when multiple migration operations can't be run inside a transaction + +The majority of operations performed during migrations are protected by a transaction. This ensures that if for some reason migration fails, the database does not end up in a corrupted state. However, some operations are not wrapped in a transaction (e.g. [operations on SQL Server memory-optimized tables](/sql/relational-databases/in-memory-oltp/unsupported-sql-server-features-for-in-memory-oltp#scenarios-not-supported), or database altering operations like modifying the database collation). To avoid corrupting the database in case of migration failure, it is recommended that these operations are performed in isolation using a separate migration. EF9 now detects a scenario when a migration contains multiple operations, one of which can't be wrapped in a transaction, and issues a warning. + ## Model building @@ -1299,7 +1314,7 @@ 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!] +> [!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. From e880eee3851280231dd5d1454a6d31ecdad1a1b7 Mon Sep 17 00:00:00 2001 From: Dave Callan <106764096+davepcallan@users.noreply.github.com> Date: Mon, 14 Oct 2024 07:01:05 +0100 Subject: [PATCH 049/224] Update QueryTrackingBehavior.cs (#4702) Without modification this benchmark fails as blog url and post title and content are not marked as nullable ? and we don't explicitly insert into these fields in the SeedData method so SQL Server rejects the insert. Have amended SeedData to insert dummy data into blog.url, and post.title and post.content. Alternative is to remove these fields or mark them as nullable but in the context of tracking v no-tracking, better to keep a more realistic scenario and just populate the fields IMHO. --- samples/core/Benchmarks/QueryTrackingBehavior.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/core/Benchmarks/QueryTrackingBehavior.cs b/samples/core/Benchmarks/QueryTrackingBehavior.cs index 32eaad6422..0ecb8cc1a9 100644 --- a/samples/core/Benchmarks/QueryTrackingBehavior.cs +++ b/samples/core/Benchmarks/QueryTrackingBehavior.cs @@ -54,8 +54,9 @@ public static void SeedData(int numBlogs, int numPostsPerBlog) { using var context = new BloggingContext(); context.AddRange( - Enumerable.Range(0, numBlogs).Select( - _ => new Blog { Posts = Enumerable.Range(0, numPostsPerBlog).Select(_ => new Post()).ToList() })); + Enumerable.Range(0, numBlogs) + .Select(_ => new Blog { Url = "Some URL", Posts = Enumerable.Range(0, numPostsPerBlog) + .Select(_ => new Post() { Title = "Some Title", Content = "Some Content"}).ToList() })); context.SaveChanges(); } } From 57f0edfeee0a14434fbac71981f1e0592d69e6df Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 14 Oct 2024 08:01:46 +0200 Subject: [PATCH 050/224] Fix typo (#4834) Fixes #4833 --- entity-framework/core/change-tracking/identity-resolution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/change-tracking/identity-resolution.md b/entity-framework/core/change-tracking/identity-resolution.md index 6ede86de18..5c9f066c82 100644 --- a/entity-framework/core/change-tracking/identity-resolution.md +++ b/entity-framework/core/change-tracking/identity-resolution.md @@ -579,7 +579,7 @@ Entity types are often configured to use [automatically generated key values](xr --> [!code-csharp[Pet](../../../samples/core/ChangeTracking/IdentityResolutionInEFCore/IdentityResolutionSamples.cs?name=Pet)] -Consider code that attempts to tracker two new entity instances without setting key values: +Consider code that attempts to track two new entity instances without setting key values: -[!code-csharp[ConfigureServices](../../../samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Startup.cs?name=ConfigureServices)] -This example registers a `DbContext` subclass called `ApplicationDbContext` as a scoped service in the ASP.NET Core application service provider (a.k.a. the dependency injection container). The context is configured to use the SQL Server database provider and will read the connection string from ASP.NET Core configuration. It typically does not matter _where_ in `ConfigureServices` the call to `AddDbContext` is made. +[!code-csharp[snippet_1](../../../samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs?name=snippet_1)] + +The preceding code registers `ApplicationDbContext`, a subclass of `DbContext`, as a scoped service in the ASP.NET Core app service provider. The service provider is also known as the dependency injection container. The context is configured to use the SQL Server database provider and reads the connection string from ASP.NET Core configuration. The `ApplicationDbContext` class must expose a public constructor with a `DbContextOptions` parameter. This is how context configuration from `AddDbContext` is passed to the `DbContext`. For example: @@ -63,9 +68,10 @@ The `ApplicationDbContext` class must expose a public constructor with a `DbCont } } --> + [!code-csharp[ApplicationDbContext](../../../samples/core/Miscellaneous/ConfiguringDbContext/WebApp/ApplicationDbContext.cs?name=ApplicationDbContext)] -`ApplicationDbContext` can then be used in ASP.NET Core controllers or other services through constructor injection. For example: +`ApplicationDbContext` can be used in ASP.NET Core controllers or other services through constructor injection: -## Simple DbContext initialization with 'new' +## Basic DbContext initialization with 'new' -`DbContext` instances can be constructed in the normal .NET way, for example with `new` in C#. Configuration can be performed by overriding the `OnConfiguring` method, or by passing options to the constructor. For example: +`DbContext` instances can be constructed with `new` in C#. Configuration can be performed by overriding the `OnConfiguring` method, or by passing options to the constructor. For example: [!code-csharp[UseNewForWebApp](../../../samples/core/Miscellaneous/ConfiguringDbContext/WebApp/UseNewForWebApp.cs?name=UseNewForWebApp)] -## Using a DbContext factory (e.g. for Blazor) +## Use a DbContext factory Some application types (e.g. [ASP.NET Core Blazor](/aspnet/core/blazor/)) use dependency injection but do not create a service scope that aligns with the desired `DbContext` lifetime. Even where such an alignment does exist, the application may need to perform multiple units-of-work within this scope. For example, multiple units-of-work within a single HTTP request. diff --git a/entity-framework/core/includes/managed-identities-test-non-production.md b/entity-framework/core/includes/managed-identities-test-non-production.md index 42ec1496a8..1a7c06c5d3 100644 --- a/entity-framework/core/includes/managed-identities-test-non-production.md +++ b/entity-framework/core/includes/managed-identities-test-non-production.md @@ -4,6 +4,7 @@ author: rick-anderson ms.author: riande ms.date: 10/23/2024 ms.topic: include +title: an include file --- > [!WARNING] -> This article uses a local database that doesn't require the user to be authenticated. Production apps should use the most secure authentication flow available. For more information on authentication for deployed test and production apps, see [Secure authentication flows](xref:security/index#secure-authentication-flows). +> This article uses a local database that doesn't require the user to be authenticated. Production apps should use the most secure authentication flow available. For more information on authentication for deployed test and production apps, see [Secure authentication flows](/aspnet/core/security/#secure-authentication-flows). diff --git a/entity-framework/core/index.md b/entity-framework/core/index.md index cf68985f76..24f47ebcb1 100644 --- a/entity-framework/core/index.md +++ b/entity-framework/core/index.md @@ -50,7 +50,7 @@ While EF Core is good at abstracting many programming details, there are some be * Find issues in the app that only show up when using a specific versions or edition of the database server. * Catch breaking changes when upgrading EF Core and other dependencies. For example, adding or upgrading frameworks like ASP.NET Core, OData, or AutoMapper. These dependencies can affect EF Core in unexpected ways. * Performance and stress testing with representative loads. The naïve usage of some features doesn't scale well. For example, multiple collections Includes, heavy use of lazy loading, conditional queries on non-indexed columns, massive updates and inserts with store-generated values, lack of concurrency handling, large models, inadequate cache policy. -* Security review: For example, handling of connection strings and other secrets, database permissions for non-deployment operation, input validation for raw SQL, encryption for sensitive data. +* Security review: For example, handling of connection strings and other secrets, database permissions for non-deployment operation, input validation for raw SQL, encryption for sensitive data. See [Secure authentication flows](/aspnet/core/security/#secure-authentication-flows) for secure configuration and authentication flow. * Make sure logging and diagnostics are sufficient and usable. For example, appropriate logging configuration, query tags, and Application Insights. * Error recovery. Prepare contingencies for common failure scenarios such as version rollback, fallback servers, scale-out and load balancing, DoS mitigation, and data backups. * Application deployment and migration. Plan out how migrations are going to be applied during deployment; doing it at application start can suffer from concurrency issues and requires higher permissions than necessary for normal operation. Use staging to facilitate recovery from fatal errors during migration. For more information, see [Applying Migrations](xref:core/managing-schemas/migrations/applying). diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md index 0539ffad76..ed3e45c97a 100644 --- a/entity-framework/core/managing-schemas/migrations/applying.md +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -222,10 +222,10 @@ Options: | `--no-color` | | Don't colorize output. | | `--prefix-output` | | Prefix output with level. | -The following example applies migrations to a local SQL Server instance using the specified username and password. +The following example applies migrations to a local SQL Server instance using the specified username and credentials: ```powershell -.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password=myPassword' +.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password={;'$Credential;'here'}' ``` > [!WARNING] diff --git a/entity-framework/core/managing-schemas/scaffolding/index.md b/entity-framework/core/managing-schemas/scaffolding/index.md index aaba0bf5c3..7d68a744d9 100644 --- a/entity-framework/core/managing-schemas/scaffolding/index.md +++ b/entity-framework/core/managing-schemas/scaffolding/index.md @@ -7,7 +7,7 @@ uid: core/managing-schemas/scaffolding --- # Scaffolding (Reverse Engineering) -Reverse engineering is the process of scaffolding entity type classes and a `DbContext` class based on a database schema. It can be performed using the `Scaffold-DbContext` command of the EF Core Package Manager Console (PMC) tools or the `dotnet ef dbcontext scaffold` command of the .NET Command-line Interface (CLI) tools. +Reverse engineering is the process of scaffolding entity type classes and a [DbContext](/dotnet/api/microsoft.entityframeworkcore.dbcontext) class based on a database schema. It can be performed using the `Scaffold-DbContext` command of the EF Core Package Manager Console (PMC) tools or the `dotnet ef dbcontext scaffold` command of the .NET Command-line Interface (CLI) tools. > [!NOTE] > The scaffolding of a `DbContext` and entity types documented here is distinct from the [scaffolding of controllers in ASP.NET Core](/aspnet/mvc/overview/getting-started/introduction/adding-a-controller) using Visual Studio, which is not documented here. @@ -27,9 +27,11 @@ Both the PMC and the .NET CLI commands have two required arguments: the connecti ### Connection string -The first argument to the command is a connection string to the database. The tools will use this connection string to read the database schema. +[!INCLUDE [managed-identities-test-non-production](~/core/includes/managed-identities-test-non-production.md)] -How you quote and escape the connection string depends on which shell you are using to execute the command; refer to your shell's documentation for more information. For example, PowerShell requires you to escape the `$` character, but not `\`. +The first argument to the command is a connection string to the database. The tools use this connection string to read the database schema. + +How the connection string is quoted and escaped depends on the shell that is used to run the command. Refer to the shell's documentation. For example, PowerShell requires escaping `$`, but not `\`. The following example scaffolds entity types and a `DbContext` from the `Chinook` database located on the machine's SQL Server LocalDB instance, making use of the `Microsoft.EntityFrameworkCore.SqlServer` database provider. diff --git a/entity-framework/core/miscellaneous/multitenancy.md b/entity-framework/core/miscellaneous/multitenancy.md index 51cd9f7bd4..316f72c430 100644 --- a/entity-framework/core/miscellaneous/multitenancy.md +++ b/entity-framework/core/miscellaneous/multitenancy.md @@ -10,6 +10,8 @@ uid: core/miscellaneous/multitenancy Many line of business applications are designed to work with multiple customers. It is important to secure the data so that customer data isn't "leaked" or seen by other customers and potential competitors. These applications are classified as "multi-tenant" because each customer is considered a tenant of the application with their own set of data. +[!INCLUDE [managed-identities-test-non-production](~/core/includes/managed-identities-test-non-production.md)] + > [!IMPORTANT] > This document provides examples and solutions "as is." These are not intended to be "best practices" but rather "working practices" for your consideration. diff --git a/entity-framework/ef6/fundamentals/configuring/config-file.md b/entity-framework/ef6/fundamentals/configuring/config-file.md index 68020abc09..89fba22d06 100644 --- a/entity-framework/ef6/fundamentals/configuring/config-file.md +++ b/entity-framework/ef6/fundamentals/configuring/config-file.md @@ -6,7 +6,16 @@ ms.date: 10/23/2016 uid: ef6/fundamentals/configuring/config-file --- # Configuration File Settings -Entity Framework allows a number of settings to be specified from the configuration file. In general EF follows a ‘convention over configuration’ principle: all the settings discussed in this post have a default behavior, you only need to worry about changing the setting when the default no longer satisfies your requirements. +Entity Framework allows a number of settings to be specified from the configuration file. In general EF follows a ‘convention over configuration’ principle: all the settings discussed in this post have a default behavior, you only need to worry about changing the setting when the default no longer satisfies your requirements. + +## Configuration data guidelines + +* Never store passwords or other sensitive data in configuration provider code or in plain text configuration files. +* Don't use production secrets in development or test environments. +* Specify secrets outside of the project so that they can't be accidentally committed to a source code repository. +* Consider protecting the contents of the configuration file using [Protected Configuration](/dotnet/framework/data/adonet/connection-strings-and-configuration-files#encrypt-configuration-file-sections-using-protected-configuration). + +[!INCLUDE [managed-identities-test-non-production](~/core/includes/managed-identities-test-non-production.md)] ## A Code-Based Alternative diff --git a/entity-framework/ef6/fundamentals/configuring/connection-strings.md b/entity-framework/ef6/fundamentals/configuring/connection-strings.md index 20d8b71ba5..383d8fe70b 100644 --- a/entity-framework/ef6/fundamentals/configuring/connection-strings.md +++ b/entity-framework/ef6/fundamentals/configuring/connection-strings.md @@ -6,12 +6,15 @@ ms.date: 10/23/2016 uid: ef6/fundamentals/configuring/connection-strings --- # Connection strings and models -This topic covers how Entity Framework discovers which database connection to use, and how you can change it. Models created with Code First and the EF Designer are both covered in this topic. +This article covers how Entity Framework discovers which database connection to use, and how to change it. Models created with Code First and the EF Designer are covered. -Typically an Entity Framework application uses a class derived from DbContext. This derived class will call one of the constructors on the base DbContext class to control: +[!INCLUDE [managed-identities-test-non-production](~/core/includes/managed-identities-test-non-production.md)] -- How the context will connect to a database — that is, how a connection string is found/used -- Whether the context will use calculate a model using Code First or load a model created with the EF Designer + +Typically an Entity Framework application uses a class derived from DbContext. This derived class calls one of the constructors on the base DbContext class to control: + +- How the context connects to a database, that is, how a connection string is found and used. +- Whether the context calculates a model using Code First or loads a model created with the EF Designer. - Additional advanced options The following fragments show some of the ways the DbContext constructors can be used. diff --git a/entity-framework/ef6/fundamentals/configuring/dependency-resolution.md b/entity-framework/ef6/fundamentals/configuring/dependency-resolution.md index 28e48f3674..75b56b4903 100644 --- a/entity-framework/ef6/fundamentals/configuring/dependency-resolution.md +++ b/entity-framework/ef6/fundamentals/configuring/dependency-resolution.md @@ -58,7 +58,7 @@ This article does not contain full details on how to implement IDbDependencyReso **Version introduced**: EF6.0.0 -**Object returned**: The connection factory that will be used when EF creates a database connection by convention. That is, when no connection or connection string is given to EF, and no connection string can be found in the app.config or web.config, then this service is used to create a connection by convention. Changing the connection factory can allow EF to use a different type of database (for example, SQL Server Compact Edition) by default. +**Object returned**: The connection factory that will be used when EF creates a database connection by convention. That is, when no connection or connection string is given to EF, and no connection string can be found in the `app.config` or `web.config`, then this service is used to create a connection by convention. Changing the connection factory can allow EF to use a different type of database (for example, SQL Server Compact Edition) by default. Never store passwords or other sensitive data in configuration provider code or in plain text configuration files. Specify secrets outside of the project so that they can't be accidentally committed to a source code repository. Consider protecting the contents of the configuration file using [Protected Configuration](/dotnet/framework/data/adonet/connection-strings-and-configuration-files#encrypt-configuration-file-sections-using-protected-configuration). **Key**: Not used; will be null diff --git a/entity-framework/efcore-and-ef6/porting/port-code.md b/entity-framework/efcore-and-ef6/porting/port-code.md index 168f9d994f..8d3667e3c8 100644 --- a/entity-framework/efcore-and-ef6/porting/port-code.md +++ b/entity-framework/efcore-and-ef6/porting/port-code.md @@ -25,7 +25,7 @@ Most APIs that you use in EF6 are in the `System.Data.Entity` namespace (and rel As described in [configuring the database connection](xref:efcore-and-ef6/porting/port-detailed-cases#configuring-the-database-connection), EF Core has less magic around detecting the database to connect to. You will need to override the `OnConfiguring` method on your derived context, and use the database provider specific API to setup the connection to the database. -Most EF6 applications store the connection string in the applications `App/Web.config` file. In EF Core, you read this connection string using the `ConfigurationManager` API. You may need to add a reference to the `System.Configuration` framework assembly to be able to use this API. +Most EF6 applications store the connection string in the applications `App/Web.config` file. In EF Core, you read this connection string using the `ConfigurationManager` API. You may need to add a reference to the `System.Configuration` framework assembly to be able to use this API: ```csharp public class BloggingContext : DbContext @@ -40,6 +40,9 @@ public class BloggingContext : DbContext } ``` +> Warning +> Never store passwords or other sensitive data in source code or configuration files. Production secrets shouldn't be used for development or test. Secrets shouldn't be deployed with the app. Production secrets should be accessed through a controlled means like Azure Key Vault. Azure test and production secrets can be stored and protected with the [Azure Key Vault configuration provider](/aspnet/core/security/key-vault-configuration). + ## Update your code At this point, it's a matter of addressing compilation errors and reviewing code to see if the behavior changes will impact you. diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Program.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Program.cs index 5b331a6ad7..e4fbbececf 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Program.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Program.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.Hosting; using WebApp; -public class Program +public class Program { public static void Main(string[] args) { diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs new file mode 100644 index 0000000000..e6e96ef97c --- /dev/null +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs @@ -0,0 +1,40 @@ +var builder = WebApplication.CreateBuilder(args); +// +var connectionString = + builder.Configuration.GetConnectionString("DefaultConnection") + ?? throw new InvalidOperationException("Connection string" + + "'DefaultConnection' not found."); + +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +// + +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); +builder.Services.AddRazorPages(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + app.UseHsts(); +} + +app.UseHttpsRedirection(); + +app.UseRouting(); + +app.UseAuthorization(); + +app.MapStaticAssets(); +app.MapRazorPages() + .WithStaticAssets(); + +app.Run(); diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WithContextFactory/FactoryServicesExample.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WithContextFactory/FactoryServicesExample.cs index 034058717a..c31dcf6616 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/WithContextFactory/FactoryServicesExample.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WithContextFactory/FactoryServicesExample.cs @@ -10,8 +10,8 @@ public class FactoryServicesExample public void ConfigureServices(IServiceCollection services) { services.AddDbContextFactory( - options => - options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0")); + options => options.UseSqlServer( + @"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0")); } #endregion } diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WithNew/ApplicationDbContext.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WithNew/ApplicationDbContext.cs index 70df3560a3..29e3b9c2f5 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/WithNew/ApplicationDbContext.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WithNew/ApplicationDbContext.cs @@ -7,7 +7,8 @@ public class ApplicationDbContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0"); + optionsBuilder.UseSqlServer( + @"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0"); } } #endregion diff --git a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs index aaadd10ff4..9937471d30 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs @@ -215,8 +215,7 @@ async Task> GetPostsForceConstantCollection(int[] ids) Console.WriteLine(); Console.WriteLine("Aggregate over subquery/aggregate:"); Console.WriteLine(); - - #region AggregateOverSubquery + // var latestPostsAverageRatingByLanguage = await context.Blogs. Select(x => new { @@ -226,7 +225,7 @@ async Task> GetPostsForceConstantCollection(int[] ids) .GroupBy(x => x.Language) .Select(x => x.Average(xx => xx.LatestPostRating)) .ToListAsync(); - #endregion + // // Max over decimal is not supported on Sqlite if (!context.UseSqlite) From 164bd44a3fe2c68148f804cee6bf6e1fefcc2070 Mon Sep 17 00:00:00 2001 From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:03:23 -1000 Subject: [PATCH 062/224] Don't build includes (#4860) Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com> --- entity-framework/docfx.json | 1 + 1 file changed, 1 insertion(+) diff --git a/entity-framework/docfx.json b/entity-framework/docfx.json index b281877659..7d113f510c 100644 --- a/entity-framework/docfx.json +++ b/entity-framework/docfx.json @@ -33,6 +33,7 @@ "exclude": [ "**/bin/**", "**/obj/**", + "**/includes/**", "_site/**" ] } From 84be86552c22b94f19c0570088ad708ebb5606cf Mon Sep 17 00:00:00 2001 From: Rick Anderson <3605364+Rick-Anderson@users.noreply.github.com> Date: Fri, 1 Nov 2024 22:37:22 -1000 Subject: [PATCH 063/224] Revert "Update .markdownlint.json (#4856)" (#4861) This reverts commit b56e6e110aafa1b34df82b303fea42cbdc365274. --- .markdownlint.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.markdownlint.json b/.markdownlint.json index 52e278cb81..41961c8893 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -1,7 +1,5 @@ { - "default": true, - "first-header-h1": false, - "first-line-h1": false, + "default": true, "MD002": false, "MD013": false, "MD024": false, From c574492c5dc76e7c1f947970696324a8a6392df9 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 12 Nov 2024 10:57:52 +0100 Subject: [PATCH 064/224] Documentation for NativeAOT/precompiled queries (#4868) Closes #3988 --- .../nativeaot-and-precompiled-queries.md | 110 ++++++++++++++++++ .../core/what-is-new/ef-core-9.0/whatsnew.md | 45 ++++--- entity-framework/toc.yml | 3 +- 3 files changed, 142 insertions(+), 16 deletions(-) create mode 100644 entity-framework/core/performance/nativeaot-and-precompiled-queries.md diff --git a/entity-framework/core/performance/nativeaot-and-precompiled-queries.md b/entity-framework/core/performance/nativeaot-and-precompiled-queries.md new file mode 100644 index 0000000000..1ec493d3ac --- /dev/null +++ b/entity-framework/core/performance/nativeaot-and-precompiled-queries.md @@ -0,0 +1,110 @@ +--- +title: NativeAOT Support and Precompiled Queries (Experimental) - EF Core +description: Publishing NativeAOT Entity Framework Core applications and using precompiled queries +author: roji +ms.date: 11/10/2024 +uid: core/performance/nativeaot-and-precompiled-queries +--- +# NativeAOT Support and Precompiled Queries (Experimental) + +> [!WARNING] +> NativeAOT and query precompilation are highly experimental feature, and are not yet suited for production use. The support described below should be viewed as infrastructure towards the final feature, which will likely be released with EF 10. We encourage you to experiment with the current support and report on your experiences, but recommend against deploying EF NativeAOT applications in production. See below for specific known limitations. + +[.NET NativeAOT](/dotnet/core/deploying/native-aot) allows publishing self-contained .NET applications that have been compiled ahead-of-time (AOT). Doing so offers the following advantages: + +* Significantly faster application startup time +* Small, self-contained binaries that have smaller memory footprints and are easier to deploy +* Running applications in environments where just-in-time compilation isn't supported + +EF applications published with NativeAOT start up much faster than the same applications without it. In addition to the general .NET startup improvements that NativeAOT offers (i.e. no JIT compilation required each time), EF also precompiles LINQ queries when publishing your application, so that no processing is needed when starting up and the SQL is already available for immediate execution. The more EF LINQ queries an application has in its code, the faster the startup gains are expected to be. + +## Publishing an EF NativeAOT Application + +First, enable NativeAOT publishing for your project as follows: + +```xml + + true + +``` + +EF's support for LINQ query execution under NativeAOT relies on *query precompilation*: this mechanism statically identifies EF LINQ queries and generates C# [*interceptors*](/dotnet/csharp/whats-new/csharp-12#interceptors), which contain code to execute each specific query. This can significantly cut down on your application's startup time, as the heavy lifting of processing and compiling your LINQ queries into SQL no longer happens every time your application starts up. Instead, each query's interceptor contains the finalized SQL for that query, as well as optimized code to materialize database results as .NET objects. + +C# interceptors are currently an experimental feature, and require a special opt-in in your project file: + +```xml + + $(InterceptorsPreviewNamespaces);Microsoft.EntityFrameworkCore.GeneratedInterceptors + +``` + +Finally, the [`Microsoft.EntityFrameworkCore.Tasks`](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tasks) package contains MSBuild integration that will perform the query precompilation (and generate the required compiled model) when you publish your application: + +```xml + +``` + +You're now ready to publish your EF NativeAOT application: + +```console +dotnet publish -r linux-arm64 -c Release +``` + +This shows publishing a NativeAOT publishing for Linux running on ARM64; [consult this catalog](/dotnet/core/rid-catalog) to find your runtime identifier. If you'd like to generate the interceptors without publishing - for example to examine the generated sources - you can do so via the `net ef dbcontext optimize --precompile-queries --nativeaot` command. + +Due to the way C# interceptors work, any change in the application source invalidates them and requires repeating the above process. As a result, interceptor generation and actual publishing aren't expected to happen in the inner loop, as the developer is working on code; instead, both `dotnet ef dbcontext optimize` and `dotnet publish` can be executed in a publishing/deployment workflow, in a CI/CD system. + +> [!NOTE] +> Publishing currently reports a number of trimming and NativeAOT warnings, meaning that your application isn't fully guaranteed to run properly. This is expected given the current experimental state of NativeAOT support; the final, non-experimental feature will report no warnings. + +## Limitations + +### Dynamic queries are not supported + +Query precompilation performs static analysis of your source code, identifying EF LINQ queries and generating C# interceptors for them. LINQ allows expressing highly dynamic queries, where LINQ operators are composed based on arbitrary conditions; such queries unfortunately cannot be statically analyzed, and are currently unsupported. Consider the following example: + +```c# +IAsyncEnumerable GetBlogs(BlogContext context, bool applyFilter) +{ + IQueryable query = context.Blogs.OrderBy(b => b.Id); + + if (applyFilter) + { + query = query.Where(b => b.Name != "foo"); + } + + return query.AsAsyncEnumerable(); +} +``` + +The above query is split across several statements, and dynamically composes the `Where` operator based on an external parameter; such queries cannot be precompiled. However, it is sometimes possible to rewrite such dynamic queries as multiple non-dynamic queries: + +```c# +IAsyncEnumerable 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(); +``` + +Since the two queries can each be statically analyzed from start to finish, precompilation can handle them. + +Note that dynamic queries will likely be supported in the future when using NativeAOT; however, since they cannot be precompiled, they will continue to slow down your application startup, and will also generally perform less efficiently compared to non-NativeAOT execution; this is because EF internally relies on code generation to materialize database results, but code generation is not supported when using NativeAOT. + +### Other limitations + +* LINQ query expression syntax (sometimes termed "comprehension syntax") is not supported. +* The generated compiled model and query interceptors may currently be quite large in terms of code size, and take a long while to generate. We plan on improving this. +* EF providers may need to build in support for precompiled queries; check your provider's documentation to know whether it is compatible with EF's NativeAOT support. +* Value converters that use captured state are not supported. + +## Precompiled queries without NativeAOT + +Because of the current limitations of EF's NativeAOT support, it may not be usable for some applications. However, you may be able to take advantage of precompiled queries while publishing regular, non-NativeAOT applications; this allows you to at least benefit from the startup time reduction that precompiled queries offer, while being able to use dynamic queries and other features not currently supported with NativeAOT. + +Using precompiled queries without NativeAOT is simply a matter of executing the following: + +```console +dotnet ef dbcontext optimize --precompile-queries +``` + +As shown above, this will generate a compiled model and interceptors for queries which could be precompiled, removing their overhead from your application's startup time. 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 3b4dfc5c2d..20174ae1e9 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 @@ -296,21 +296,36 @@ Note, however, that we plan to fully remove sync support in EF 11, so start upda ## AOT and pre-compiled queries -As mentioned in the introduction, there is a lot of work going on behind the scenes to allow EF Core to run without just-in-time (JIT) compilation. Instead, EF compile ahead-of-time (AOT) everything needed to run queries in the application. This AOT compilation and related processing will happen as part of building and publishing the application. At this point in the EF9 release, there is not much available that can be used by you, the app developer. However, for those interested, the completed issues in EF9 that support AOT and pre-compiled queries are: - -* [Compiled model: Use static binding instead of reflection for properties and fields](https://github.com/dotnet/efcore/issues/24900) -* [Compiled model: Generate lambdas used in change tracking](https://github.com/dotnet/efcore/issues/24904) -* [Make change tracking and the update pipeline compatible with AOT/trimming](https://github.com/dotnet/efcore/issues/29761) -* [Use interceptors to redirect the query to precompiled code](https://github.com/dotnet/efcore/issues/31331) -* [Make all SQL expression nodes quotable](https://github.com/dotnet/efcore/issues/33008) -* [Generate the compiled model during build](https://github.com/dotnet/efcore/issues/24894) -* [Discover the compiled model automatically](https://github.com/dotnet/efcore/issues/24893) -* [Make ParameterExtractingExpressionVisitor capable of extracting paths to evaluatable fragments in the tree](https://github.com/dotnet/efcore/issues/32999) -* [Generate expression trees in compiled models (query filters, value converters)](https://github.com/dotnet/efcore/issues/29924) -* [Make LinqToCSharpSyntaxTranslator more resilient to multiple declaration of the same variable in nested scopes](https://github.com/dotnet/efcore/issues/32716) -* [Optimize ParameterExtractingExpressionVisitor](https://github.com/dotnet/efcore/issues/32698) - -Check back here for examples of how to use pre-compiled queries as the experience comes together. +> [!WARNING] +> NativeAOT and query precompilation are highly experimental features, and are not yet suited for production use. The support described below should be viewed as infrastructure towards the final feature, which will likely be released with EF 10. We encourage you to experiment with the current support and report on your experiences, but recommend against deploying EF NativeAOT applications in production. + +EF 9.0 brings initial, experimental support for [.NET NativeAOT](/dotnet/core/deploying/native-aot), allowing the publishing of ahead-of-time compiled applications which make use of EF to access databases. To support LINQ queries in NativeAOT mode, EF relies on _query precompilation_: this mechanism statically identifies EF LINQ queries and generates C# [_interceptors_](/dotnet/csharp/whats-new/csharp-12#interceptors), which contain code to execute each specific query. This can significantly cut down on your application's startup time, as the heavy lifting of processing and compiling your LINQ queries into SQL no longer happens every time your application starts up. Instead, each query's interceptor contains the finalized SQL for that query, as well as optimized code to materialize database results as .NET objects. + +For example, given a program with the following EF query: + +```c# +var blogs = await context.Blogs.Where(b => b.Name == "foo").ToListAsync(); +``` + +EF will generate a C# interceptor into your project, which will take over the query execution. Instead of processing the query and translating it to SQL every time the program starts, the interceptor has the SQL embedded right into it (for SQL Server in this case), allowing your program to start up much faster: + +```c# +var relationalCommandTemplate = ((IRelationalCommandTemplate)(new RelationalCommand(materializerLiftableConstantContext.CommandBuilderDependencies, "SELECT [b].[Id], [b].[Name]\nFROM [Blogs] AS [b]\nWHERE [b].[Name] = N'foo'", new IRelationalParameter[] { }))); +``` + +In addition, the same interceptor contains code to materialize your .NET object from database results: + +```c# +var instance = new Blog(); +UnsafeAccessor_Blog_Id_Set(instance) = dataReader.GetInt32(0); +UnsafeAccessor_Blog_Name_Set(instance) = dataReader.GetString(1); +``` + +This uses another new .NET feature - [unsafe accessors](/dotnet/api/system.runtime.compilerservices.unsafeaccessorattribute), to inject data from the database into your object's private fields. + +If you're interested in NativeAOT and like to experiment with cutting-edge features, give this a try! Just be aware that the feature should be considered unstable, and currently has many limitations; we expect to stabilize it and make it more suitable for production usage in EF 10. + +See the [NativeAOT documentation page](xref:core/performance/nativeaot-and-precompiled-queries) for more details. ## LINQ and SQL translation diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index ddeb8ef434..3ad60c0e7e 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -350,6 +350,8 @@ href: core/performance/efficient-updating.md - name: Modeling for performance href: core/performance/modeling-for-performance.md + - name: NativeAOT and precompiled queries + href: core/performance/nativeaot-and-precompiled-queries.md - name: Advanced performance topics href: core/performance/advanced-performance-topics.md @@ -361,7 +363,6 @@ href: core/miscellaneous/async.md - name: Nullable reference types href: core/miscellaneous/nullable-reference-types.md - #- name: Using dependency injection - name: Collations and case sensitivity href: core/miscellaneous/collations-and-case-sensitivity.md - name: Connection resiliency From fed9c4222694b38c4d51590e8dca5650ee248f88 Mon Sep 17 00:00:00 2001 From: Ian Kemp Date: Tue, 12 Nov 2024 12:07:06 +0000 Subject: [PATCH 065/224] Correct TimeOnly member names to not be plural (#4869) also reorder DateOnly static members to appear before instance members - in line with DateTime and DateTimeOffset --- .../core/providers/sql-server/functions.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/entity-framework/core/providers/sql-server/functions.md b/entity-framework/core/providers/sql-server/functions.md index ce0835a31b..dd4ef926f7 100644 --- a/entity-framework/core/providers/sql-server/functions.md +++ b/entity-framework/core/providers/sql-server/functions.md @@ -115,12 +115,12 @@ dateTimeOffset.TimeOfDay | CONVERT(time, @dat dateTimeOffset.ToUnixTimeSeconds() | DATEDIFF_BIG(second, '1970-01-01T00:00:00.0000000+00:00', @dateTimeOffset) | EF Core 8.0 dateTimeOffset.ToUnixTimeMilliseconds() | DATEDIFF_BIG(millisecond, '1970-01-01T00:00:00.0000000+00:00', @dateTimeOffset) | EF Core 8.0 dateTimeOffset.Year | DATEPART(year, @dateTimeOffset) +DateOnly.FromDateTime(dateTime) | CONVERT(date, @dateTime) | EF Core 8.0 dateOnly.AddDays(value) | DATEADD(day, @value, @dateOnly) | EF Core 8.0 dateOnly.AddMonths(months) | DATEADD(month, @months, @dateOnly) | EF Core 8.0 dateOnly.AddYears(value) | DATEADD(year, @value, @dateOnly) | EF Core 8.0 dateOnly.Day | DATEPART(day, @dateOnly) | EF Core 8.0 dateOnly.DayOfYear | DATEPART(dayofyear, @dateOnly) | EF Core 8.0 -DateOnly.FromDateTime(dateTime) | CONVERT(date, @dateTime) | EF Core 8.0 dateOnly.Month | DATEPART(month, @dateOnly) | EF Core 8.0 dateOnly.Year | DATEPART(year, @dateOnly) | EF Core 8.0 EF.Functions.AtTimeZone(dateTime, timeZone) | @dateTime AT TIME ZONE @timeZone | EF Core 7.0 @@ -143,11 +143,11 @@ EF.Functions.SmallDateTimeFromParts(year, month, day, ...) | SMALLDATETIMEFROMP EF.Functions.TimeFromParts(hour, minute, second, ...) | TIMEFROMPARTS(@hour, @minute, @second, ...) timeOnly.AddHours(value) | DATEADD(hour, @value, @timeOnly) | EF Core 8.0 timeOnly.AddMinutes(value) | DATEADD(minute, @value, @timeOnly) | EF Core 8.0 -timeOnly.Hours | DATEPART(hour, @timeOnly) | EF Core 8.0 +timeOnly.Hour | DATEPART(hour, @timeOnly) | EF Core 8.0 timeOnly.IsBetween(start, end) | @timeOnly >= @start AND @timeOnly < @end | EF Core 8.0 -timeOnly.Milliseconds | DATEPART(millisecond, @timeOnly) | EF Core 8.0 -timeOnly.Minutes | DATEPART(minute, @timeOnly) | EF Core 8.0 -timeOnly.Seconds | DATEPART(second, @timeOnly) | EF Core 8.0 +timeOnly.Millisecond | DATEPART(millisecond, @timeOnly) | EF Core 8.0 +timeOnly.Minute | DATEPART(minute, @timeOnly) | EF Core 8.0 +timeOnly.Second | DATEPART(second, @timeOnly) | EF Core 8.0 timeSpan.Hours | DATEPART(hour, @timeSpan) timeSpan.Milliseconds | DATEPART(millisecond, @timeSpan) timeSpan.Minutes | DATEPART(minute, @timeSpan) From fccb85411d9022a6799642e7985070da98d0cb5f Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 12 Nov 2024 20:25:05 +0100 Subject: [PATCH 066/224] Fix code reference (#4872) Fixes #4871 --- samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs index 9937471d30..a51ea1ad9e 100644 --- a/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs +++ b/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs @@ -215,17 +215,17 @@ async Task> GetPostsForceConstantCollection(int[] ids) Console.WriteLine(); Console.WriteLine("Aggregate over subquery/aggregate:"); Console.WriteLine(); - // - var latestPostsAverageRatingByLanguage = await context.Blogs. - Select(x => new + #region AggregateOverSubquery + var latestPostsAverageRatingByLanguage = await context.Blogs + .Select(x => new { x.Language, - LatestPostRating = x.Posts.OrderByDescending(xx => xx.PublishedOn).FirstOrDefault().Rating + LatestPostRating = x.Posts.OrderByDescending(xx => xx.PublishedOn).FirstOrDefault()!.Rating }) .GroupBy(x => x.Language) .Select(x => x.Average(xx => xx.LatestPostRating)) .ToListAsync(); - // + #endregion // Max over decimal is not supported on Sqlite if (!context.UseSqlite) From 473282b043408a10b2d8f5797dbfaf258ee28431 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 12 Nov 2024 19:17:16 -0800 Subject: [PATCH 067/224] Add documentation for MSBuild integration (#4870) Clean up connection string documentation Fixes #4700 --- entity-framework/core/cli/dotnet.md | 17 +++-- entity-framework/core/cli/msbuild.md | 49 ++++++++++++++ entity-framework/core/cli/powershell.md | 7 +- .../core/dbcontext-configuration/index.md | 4 +- .../managing-schemas/migrations/applying.md | 5 +- .../managing-schemas/scaffolding/index.md | 65 +------------------ .../core/miscellaneous/connection-strings.md | 17 +++++ .../nativeaot-and-precompiled-queries.md | 11 +++- .../core/what-is-new/ef-core-9.0/whatsnew.md | 32 ++------- .../core/what-is-new/nuget-packages.md | 8 ++- entity-framework/toc.yml | 4 +- .../ConfiguringDbContext.csproj | 6 +- .../ConfiguringDbContext/WebApp/Program.cs | 5 +- .../ConfiguringDbContext/WebApp9/Program9.cs | 9 ++- 14 files changed, 127 insertions(+), 112 deletions(-) create mode 100644 entity-framework/core/cli/msbuild.md diff --git a/entity-framework/core/cli/dotnet.md b/entity-framework/core/cli/dotnet.md index 9ce90fa4b9..76848108d3 100644 --- a/entity-framework/core/cli/dotnet.md +++ b/entity-framework/core/cli/dotnet.md @@ -2,7 +2,7 @@ title: EF Core tools reference (.NET CLI) - EF Core description: Reference guide for the Entity Framework Core .NET Core CLI tools author: SamMonoRT -ms.date: 11/15/2021 +ms.date: 11/08/2024 uid: core/cli/dotnet --- @@ -171,18 +171,27 @@ Lists available `DbContext` types. The [common options](#common-options) are listed above. + + ## `dotnet ef dbcontext optimize` -Generates a compiled version of the model used by the `DbContext`. +Generates a compiled version of the model used by the `DbContext` and precompiles queries. See [Compiled models](xref:core/performance/advanced-performance-topics#compiled-models) for more information. Options: -| Option | Short | Description | -|:-----------------------------------------|:------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Option | Short | Description | +|:-----------------------------------------------------|:------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `--output-dir ` | `-o` | The directory to put files in. Paths are relative to the project directory. | | `--namespace ` | `-n` | The namespace to use for all generated classes. Defaults to generated from the root namespace and the output directory plus `CompiledModels`. | +| `--suffix ` | | The suffix to attach to the name of all the generated files. E.g. `.g` could be used to indicate that these files contain generated code | +| `--no-scaffold` | | Don't generate a compiled model. This is used when the compiled model has already been generated. | +| `--precompile-queries` | | Generate precompiled queries. This is required for NativeAOT compilation if the target project contains any queries | +| `--nativeaot` | | Generate additional code in the compiled model required for NativeAOT compilation and precompiled queries | + +> [!NOTE] +> NativeAOT support and precompiled queries are considered experimental in EF 9 and could change dramatically in the next release. The [common options](#common-options) are listed above. diff --git a/entity-framework/core/cli/msbuild.md b/entity-framework/core/cli/msbuild.md new file mode 100644 index 0000000000..0b20100a09 --- /dev/null +++ b/entity-framework/core/cli/msbuild.md @@ -0,0 +1,49 @@ +--- +title: EF Core MSBuild tasks - EF Core +description: Reference guide for the Entity Framework Core .NET MSBuild tasks +author: AndriySvyryd +ms.date: 11/08/2024 +uid: core/cli/msbuild +--- + +# Entity Framework Core MSBuild integration + +Starting with EF 9, you can use an MSBuild task to generate the compiled model and precompiled queries automatically either when the project is built or when it's published. This is mainly intended to be used with NativeAOT publishing. + +> [!WARNING] +> NativeAOT support and the MSBuild integration are experimental features, and are not yet suited for production use. + +## Installing the tasks + +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 +``` + +> [!NOTE] +> **Every** project that needs to be compiled with generated files should reference the NuGet package, it is not transitive by default. + +## Using the tasks + +If the project specifies `true` then by default the MSBuild task will generate a compiled model and precompiled queries during publishing. Otherwise, you can set the following properties to control the generation behavior: + +| MSBuild property | Description | +|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| EFOptimizeContext | Set to `true` to enable MSBuild integration. | +| EFScaffoldModelStage | Set to `publish`, `build` or `none` to indicate at which stage the compiled model will be generated. Defaults to `publish`. | +| EFPrecompileQueriesStage | Set to `publish`, `build` or `none` to indicate at which stage the precompiled queries will be generated. Defaults to `publish`. | +| DbContextName | The derived `DbContext` class to use. Class name only or fully qualified with namespaces. If this option is omitted, EF Core will perform generation for all context classes in the project. | +| EFTargetNamespace | The namespace to use for all generated classes. If this option is omitted, EF Core will use `$(RootNamespace)`. | +| EFOutputDir | The folder to put the generated files before the project is compiled. If this option is omitted, EF Core will use `$(IntermediateOutputPath)`. | +| EFNullable | Whether nullable reference types will be used in the generated code. If this option is omitted, EF Core will use `$(Nullable)`. | + +## Limitations + +* A different startup project cannot be specified when using this approach as it would introduce an inverse build dependency. This means that the context project needs to be autosuficient in terms of configuration, so if your app normally configures the context using a host builder in a different project you'd need to [implement _IDesignTimeDbContextFactory<TContext>_](xref:core/cli/dbcontext-creation#from-a-design-time-factory) in the context project. +* Since the project needs to be compilable before the compiled model is generated this approach doesn't support partial method implementations for customization of the compiled model. +* Currently, this will always generate additional code in the compiled model that's required for NativeAOT. If you are not planning to enable NativeAOT then [generate the compiled model using the CLI tools](xref:core/cli/dotnet#optimize). + +## Additional resources + +* [Compiled models](xref:core/performance/advanced-performance-topics#compiled-models) diff --git a/entity-framework/core/cli/powershell.md b/entity-framework/core/cli/powershell.md index 55bd24db27..4e067eee9a 100644 --- a/entity-framework/core/cli/powershell.md +++ b/entity-framework/core/cli/powershell.md @@ -2,7 +2,7 @@ title: EF Core tools reference (Package Manager Console) - EF Core description: Reference guide for the Entity Framework Core Visual Studio Package Manager Console author: SamMonoRT -ms.date: 11/15/2021 +ms.date: 11/08/2024 uid: core/cli/powershell --- # Entity Framework Core tools reference - Package Manager Console in Visual Studio @@ -185,6 +185,9 @@ Parameters: The [common parameters](#common-parameters) are listed above. +> [!NOTE] +> The PMC tools currently don't support generating code required for NativeAOT compilation and precompiled queries. + The following example uses the defaults and works if there is only one `DbContext` in the project: ```powershell @@ -246,7 +249,7 @@ Example that scaffolds only selected tables and creates the context in a separat Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables "Blog","Post" -ContextDir Context -Context BlogContext -ContextNamespace New.Namespace ``` -The following example reads the connection string from the project's configuration possibly set using the [Secret Manager tool](/aspnet/core/security/app-secrets#secret-manager). +The following example [reads the connection string using Configuration](xref:core/miscellaneous/connection-strings#aspnet-core). ```powershell Scaffold-DbContext "Name=ConnectionStrings:Blogging" Microsoft.EntityFrameworkCore.SqlServer diff --git a/entity-framework/core/dbcontext-configuration/index.md b/entity-framework/core/dbcontext-configuration/index.md index 82483359f5..a421e7dc9c 100644 --- a/entity-framework/core/dbcontext-configuration/index.md +++ b/entity-framework/core/dbcontext-configuration/index.md @@ -49,13 +49,13 @@ ASP.NET Core applications are [configured using dependency injection](/aspnet/co services.AddControllers(); services.AddDbContext( - options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection")); + options => options.UseSqlServer("name=DefaultConnection")); } --> [!code-csharp[snippet_1](../../../samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs?name=snippet_1)] -The preceding code registers `ApplicationDbContext`, a subclass of `DbContext`, as a scoped service in the ASP.NET Core app service provider. The service provider is also known as the dependency injection container. The context is configured to use the SQL Server database provider and reads the connection string from ASP.NET Core configuration. +The preceding code registers `ApplicationDbContext`, a subclass of `DbContext`, as a scoped service in the ASP.NET Core app service provider. The service provider is also known as the dependency injection container. The context is configured to use the SQL Server database provider and reads the connection string from [ASP.NET Core configuration](xref:core/miscellaneous/connection-strings#aspnet-core). The `ApplicationDbContext` class must expose a public constructor with a `DbContextOptions` parameter. This is how context configuration from `AddDbContext` is passed to the `DbContext`. For example: diff --git a/entity-framework/core/managing-schemas/migrations/applying.md b/entity-framework/core/managing-schemas/migrations/applying.md index ed3e45c97a..4ff1d478d8 100644 --- a/entity-framework/core/managing-schemas/migrations/applying.md +++ b/entity-framework/core/managing-schemas/migrations/applying.md @@ -2,7 +2,7 @@ title: Applying Migrations - EF Core description: Strategies for applying schema migrations to production and development databases using Entity Framework Core author: SamMonoRT -ms.date: 11/02/2021 +ms.date: 10/29/2024 uid: core/managing-schemas/migrations/applying --- # Applying Migrations @@ -117,9 +117,6 @@ The EF command-line tools can be used to apply migrations to a database. While p * The SQL commands are applied directly by the tool, without giving the developer a chance to inspect or modify them. This can be dangerous in a production environment. * The .NET SDK and the EF tool must be installed on production servers and requires the project's source code. -> [!NOTE] -> Each migration is applied in its own transaction. See [GitHub issue #22616](https://github.com/dotnet/efcore/issues/22616) for a discussion of possible future enhancements in this area. - ### [.NET Core CLI](#tab/dotnet-core-cli) The following updates your database to the latest migration: diff --git a/entity-framework/core/managing-schemas/scaffolding/index.md b/entity-framework/core/managing-schemas/scaffolding/index.md index 7d68a744d9..04ef575ecb 100644 --- a/entity-framework/core/managing-schemas/scaffolding/index.md +++ b/entity-framework/core/managing-schemas/scaffolding/index.md @@ -35,7 +35,7 @@ How the connection string is quoted and escaped depends on the shell that is use The following example scaffolds entity types and a `DbContext` from the `Chinook` database located on the machine's SQL Server LocalDB instance, making use of the `Microsoft.EntityFrameworkCore.SqlServer` database provider. -#### [.NET Core CLI](#tab/dotnet-core-cli) +#### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer @@ -49,67 +49,8 @@ Scaffold-DbContext 'Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook' *** -#### User secrets for connection strings - -If you have a .NET application that uses the hosting model and configuration system, such as an ASP.NET Core project, then you can use the `Name=` syntax to read the connection string from configuration. - -For example, consider an ASP.NET Core application with the following configuration file: - -```json -{ - "ConnectionStrings": { - "Chinook": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=Chinook" - } -} -``` - -This connection string in the config file can be used to scaffold from a database using: - -#### [.NET Core CLI](#tab/dotnet-core-cli) - -```dotnetcli -dotnet ef dbcontext scaffold "Name=ConnectionStrings:Chinook" Microsoft.EntityFrameworkCore.SqlServer -``` - -#### [Visual Studio PMC](#tab/vs) - -```powershell -Scaffold-DbContext 'Name=ConnectionStrings:Chinook' Microsoft.EntityFrameworkCore.SqlServer -``` - -*** - -However, storing connection strings in configuration files is not a good idea, since it is too easy to accidentally expose them, for example, by pushing to source control. Instead, connection strings should be stored in a secure way, such as using [Azure Key Vault](/azure/key-vault/keys/quick-create-net) or, when working locally, the [Secret Manager tool](/aspnet/core/security/app-secrets#secret-manager), aka "User Secrets". - -For example, to use the User Secrets, first remove the connection string from your ASP.NET Core configuration file. Next, initialize User Secrets by executing the following command in the same directory as the ASP.NET Core project: - -```dotnetcli -dotnet user-secrets init -``` - -This command sets up storage on your computer separate from your source code and adds a key for this storage to the project. - -Next, store the connection string in user secrets. For example: - -```dotnetcli -dotnet user-secrets set ConnectionStrings:Chinook "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" -``` - -Now the same command that previous used the named connection string from the config file will instead use the connection string stored in User Secrets. For example: - -#### [.NET Core CLI](#tab/dotnet-core-cli) - -```dotnetcli -dotnet ef dbcontext scaffold "Name=ConnectionStrings:Chinook" Microsoft.EntityFrameworkCore.SqlServer -``` - -#### [Visual Studio PMC](#tab/vs) - -```powershell -Scaffold-DbContext 'Name=ConnectionStrings:Chinook' Microsoft.EntityFrameworkCore.SqlServer -``` - -*** +> [!TIP] +> You can [use Configuration to store and retrieve the connection string](xref:core/miscellaneous/connection-strings#aspnet-core) #### Connection strings in the scaffolded code diff --git a/entity-framework/core/miscellaneous/connection-strings.md b/entity-framework/core/miscellaneous/connection-strings.md index dc86fe21b7..37f6ffa289 100644 --- a/entity-framework/core/miscellaneous/connection-strings.md +++ b/entity-framework/core/miscellaneous/connection-strings.md @@ -20,6 +20,7 @@ The ASP.NET Core configuration can store connection strings with various provide * In the `appsettings.Development.json` or `appsettings.json` file. * In an environment variable +* Using [Azure Key Vault](/azure/key-vault/keys/quick-create-net) * Using the [Secret Manager tool](/aspnet/core/security/app-secrets#secret-manager) > [!WARNING] @@ -30,10 +31,26 @@ For example, the [Secret Manager tool](/aspnet/core/security/app-secrets#secret- See the [Configuration section of the ASP.NET Core documentation](/aspnet/core/fundamentals/configuration) for more information. ```dotnetcli +dotnet user-secrets init dotnet user-secrets set ConnectionStrings:YourDatabaseAlias "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=YourDatabase" +``` + +Then, in scaffolding, use a connection string that consists of `Name=`. + +### [.NET Core CLI](#tab/dotnet-core-cli) + +```dotnetcli dotnet ef dbcontext scaffold Name=ConnectionStrings:YourDatabaseAlias Microsoft.EntityFrameworkCore.SqlServer ``` +### [Visual Studio PMC](#tab/vs) + +```powershell +Scaffold-DbContext 'Name=ConnectionStrings:YourDatabaseAlias' Microsoft.EntityFrameworkCore.SqlServer +``` + +*** + [!INCLUDE [managed-identities-test-non-production](~/core/includes/managed-identities-test-non-production.md)] The following example shows the connection string stored in `appsettings.json`. diff --git a/entity-framework/core/performance/nativeaot-and-precompiled-queries.md b/entity-framework/core/performance/nativeaot-and-precompiled-queries.md index 1ec493d3ac..cbb36bdb51 100644 --- a/entity-framework/core/performance/nativeaot-and-precompiled-queries.md +++ b/entity-framework/core/performance/nativeaot-and-precompiled-queries.md @@ -38,10 +38,15 @@ C# interceptors are currently an experimental feature, and require a special opt ``` -Finally, the [`Microsoft.EntityFrameworkCore.Tasks`](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tasks) package contains MSBuild integration that will perform the query precompilation (and generate the required compiled model) when you publish your application: +Finally, the [`Microsoft.EntityFrameworkCore.Tasks`](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tasks) package contains [MSBuild integration](xref:core/cli/msbuild) that will perform the query precompilation (and generate the required compiled model) when you publish your application: ```xml - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + ``` You're now ready to publish your EF NativeAOT application: @@ -50,7 +55,7 @@ You're now ready to publish your EF NativeAOT application: dotnet publish -r linux-arm64 -c Release ``` -This shows publishing a NativeAOT publishing for Linux running on ARM64; [consult this catalog](/dotnet/core/rid-catalog) to find your runtime identifier. If you'd like to generate the interceptors without publishing - for example to examine the generated sources - you can do so via the `net ef dbcontext optimize --precompile-queries --nativeaot` command. +This shows publishing a NativeAOT publishing for Linux running on ARM64; [consult this catalog](/dotnet/core/rid-catalog) to find your runtime identifier. If you'd like to generate the interceptors without publishing - for example to examine the generated sources - you can do so via the `dotnet ef dbcontext optimize --precompile-queries --nativeaot` command. Due to the way C# interceptors work, any change in the application source invalidates them and requires repeating the above process. As a result, interceptor generation and actual publishing aren't expected to happen in the inner loop, as the developer is working on code; instead, both `dotnet ef dbcontext optimize` and `dotnet publish` can be executed in a publishing/deployment workflow, in a CI/CD system. 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 20174ae1e9..91fe0994b6 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 @@ -2,7 +2,7 @@ title: What's New in EF Core 9 description: Overview of new features in EF Core 9 author: ajcvickers -ms.date: 10/10/2024 +ms.date: 10/21/2024 uid: core/what-is-new/ef-core-9.0/whatsnew --- @@ -1166,38 +1166,21 @@ Notice that the model was not built when starting the application because the co ### 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: +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 an MSBuild task 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 +dotnet add package Microsoft.EntityFrameworkCore.Tasks --version 9.0.0 ``` > [!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: +Then enable the integration by setting the `EFOptimizeContext` and `EFScaffoldModelStage` properties in 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 + build ``` @@ -1211,7 +1194,7 @@ dotnet exec --depsfile D:\code\EntityFramework.Docs\samples\core\Miscellaneous\N --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 + --assembly D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model\bin\Release\net8.0\Model.dll --project-dir D:\code\EntityFramework.Docs\samples\core\Miscellaneous\NewInEFCore9.CompiledModels\Model --root-namespace NewInEfCore9 --language C# @@ -1231,8 +1214,7 @@ 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. +For more information see [MSBuild integration](xref:core/cli/msbuild). diff --git a/entity-framework/core/what-is-new/nuget-packages.md b/entity-framework/core/what-is-new/nuget-packages.md index a0b6e36de1..6baa883dc0 100644 --- a/entity-framework/core/what-is-new/nuget-packages.md +++ b/entity-framework/core/what-is-new/nuget-packages.md @@ -2,13 +2,13 @@ title: EF Core NuGet Packages description: Overview of the different Entity Framework Core NuGet packages author: ajcvickers -ms.date: 01/21/2021 +ms.date: 10/21/2024 uid: core/what-is-new/nuget-packages --- # EF Core NuGet Packages -Entity Framework Core (EF Core) is shipped as [NuGet](https://www.nuget.org/) packages. The packages needed by an application depends on: +Entity Framework Core (EF Core) is shipped as [NuGet](https://www.nuget.org/profiles/EntityFramework) packages. The packages needed by an application depends on: - The type of database system being used (SQL Server, SQLite, etc.) - The EF Core features needed @@ -53,8 +53,9 @@ Common database providers are listed in the table below. See [database providers Use of tooling for [EF Core migrations](xref:core/managing-schemas/migrations/index) and [reverse engineering (scaffolding) from an existing database](xref:core/managing-schemas/scaffolding) requires installation of the appropriate tooling package: +- [dotnet-ef](https://www.nuget.org/packages/dotnet-ef/) for cross-platform command line tooling +- [Microsoft.EntityFrameworkCore.Tasks](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tasks/) for MSBuild tasks allowing build-time integration. - [Microsoft.EntityFrameworkCore.Tools](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tools/) for PowerShell tooling that works in the Visual Studio [Package Manager Console](/nuget/consume-packages/install-use-packages-powershell) -- [dotnet-ef](https://www.nuget.org/packages/dotnet-ef/) and [Microsoft.EntityFrameworkCore.Design](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Design/) for cross-platform command line tooling See [Entity Framework Core Tools Reference](xref:core/cli/index) for more information on using EF Core tooling, including how to correctly install the `dotnet-ef` tool in a project or globally. @@ -84,6 +85,7 @@ Other EF Core packages are pulled in as dependencies of the database provider pa | Lightweight package for EF Core attributes, etc. | [Microsoft.EntityFrameworkCore.Abstractions](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Abstractions/) | Roslyn code analyzers for EF Core usage | [Microsoft.EntityFrameworkCore.Analyzers](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Analyzers/) | EF Core SQLite provider without a native SQLite dependency | [Microsoft.EntityFrameworkCore.Sqlite.Core](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite.Core/) +| Design-time functionality implementation shared by EF tools| [Microsoft.EntityFrameworkCore.Design](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Design/) ## Packages for database provider testing diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index 3ad60c0e7e..ea09ef563b 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -451,7 +451,7 @@ - name: Tools & extensions href: core/extensions/index.md - - name: Command-line reference + - name: Design-time tools reference items: - name: Overview href: core/cli/index.md @@ -459,6 +459,8 @@ href: core/cli/powershell.md - name: .NET Core CLI href: core/cli/dotnet.md + - name: MSBuild Tasks + href: core/cli/msbuild.md - name: Design-time DbContext creation href: core/cli/dbcontext-creation.md - name: Design-time services diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/ConfiguringDbContext.csproj b/samples/core/Miscellaneous/ConfiguringDbContext/ConfiguringDbContext.csproj index fb34b81e0b..5c4f6ce07a 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/ConfiguringDbContext.csproj +++ b/samples/core/Miscellaneous/ConfiguringDbContext/ConfiguringDbContext.csproj @@ -1,11 +1,15 @@ - + net8.0 + enable + + + diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Program.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Program.cs index e4fbbececf..3bad2b496f 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Program.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp/Program.cs @@ -1,8 +1,9 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; -using WebApp; -public class Program +namespace WebApp; + +public class Program { public static void Main(string[] args) { diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs index e6e96ef97c..d78296f09d 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs +++ b/samples/core/Miscellaneous/ConfiguringDbContext/WebApp9/Program9.cs @@ -1,3 +1,7 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using WebApp; + var builder = WebApplication.CreateBuilder(args); // var connectionString = @@ -28,13 +32,12 @@ } app.UseHttpsRedirection(); +app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); -app.MapStaticAssets(); -app.MapRazorPages() - .WithStaticAssets(); +app.MapRazorPages(); app.Run(); From 267ed2966b345a12db52adb498ef3d9bd9bd4683 Mon Sep 17 00:00:00 2001 From: dotnetdoktor Date: Wed, 13 Nov 2024 15:09:23 +0100 Subject: [PATCH 068/224] Fix: net ef dbcontext --> dotnet ef dbcontext (#4874) From d3b8614740b0af90520b03c9a27001abee9fe971 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 14 Nov 2024 02:02:10 +0100 Subject: [PATCH 069/224] Update what's new index page for EF 9 (#4876) Closes #4875 --- entity-framework/core/what-is-new/index.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/entity-framework/core/what-is-new/index.md b/entity-framework/core/what-is-new/index.md index 1230ee5b85..50e50384a6 100644 --- a/entity-framework/core/what-is-new/index.md +++ b/entity-framework/core/what-is-new/index.md @@ -2,7 +2,7 @@ title: EF Core releases and planning description: Current EF Core releases and schedule/planning details for future releases author: ajcvickers -ms.date: 11/9/2022 +ms.date: 11/13/2024 uid: core/what-is-new/index --- @@ -12,9 +12,10 @@ uid: core/what-is-new/index | Release | Target framework | Supported until | Links | |----------------------------------------------------------------------------------------|-------------------|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [EF Core 9.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) | .NET 8 | May 12, 2026 | [What's new](xref:core/what-is-new/ef-core-9.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-9.0/breaking-changes) | | [EF Core 8.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) | .NET 8 | November 10, 2026 | [What's new](xref:core/what-is-new/ef-core-8.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-8.0/breaking-changes) | | ~~[EF Core 7.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/7.0.0)~~ | .NET 6 | Expired May 14, 2024 | [What's new](xref:core/what-is-new/ef-core-7.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-7.0/breaking-changes) | -| [EF Core 6.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/6.0.0) | .NET 6 | November 12, 2024 (LTS) | [What's new](xref:core/what-is-new/ef-core-6.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-6.0/breaking-changes) | +| ~~[EF Core 6.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/6.0.0)~~ | .NET 6 | Expired November 12, 2024 | [What's new](xref:core/what-is-new/ef-core-6.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-6.0/breaking-changes) | | ~~[EF Core 5.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/5.0.17)~~ | .NET Standard 2.1 | Expired May 10, 2022 | [Announcement](https://devblogs.microsoft.com/dotnet/announcing-the-release-of-ef-core-5-0/) / [Breaking changes](xref:core/what-is-new/ef-core-5.0/breaking-changes) | | ~~[EF Core 3.1](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/3.1.31)~~ | .NET Standard 2.0 | Expired December 13, 2022 | [Announcement](https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-3-1-and-entity-framework-6-4/) | | ~~[EF Core 3.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/3.0.3)~~ | .NET Standard 2.1 | Expired March 3, 2020 | [Announcement](https://devblogs.microsoft.com/dotnet/announcing-ef-core-3-0-and-ef-6-3-general-availability/) / [Breaking changes](xref:core/what-is-new/ef-core-3.x/breaking-changes) | @@ -32,8 +33,8 @@ Entity Framework Core releases and support are aligned with .NET releases and su ## Guidance on updating to new releases -* Supported releases are patched for security and other critical bugs. Always use the latest patch of a given release. For example, for EF Core 2.1, use 2.1.x for the highest 'x' available. -* Major version updates (for example, from EF Core 2 to EF Core 3) often have breaking changes. Thorough testing is advised when updating across major versions. Use the breaking changes links above for guidance on dealing with breaking changes. +* Supported releases are patched for security and other critical bugs. Always use the latest patch of a given release. For example, for EF Core 9.0, use 9.0.x for the highest 'x' available. +* Major version updates (for example, from EF Core 8 to EF Core 9) often have breaking changes. Thorough testing is advised when updating across major versions. Use the breaking changes links above for guidance on dealing with breaking changes. * Minor version updates do not typically contain breaking changes. However, thorough testing is still advised since new features can introduce regressions. ## Release planning and schedules @@ -44,8 +45,6 @@ Patch releases usually ship monthly, but have a long lead time. See the [release planning process](xref:core/what-is-new/release-planning) for more information on how we decide what to ship in each release. We typically don't do detailed planning for further out than the next major or minor release. -## EF Core 9.0 +## EF Core 10.0 -The next planned stable release is **EF Core 9.0**, or just **EF9**, scheduled for **November 2024**. - -See the [What's New in EF9](xref:core/what-is-new/ef-core-9.0/whatsnew) for more information. +The next planned stable release is **EF Core 10.0**, or just **EF10**, scheduled for **November 2025**. From 0261e683b5ed0310269c83fe72a46899e11d63f7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 14 Nov 2024 21:23:12 +0100 Subject: [PATCH 070/224] Add HasData limitation note for DateTime.Now (#4878) Relates to https://github.com/dotnet/efcore/issues/35080#issuecomment-2473864073 --- entity-framework/core/modeling/data-seeding.md | 1 + 1 file changed, 1 insertion(+) diff --git a/entity-framework/core/modeling/data-seeding.md b/entity-framework/core/modeling/data-seeding.md index 4dba91863a..2d6fe7b2f5 100644 --- a/entity-framework/core/modeling/data-seeding.md +++ b/entity-framework/core/modeling/data-seeding.md @@ -107,6 +107,7 @@ If your scenario includes any of the following it is recommended to use `UseSeed * Data that needs key values to be generated by the database, including entities that use alternate keys as the identity * Data that requires custom transformation (that is not handled by [value conversions](xref:core/modeling/value-conversions)), such as some password hashing * Data that requires calls to external API, such as ASP.NET Core Identity roles and users creation +* Data that isn't fixed and deterministic, such as seeding to `DateTime.Now`. From 7cd56123924446e7e43da9a4dab7d83f62f51c4f Mon Sep 17 00:00:00 2001 From: Dave Callan <106764096+davepcallan@users.noreply.github.com> Date: Fri, 15 Nov 2024 13:57:26 +0000 Subject: [PATCH 071/224] Remove reference to .NET 9 'Preview' in the EF9 targeting sentence as .NET9 is now GA (#4880) Remove reference to .NET 9 'Preview' in the EF9 targeting sentence as .NET9 is now GA --- entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 91fe0994b6..2b09356c76 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 @@ -15,7 +15,7 @@ EF9 is available as [daily builds](https://github.com/dotnet/efcore/blob/main/do > [!TIP] > You can run and debug into the samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs). Each section below links to the source code specific to that section. -EF9 targets .NET 8, and can therefore be used with either [.NET 8 (LTS)](https://dotnet.microsoft.com/download/dotnet/8.0) or a [.NET 9 preview](https://dotnet.microsoft.com/download/dotnet/9.0). +EF9 targets .NET 8, and can therefore be used with either [.NET 8 (LTS)](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0). > [!TIP] > The _What's New_ docs are updated for each preview. All the samples are set up to use the [EF9 daily builds](https://github.com/dotnet/efcore/blob/main/docs/DailyBuilds.md), which usually have several additional weeks of completed work compared to the latest preview. We strongly encourage use of the daily builds when testing new features so that you're not doing your testing against stale bits. From 063088e4e056dce7644801862d0a3f6acd612682 Mon Sep 17 00:00:00 2001 From: Jon Galloway Date: Fri, 15 Nov 2024 11:29:45 -0800 Subject: [PATCH 072/224] Add missing closing perintheses (#4881) --- entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2b09356c76..a48c9bb0fc 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 @@ -1086,7 +1086,7 @@ The above were only some of the more important query improvements in EF9; see [t ### Protection against concurrent migrations -EF9 introduces a locking mechanism to protect against multiple migration executions happening simultaneously, as that could leave the database in a corrupted state. This doesn't happen when migrations are deployed to the production environment using [recommended methods](/ef/core/managing-schemas/migrations/applying#sql-scripts), but can happen if migrations are applied at runtime using the [`DbContext.Database.Migrate()`](/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.migrate) method. We recommend applying migrations at deployment, rather than as part of application startup, but that can result in more complicated application architectures (e.g. [when using .NET Aspire projects](/dotnet/aspire/database/ef-core-migrations). +EF9 introduces a locking mechanism to protect against multiple migration executions happening simultaneously, as that could leave the database in a corrupted state. This doesn't happen when migrations are deployed to the production environment using [recommended methods](/ef/core/managing-schemas/migrations/applying#sql-scripts), but can happen if migrations are applied at runtime using the [`DbContext.Database.Migrate()`](/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.migrate) method. We recommend applying migrations at deployment, rather than as part of application startup, but that can result in more complicated application architectures (e.g. [when using .NET Aspire projects](/dotnet/aspire/database/ef-core-migrations)). > [!NOTE] > If you are using Sqlite database, see [potential issues associated with this feature](/ef/core/providers/sqlite/limitations#concurrent-migrations-protection). From f0316db59267b971ab493920b9027c0cb4dae7a2 Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Sat, 16 Nov 2024 14:01:12 -0700 Subject: [PATCH 073/224] Bump some supported versions (#4882) The current Bricelam.EntityFrameworkCore.Pluralizer and EntityFrameworkCore.ConfigurationManager binaries continue to work in EF9 --- entity-framework/core/extensions/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index 7077b8b051..3e2847f85a 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -104,7 +104,7 @@ EF Core extensions for Bulk operations (Insert, Update, Delete). For EF Core: 2- ### Bricelam.EntityFrameworkCore.Pluralizer -Adds design-time pluralization. For EF Core: 2-8. +Adds design-time pluralization. For EF Core: 2-9. [GitHub repository](https://github.com/bricelam/EFCore.Pluralizer) | [NuGet](https://www.nuget.org/packages/Bricelam.EntityFrameworkCore.Pluralizer) @@ -204,7 +204,7 @@ An implementation for soft deleting entities. For EF Core: 3-6. ### EntityFrameworkCore.ConfigurationManager -Extends EF Core to resolve connection strings from App.config. For EF Core: 3-8. +Extends EF Core to resolve connection strings from App.config. For EF Core: 3-9. [GitHub repository](https://github.com/efcore/EFCore.ConfigurationManager) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.ConfigurationManager) From 2134b4444498dee8180d01829b1a30dd97c83cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Thu, 21 Nov 2024 09:49:00 +0100 Subject: [PATCH 074/224] Update standups. (#4884) --- .../core/learn-more/community-standups.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/entity-framework/core/learn-more/community-standups.md b/entity-framework/core/learn-more/community-standups.md index e28c9599e3..d7e0a4fbb0 100644 --- a/entity-framework/core/learn-more/community-standups.md +++ b/entity-framework/core/learn-more/community-standups.md @@ -16,6 +16,7 @@ The .NET Data Community Standups are live-streamed every other Wednesday to Twit | Date | Area | Title | |--------------|-----------------------|------------------------------------------------------------------------------------------| +| Nov 20, 2024 | Release | [EF Core 9: Release extravaganza](#Nov20_2024) | | Jun 26, 2024 | SQL schemas | [Improve your SQL schema and scripts with .NET based static code analysis](#June26_2024) | | May 15, 2024 | Firebird | [Harnessing the Power of Firebird in .NET](#May15_2024) | | Apr 17, 2024 | EF Core mapping | [All about EF Core property mapping](#Apr17_2024) | @@ -98,6 +99,19 @@ The .NET Data Community Standups are live-streamed every other Wednesday to Twit ## 2024 + + +### November 20: [EF Core 9: Release extravaganza](https://www.youtube.com/live/wG8D5HJMzjA?si=239r9dKJhBxilQ2e) + +EF Core 9 was just released. Join us in this special session talking with industry experts about all topic EF Core. + +Featuring: + +- [Erik Ejlskov Jensen](https://erikej.github.io) (Special guest) +- [Julie Lerman](https://thedatafarm.com/) (Special guest) +- [Jiri Cincura](https://github.com/cincuranet) (Host) +- [Shay Rojansky](https://github.com/roji) (Host) + ### June 26: [Improve your SQL schema and scripts with .NET based static code analysis](https://www.youtube.com/live/yIOFMHzaKGs?si=YuvPQNKpKomd0wue) From 6ccf94cccddf4bd3119a88605c18b232845f576e Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Thu, 21 Nov 2024 09:17:36 -0700 Subject: [PATCH 075/224] Point to latest API reference (#4885) --- entity-framework/toc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index ea09ef563b..4666b58e10 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -469,7 +469,7 @@ - name: Learn more items: - name: EF Core API reference >> - href: /dotnet/api/?view=efcore-7.0&preserve-view=true + href: /dotnet/api/?view=efcore-9.0&preserve-view=true - name: .NET Data Community Standups href: core/learn-more/community-standups.md From f257a9c519bea32704e3db326b61236c206b639c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Fri, 22 Nov 2024 12:40:37 +0100 Subject: [PATCH 076/224] Fix links, versions and some texts. (#4886) --- .../core/providers/sqlite/functions.md | 4 ++-- .../core/providers/sqlite/index.md | 2 +- .../core/providers/sqlite/limitations.md | 22 +++++++++---------- .../core/providers/sqlite/spatial.md | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/entity-framework/core/providers/sqlite/functions.md b/entity-framework/core/providers/sqlite/functions.md index 1105a25299..4a25714363 100644 --- a/entity-framework/core/providers/sqlite/functions.md +++ b/entity-framework/core/providers/sqlite/functions.md @@ -149,11 +149,11 @@ Math.Truncate(d) | trunc(@d) | EF Co > [!TIP] > In addition to the methods listed here, corresponding [generic math](/dotnet/standard/generics/math) implementations -> and [MathF](/dotnet/api/system.mathf) methods are also translated. For example, `Math.Sin`, `MathF.Sin`, `double.Sin`, +> and methods are also translated. For example, `Math.Sin`, `MathF.Sin`, `double.Sin`, > and `float.Sin` all map to the `sin` function in SQL. > [!TIP] -> SQL functions prefixed with *ef* are created by EF Core. +> SQL functions prefixed with `ef_` are created by EF Core. ## String functions diff --git a/entity-framework/core/providers/sqlite/index.md b/entity-framework/core/providers/sqlite/index.md index 7ff625161f..0d30b325b3 100644 --- a/entity-framework/core/providers/sqlite/index.md +++ b/entity-framework/core/providers/sqlite/index.md @@ -29,7 +29,7 @@ Install-Package Microsoft.EntityFrameworkCore.Sqlite ## Supported Database Engines -* SQLite (3.7 onwards) +* SQLite (3.46.1 onwards) ## Limitations diff --git a/entity-framework/core/providers/sqlite/limitations.md b/entity-framework/core/providers/sqlite/limitations.md index b345fba441..6107b6fce7 100644 --- a/entity-framework/core/providers/sqlite/limitations.md +++ b/entity-framework/core/providers/sqlite/limitations.md @@ -11,7 +11,7 @@ The SQLite provider has a number of migrations limitations. Most of these limita ## Modeling limitations -The common relational library (shared by Entity Framework relational database providers) defines APIs for modelling concepts that are common to most relational database engines. A couple of these concepts are not supported by the SQLite provider. +The common relational library (shared by EF Core relational database providers) defines APIs for modelling concepts that are common to most relational database engines. A couple of these concepts are not supported by the SQLite provider. * Schemas * Sequences @@ -21,14 +21,14 @@ The common relational library (shared by Entity Framework relational database pr SQLite doesn't natively support the following data types. EF Core can read and write values of these types, and querying for equality (`where e.Property == value`) is also supported. Other operations, however, like comparison and ordering will require evaluation on the client. -* DateTimeOffset -* Decimal -* TimeSpan -* UInt64 +* `DateTimeOffset` +* `decimal` +* `TimeSpan` +* `ulong` -Instead of `DateTimeOffset`, we recommend using DateTime values. When handling multiple time zones, we recommend converting the values to UTC before saving and then converting back to the appropriate time zone. +Instead of `DateTimeOffset`, we recommend using `DateTime` values. When handling multiple time zones, we recommend converting the values to UTC before saving and then converting back to the appropriate time zone. -The `Decimal` type provides a high level of precision. If you don't need that level of precision, however, we recommend using double instead. You can use a [value converter](xref:core/modeling/value-conversions) to continue using decimal in your classes. +The `decimal` type provides a high level of precision. If you don't need that level of precision, however, we recommend using `double` instead. You can use a [value converter](xref:core/modeling/value-conversions) to continue using `decimal` in your classes. ```csharp modelBuilder.Entity() @@ -40,7 +40,7 @@ modelBuilder.Entity() The SQLite database engine does not support a number of schema operations that are supported by the majority of other relational databases. If you attempt to apply one of the unsupported operations to a SQLite database then a `NotSupportedException` will be thrown. -A rebuild will be attempted in order to perform certain operations. Rebuilds are only possible for database artifacts that are part of your EF Core model. If a database artifact isn't part of the model--for example, if it was created manually inside a migration--then a `NotSupportedException` is still thrown. +A rebuild will be attempted in order to perform certain operations. Rebuilds are only possible for database artifacts that are part of your EF Core model. If a database artifact isn't part of the model - for example, if it was created manually inside a migration - then a `NotSupportedException` is still thrown. Operation | Supported? ---------------------|:---------- @@ -70,7 +70,7 @@ Delete | ✔ ### Migrations limitations workaround -You can workaround some of these limitations by manually writing code in your migrations to perform a rebuild. Table rebuilds involve creating a new table, copying data to the new table, dropping the old table, renaming the new table. You will need to use the `Sql(string)` method to perform some of these steps. +You can workaround some of these limitations by manually writing code in your migrations to perform a rebuild. Table rebuilds involve creating a new table, copying data to the new table, dropping the old table, renaming the new table. You will need to use the method to perform some of these steps. See [Making Other Kinds Of Table Schema Changes](https://sqlite.org/lang_altertable.html#otheralter) in the SQLite documentation for more details. @@ -92,9 +92,9 @@ dotnet ef database update --connection "Data Source=My.db" ## Concurrent migrations protection -EF9 introduced a locking mechanism when executing migrations. It aims to protect against multiple migration executions happening simultaneously, as that could leave the database in a corrupted state. This is one of the potential problems resulting from applying migrations at runtime using the [`DbContext.Database.Migrate()`](/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.migrate) method (see [Applying migrations](xref:core/managing-schemas/migrations/applying) for more information). To mitigate this, EF creates an exclusive lock on the database before any migration operations are applied. +EF9 introduced a locking mechanism when executing migrations. It aims to protect against multiple migration executions happening simultaneously, as that could leave the database in a corrupted state. This is one of the potential problems resulting from applying migrations at runtime using the method (see [Applying migrations](xref:core/managing-schemas/migrations/applying) for more information). To mitigate this, EF creates an exclusive lock on the database before any migration operations are applied. -Unfortunately, SQLite does not have built-in locking mechanism, so EF creates a separate table (`__EFMigrationsLock`) and uses it for locking. The lock is released when the migration completes and the seeding code finishes execution. However, if for some reason migration fails in a non-recoverable way, the lock may not be released correctly. If this happens, consecutive migrations will be blocked from executing SQL and therefore never complete. You can manually unblock them by deleting the `__EFMigrationsLock` table in the database. +Unfortunately, SQLite does not have built-in locking mechanism, so EF Core creates a separate table (`__EFMigrationsLock`) and uses it for locking. The lock is released when the migration completes and the seeding code finishes execution. However, if for some reason migration fails in a non-recoverable way, the lock may not be released correctly. If this happens, consecutive migrations will be blocked from executing SQL and therefore never complete. You can manually unblock them by deleting the `__EFMigrationsLock` table in the database. ## See also diff --git a/entity-framework/core/providers/sqlite/spatial.md b/entity-framework/core/providers/sqlite/spatial.md index 0ff653f48a..87d78dc263 100644 --- a/entity-framework/core/providers/sqlite/spatial.md +++ b/entity-framework/core/providers/sqlite/spatial.md @@ -11,7 +11,7 @@ This page includes additional information about using spatial data with the SQLi ## Installing SpatiaLite -On Windows, the native mod_spatialite library is distributed as a NuGet package dependency. Other platforms need to install it separately. This is typically done using a software package manager. For example, you can use APT on Debian and Ubuntu; and Homebrew on MacOS. +On Windows, the native `mod_spatialite` library is distributed as a [NuGet package](https://www.nuget.org/packages/mod_spatialite) dependency. Other platforms need to install it separately. This is typically done using a software package manager. For example, you can use APT on Debian and Ubuntu; and Homebrew on MacOS. ```bash # Debian/Ubuntu @@ -139,4 +139,4 @@ EnvelopeCombiner.CombineAsGeometry(group.Select(x => x.Property)) | Extent(Prope ## Additional resources * [SpatiaLite Homepage](https://www.gaia-gis.it/fossil/libspatialite) -* [NetTopologySuite Docs](https://nettopologysuite.github.io/NetTopologySuite/) +* [NetTopologySuite API Documentation](https://nettopologysuite.github.io/NetTopologySuite/api/NetTopologySuite.html) From e578fcfa3e7d0f34d11ec9ecae865a4a4a7f7efc Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Mon, 25 Nov 2024 12:49:48 +0100 Subject: [PATCH 077/224] Update some extensions for EF Core 9 (#4889) --- entity-framework/core/extensions/index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index 3e2847f85a..715847f1f4 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -17,13 +17,13 @@ These tools and extensions provide additional functionality for Entity Framework ### EF Core Power Tools -EF Core Power Tools is a Visual Studio extension that exposes various EF Core design-time tasks in a simple user interface. It includes reverse engineering of DbContext and entity classes from existing databases and [SQL Server DACPACs](/sql/relational-databases/data-tier-applications/data-tier-applications), management of database migrations, and model visualizations. For EF Core: 6-8. +EF Core Power Tools is a Visual Studio extension that exposes various EF Core design-time tasks in a simple user interface. It includes reverse engineering of DbContext and entity classes from existing databases and [SQL Server DACPACs](/sql/relational-databases/data-tier-applications/data-tier-applications), and model visualizations and diagrams. For EF Core: 6-9. [GitHub wiki](https://github.com/ErikEJ/EFCorePowerTools/wiki) ### EF Core Power Tools CLI -EF Core Power Tools CLI is a .NET global command line tool. It enables advanced reverse engineering of DbContext and entity classes from existing databases and [SQL Server DACPACs](/sql/relational-databases/data-tier-applications/data-tier-applications). For EF Core: 6-8. +EF Core Power Tools CLI is a .NET global command line tool. It enables advanced reverse engineering of DbContext and entity classes from existing databases and [SQL Server DACPACs](/sql/relational-databases/data-tier-applications/data-tier-applications). For EF Core: 6-9. [NuGet](https://www.nuget.org/packages/ErikEJ.EFCorePowerTools.Cli/#readme-body-tab) @@ -169,13 +169,13 @@ This will automatically make all your table and column names have snake_case, al ### EFCore.CheckConstraints -This plugin allows you to opt into some check constraints - just activate it and they'll automatically get created for you. For EF Core: 5-8. +This plugin allows you to opt into some check constraints - just activate it and they'll automatically get created for you. For EF Core: 5-9. [GitHub repository](https://github.com/efcore/EFCore.CheckConstraints) | [NuGet](https://www.nuget.org/packages/EFCore.CheckConstraints) ### SimplerSoftware.EntityFrameworkCore.SqlServer.NodaTime -Adds native support to EntityFrameworkCore for SQL Server for the NodaTime types. For EF Core: 3-8. +Adds native support to EntityFrameworkCore for SQL Server for the NodaTime types. For EF Core: 3-9. [GitHub repository](https://github.com/StevenRasmussen/EFCore.SqlServer.NodaTime) | [NuGet](https://www.nuget.org/packages/SimplerSoftware.EntityFrameworkCore.SqlServer.NodaTime) @@ -222,13 +222,13 @@ Adds support for [NodaTime](https://nodatime.org) types when using [SQLite](http ### ErikEJ.EntityFrameworkCore.SqlServer.Dacpac -Enables reverse engineering an EF Core model from a SQL Server data-tier application package (.dacpac). For EF Core: 6-8. +Enables reverse engineering an EF Core model from a SQL Server data-tier application package (.dacpac). For EF Core: 6-9. [GitHub repository](https://github.com/ErikEJ/EFCorePowerTools/tree/master/src/GUI/ErikEJ.EntityFrameworkCore.SqlServer.Dacpac) | [NuGet](https://www.nuget.org/packages/ErikEJ.EntityFrameworkCore.SqlServer.Dacpac) ### ErikEJ.EntityFrameworkCore.DgmlBuilder -Generate DGML (Graph) content that visualizes your DbContext. Adds the AsDgml() extension method to the DbContext class. For EF Core: 6-7. +Generate DGML (Graph) content that visualizes your DbContext. Adds the AsDgml() extension method to the DbContext class. For EF Core: 6-9. [GitHub repository](https://github.com/ErikEJ/EFCorePowerTools/tree/master/src/GUI/ErikEJ.EntityFrameworkCore.DgmlBuilder) | [NuGet](https://www.nuget.org/packages/ErikEJ.EntityFrameworkCore.DgmlBuilder) From 579baa90c51959a55e7f60544cc4af8a96b5d216 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sat, 30 Nov 2024 10:50:45 +0100 Subject: [PATCH 078/224] 8.0 breaking change note on parameterized collection perf regression (#4887) See https://github.com/dotnet/efcore/issues/32394#issuecomment-2493417868 --- .../ef-core-8.0/breaking-changes.md | 105 ++++++++++++++++-- 1 file changed, 93 insertions(+), 12 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-8.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-8.0/breaking-changes.md index f5fac2ae13..844ebf1b2e 100644 --- a/entity-framework/core/what-is-new/ef-core-8.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-8.0/breaking-changes.md @@ -22,6 +22,7 @@ EF Core 8 targets .NET 8. Applications targeting older .NET, .NET Core, and .NET | **Breaking change** | **Impact** | |:--------------------------------------------------------------------------------------------------------------|------------| | [`Contains` in LINQ queries may stop working on older SQL Server versions](#sqlserver-contains-compatibility) | High | +| [Possible query performance regressions around `Contains` in LINQ queries](#contains-perf-regression) | High | | [Enums in JSON are stored as ints instead of strings by default](#enums-as-ints) | High | | [SQL Server `date` and `time` now scaffold to .NET `DateOnly` and `TimeOnly`](#sqlserver-date-time-only) | Medium | | [Boolean columns with a database generated value are no longer scaffolded as nullable](#scaffold-bools) | Medium | @@ -47,17 +48,79 @@ EF Core 8 targets .NET 8. Applications targeting older .NET, .NET Core, and .NET #### Old behavior -Previously, when the `Contains` operator was used in LINQ queries with a parameterized value list, EF generated SQL that was inefficient but worked on all SQL Server versions. +EF had specialized support for LINQ queries using `Contains` operator over a parameterized value list: + +```c# +var names = new[] { "Blog1", "Blog2" }; + +var blogs = await context.Blogs + .Where(b => names.Contains(b.Name)) + .ToArrayAsync(); +``` + +Before EF Core 8.0, EF inserted the parameterized values as constants into the SQL: + +```sql +SELECT [b].[Id], [b].[Name] +FROM [Blogs] AS [b] +WHERE [b].[Name] IN (N'Blog1', N'Blog2') +``` #### New behavior -Starting with EF Core 8.0, EF now generates SQL that is more efficient, but is unsupported on SQL Server 2014 and below. +Starting with EF Core 8.0, EF now generates SQL that is more efficient in many cases, but is unsupported on SQL Server 2014 and below: + +```sql +SELECT [b].[Id], [b].[Name] +FROM [Blogs] AS [b] +WHERE [b].[Name] IN ( + SELECT [n].[value] + FROM OPENJSON(@__names_0) WITH ([value] nvarchar(max) '$') AS [n] +) +``` Note that newer SQL Server versions may be configured with an older [compatibility level](/sql/t-sql/statements/alter-database-transact-sql-compatibility-level), also making them incompatible with the new SQL. This can also occur with an Azure SQL database which was migrated from a previous on-premises SQL Server instance, carrying over the old compatibility level. #### Why -The previous SQL generated by EF Core for `Contains` inserted the parameterized values as constants in the SQL. For example, the following LINQ query: +The insertion of constant values into the SQL creates many performance problems, defeating query plan caching and causing unneeded evictions of other queries. The new EF Core 8.0 translation uses the SQL Server [`OPENJSON`](/sql/t-sql/functions/openjson-transact-sql) function to instead transfer the values as a JSON array. This solves the performance issues inherent in the previous technique; however, the `OPENJSON` function is unavailable in SQL Server 2014 and below. + +For more information about this change, [see this blog post](https://devblogs.microsoft.com/dotnet/announcing-ef8-preview-4/). + +#### Mitigations + +If your database is SQL Server 2016 (13.x) or newer, or if you're using Azure SQL, check the configured compatibility level of your database via the following command: + +```sql +SELECT name, compatibility_level FROM sys.databases; +``` + +If the compatibility level is below 130 (SQL Server 2016), consider modifying it to a newer value ([documentation](/sql/t-sql/statements/alter-database-transact-sql-compatibility-level#best-practices-for-upgrading-database-compatibility-leve)). + +Otherwise, if your database version really is older than SQL Server 2016, or is set to an old compatibility level which you cannot change for some reason, you can configure EF to revert to the older, pre-8.0 SQL. If you're using EF 9, you can use the newly-introduced : + +```c# +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseSqlServer("", o => o.TranslateParameterizedCollectionsToConstants()) +``` + +If you're using EF 8, you can achieve the same effect when using SQL Server by configuring EF's SQL compatibility level: + +```c# +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder + .UseSqlServer(@"", o => o.UseCompatibilityLevel(120)); +``` + + + +### Possible query performance regressions around `Contains` in LINQ queries + +[Tracking Issue #32394](https://github.com/dotnet/efcore/issues/32394) + +#### Old behavior + +EF had specialized support for LINQ queries using `Contains` operator over a parameterized value list: ```c# var names = new[] { "Blog1", "Blog2" }; @@ -67,7 +130,7 @@ var blogs = await context.Blogs .ToArrayAsync(); ``` -... would be translated to the following SQL: +Before EF Core 8.0, EF inserted the parameterized values as constants into the SQL: ```sql SELECT [b].[Id], [b].[Name] @@ -75,21 +138,31 @@ FROM [Blogs] AS [b] WHERE [b].[Name] IN (N'Blog1', N'Blog2') ``` -Such insertion of constant values into the SQL creates many performance problems, defeating query plan caching and causing unneeded evictions of other queries. The new EF Core 8.0 translation uses the SQL Server [`OPENJSON`](/sql/t-sql/functions/openjson-transact-sql) function to instead transfer the values as a JSON array. This solves the performance issues inherent in the previous technique; however, the `OPENJSON` function is unavailable in SQL Server 2014 and below. +#### New behavior -For more information about this change, [see this blog post](https://devblogs.microsoft.com/dotnet/announcing-ef8-preview-4/). +Starting with EF Core 8.0, EF now generates the following: + +```sql +SELECT [b].[Id], [b].[Name] +FROM [Blogs] AS [b] +WHERE [b].[Name] IN ( + SELECT [n].[value] + FROM OPENJSON(@__names_0) WITH ([value] nvarchar(max) '$') AS [n] +) +``` + +However, after the release of EF 8 it turned out that while the new SQL is more efficient for most cases, it can be dramatically less efficient in a minority of cases, even causing query timeouts in some cases #### Mitigations -If your database is SQL Server 2016 (13.x) or newer, or if you're using Azure SQL, check the configured compatibility level of your database via the following command: +If you're using EF 9, you can use the newly-introduced to revert the `Contains` translation for all queries back to the pre-8.0 behavior: -```sql -SELECT name, compatibility_level FROM sys.databases; +```c# +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseSqlServer("", o => o.TranslateParameterizedCollectionsToConstants()) ``` -If the compatibility level is below 130 (SQL Server 2016), consider modifying it to a newer value ([documentation](/sql/t-sql/statements/alter-database-transact-sql-compatibility-level#best-practices-for-upgrading-database-compatibility-leve)). - -Otherwise, if your database version really is older than SQL Server 2016, or is set to an old compatibility level which you cannot change for some reason, configure EF Core to revert to the older, less efficient SQL as follows: +If you're using EF 8, you can achieve the same effect when using SQL Server by configuring EF's SQL compatibility level: ```c# protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) @@ -97,6 +170,14 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) .UseSqlServer(@"", o => o.UseCompatibilityLevel(120)); ``` +Finally, you can control the translation on a query-by-query basis using as follows: + +```c# +var blogs = await context.Blogs + .Where(b => EF.Constant(names).Contains(b.Name)) + .ToArrayAsync(); +``` + ### Enums in JSON are stored as ints instead of strings by default From 33179dff18df83b8ac2437c47e82b1243c99ddba Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sat, 30 Nov 2024 14:00:35 +0100 Subject: [PATCH 079/224] Stop using escape sequences in xref (#4888) %2A -> * %60 -> ` --- .../core/change-tracking/change-detection.md | 24 +++---- .../core/change-tracking/debug-views.md | 2 +- .../core/change-tracking/entity-entries.md | 70 +++++++++---------- .../core/change-tracking/explicit-tracking.md | 22 +++--- .../change-tracking/identity-resolution.md | 10 +-- .../core/change-tracking/index.md | 12 ++-- .../core/change-tracking/miscellaneous.md | 30 ++++---- .../change-tracking/relationship-changes.md | 6 +- .../core/cli/dbcontext-creation.md | 4 +- .../core/dbcontext-configuration/index.md | 28 ++++---- .../core/logging-events-diagnostics/events.md | 6 +- .../extensions-logging.md | 8 +-- .../core/logging-events-diagnostics/index.md | 2 +- .../interceptors.md | 16 ++--- .../simple-logging.md | 16 ++--- .../core/managing-schemas/ensure-created.md | 2 +- entity-framework/core/miscellaneous/async.md | 6 +- .../core/modeling/bulk-configuration.md | 14 ++-- .../core/modeling/entity-types.md | 2 +- .../core/modeling/generated-properties.md | 4 +- entity-framework/core/modeling/index.md | 8 +-- .../core/modeling/keyless-entity-types.md | 2 +- .../modeling/relationships/navigations.md | 8 +-- .../core/modeling/shadow-properties.md | 2 +- .../core/modeling/value-comparers.md | 12 ++-- .../core/modeling/value-conversions.md | 44 ++++++------ .../advanced-performance-topics.md | 8 +-- .../core/performance/efficient-querying.md | 12 ++-- .../core/performance/efficient-updating.md | 2 +- .../core/providers/cosmos/modeling.md | 18 ++--- .../core/providers/cosmos/querying.md | 4 +- .../core/querying/database-functions.md | 2 +- entity-framework/core/querying/filters.md | 2 +- entity-framework/core/querying/sql-queries.md | 30 ++++---- entity-framework/core/querying/tracking.md | 4 +- entity-framework/core/saving/basic.md | 6 +- .../core/saving/cascade-delete.md | 6 +- .../saving/execute-insert-update-delete.md | 8 +-- entity-framework/core/saving/index.md | 10 +-- .../testing/choosing-a-testing-strategy.md | 2 +- .../core/testing/testing-with-the-database.md | 2 +- .../testing/testing-without-the-database.md | 2 +- .../core/what-is-new/ef-core-5.0/whatsnew.md | 14 ++-- .../ef-core-6.0/breaking-changes.md | 40 +++++------ .../core/what-is-new/ef-core-6.0/whatsnew.md | 18 ++--- .../ef-core-7.0/breaking-changes.md | 2 +- .../core/what-is-new/ef-core-7.0/whatsnew.md | 32 ++++----- .../ef-core-8.0/breaking-changes.md | 6 +- .../core/what-is-new/ef-core-8.0/whatsnew.md | 12 ++-- .../ef-core-9.0/breaking-changes.md | 8 +-- .../core/what-is-new/ef-core-9.0/whatsnew.md | 4 +- 51 files changed, 307 insertions(+), 307 deletions(-) diff --git a/entity-framework/core/change-tracking/change-detection.md b/entity-framework/core/change-tracking/change-detection.md index 6f9e64f679..7404a6e28a 100644 --- a/entity-framework/core/change-tracking/change-detection.md +++ b/entity-framework/core/change-tracking/change-detection.md @@ -8,7 +8,7 @@ uid: core/change-tracking/change-detection # Change Detection and Notifications -Each instance tracks changes made to entities. These tracked entities in turn drive the changes to the database when is called. This is covered in [Change Tracking in EF Core](xref:core/change-tracking/index), and this document assumes that entity states and the basics of Entity Framework Core (EF Core) change tracking are understood. +Each instance tracks changes made to entities. These tracked entities in turn drive the changes to the database when is called. This is covered in [Change Tracking in EF Core](xref:core/change-tracking/index), and this document assumes that entity states and the basics of Entity Framework Core (EF Core) change tracking are understood. Tracking property and relationship changes requires that the DbContext is able to detect these changes. This document covers how this detection happens, as well as how to use property notifications or change-tracking proxies to force immediate detection of changes. @@ -121,7 +121,7 @@ Contrast this to the following code which modifies the entities in the same way, --> [!code-csharp[Snapshot_change_tracking_2](../../../samples/core/ChangeTracking/ChangeDetectionAndNotifications/SnapshotSamples.cs?name=Snapshot_change_tracking_2)] -In this case the change tracker debug view shows that all entity states and property modifications are known, even though detection of changes has not happened. This is because is an EF Core method, which means that EF Core immediately knows about the change made by this method. Likewise, calling allows EF Core to immediately know about the new entity and track it appropriately. +In this case the change tracker debug view shows that all entity states and property modifications are known, even though detection of changes has not happened. This is because is an EF Core method, which means that EF Core immediately knows about the change made by this method. Likewise, calling allows EF Core to immediately know about the new entity and track it appropriately. > [!TIP] > Don't attempt to avoid detecting changes by always using EF Core methods to make entity changes. Doing so is often more cumbersome and performs less well than making changes to entities in the normal way. The intention of this document is to inform as to when detecting changes is needed and when it is not. The intention is not to encourage avoidance of change detection. @@ -130,15 +130,15 @@ In this case the change tracker debug view shows that all entity states and prop is called automatically by methods where doing so is likely to impact the results. These methods are: -- and , to ensure that all changes are detected before updating the database. -- and , to ensure entity states and modified properties are up-to-date. +- and , to ensure that all changes are detected before updating the database. +- and , to ensure entity states and modified properties are up-to-date. - , to ensure that the result is accurate. - , to ensure correct entity states for principal/parent entities before cascading. -- , to ensure that the tracked graph is up-to-date. +- , to ensure that the tracked graph is up-to-date. There are also some places where detection of changes happens on only a single entity instance, rather than on the entire graph of tracked entities. These places are: -- When using , to ensure that the entity's state and modified properties are up-to-date. +- When using , to ensure that the entity's state and modified properties are up-to-date. - When using methods such as `Property`, `Collection`, `Reference` or `Member` to ensure property modifications, current values, etc. are up-to-date. - When a dependent/child entity is going to be deleted because a required relationship has been severed. This detects when an entity should not be deleted because it has been re-parented. @@ -176,7 +176,7 @@ The performance of detecting changes is not a bottleneck for most applications. --> [!code-csharp[SaveChanges](../../../samples/core/ChangeTracking/ChangeDetectionAndNotifications/SnapshotSamples.cs?name=SaveChanges)] -As we know from the previous section, both and automatically detect changes. However, after calling Entries, the code does not then make any entity or property state changes. (Setting normal property values on Added entities does not cause any state changes.) The code therefore disables unnecessary automatic change detection when calling down into the base SaveChanges method. The code also makes use of a try/finally block to ensure that the default setting is restored even if SaveChanges fails. +As we know from the previous section, both and automatically detect changes. However, after calling Entries, the code does not then make any entity or property state changes. (Setting normal property values on Added entities does not cause any state changes.) The code therefore disables unnecessary automatic change detection when calling down into the base SaveChanges method. The code also makes use of a try/finally block to ensure that the default setting is restored even if SaveChanges fails. > [!TIP] > Do not assume that your code must disable automatic change detection to perform well. This is only needed when profiling an application tracking many entities indicates that performance of change detection is an issue. @@ -234,7 +234,7 @@ Notification entities make use of the [!code-csharp[Model](../../../samples/core/ChangeTracking/ChangeDetectionAndNotifications/NotificationEntitiesSamples.cs?name=Model)] -In addition, any collection navigations must implement `INotifyCollectionChanged`; in the example above this is satisfied by using an of posts. EF Core also ships with an implementation that has more efficient lookups at the expense of stable ordering. +In addition, any collection navigations must implement `INotifyCollectionChanged`; in the example above this is satisfied by using an of posts. EF Core also ships with an implementation that has more efficient lookups at the expense of stable ordering. Most of this notification code is typically moved into an unmapped base class. For example: @@ -283,7 +283,7 @@ Most of this notification code is typically moved into an unmapped base class. F There is no way for EF Core to validate that `INotifyPropertyChanging` or `INotifyPropertyChanged` are fully implemented for use with EF Core. In particular, some uses of these interfaces do so with notifications only on certain properties, rather than on all properties (including navigations) as required by EF Core. For this reason, EF Core does not automatically hook into these events. -Instead, EF Core must be configured to use these notification entities. This is usually done for all entity types by calling . For example: +Instead, EF Core must be configured to use these notification entities. This is usually done for all entity types by calling . For example: [!code-csharp[OnModelCreating](../../../samples/core/ChangeTracking/ChangeDetectionAndNotifications/NotificationWithBaseSamples.cs?name=OnModelCreating)] -(The strategy can also be set differently for different entity types using , but this is usually counterproductive since DetectChanges is still required for those types that are not notification entities.) +(The strategy can also be set differently for different entity types using , but this is usually counterproductive since DetectChanges is still required for those types that are not notification entities.) Full notification change tracking requires that both `INotifyPropertyChanging` and `INotifyPropertyChanged` are implemented. This allows original values to be saved just before the property value is changed, avoiding the need for EF Core to create a snapshot when tracking the entity. Entity types that implement only `INotifyPropertyChanged` can also be used with EF Core. In this case, EF still creates a snapshot when tracking an entity to keep track of original values, but then uses the notifications to detect changes immediately, rather than needing DetectChanges to be called. @@ -357,7 +357,7 @@ Post {Id: 2} Unchanged ## Change-tracking proxies -EF Core can dynamically generate proxy types that implement and . This requires installing the [Microsoft.EntityFrameworkCore.Proxies](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Proxies/) NuGet package, and enabling change-tracking proxies with For example: +EF Core can dynamically generate proxy types that implement and . This requires installing the [Microsoft.EntityFrameworkCore.Proxies](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Proxies/) NuGet package, and enabling change-tracking proxies with For example: [!code-csharp[Work_with_a_single_property_1b](../../../samples/core/ChangeTracking/AccessingTrackedEntities/Samples.cs?name=Work_with_a_single_property_1b)] -The returned can then be used to access information about the property. For example, it can be used to get and set the current value of the property on this entity: +The returned can then be used to access information about the property. For example, it can be used to get and set the current value of the property on this entity: [!code-csharp[Work_with_a_single_property_1d](../../../samples/core/ChangeTracking/AccessingTrackedEntities/Samples.cs?name=Work_with_a_single_property_1d)] -Both of the Property methods used above return a strongly-typed generic instance. Using this generic type is preferred because it allows access to property values without [boxing value types](/dotnet/csharp/programming-guide/types/boxing-and-unboxing). However, if the type of entity or property is not known at compile-time, then a non-generic can be obtained instead: +Both of the Property methods used above return a strongly-typed generic instance. Using this generic type is preferred because it allows access to property values without [boxing value types](/dotnet/csharp/programming-guide/types/boxing-and-unboxing). However, if the type of entity or property is not known at compile-time, then a non-generic can be obtained instead: [!code-csharp[Work_with_a_single_navigation_1](../../../samples/core/ChangeTracking/AccessingTrackedEntities/Samples.cs?name=Work_with_a_single_navigation_1)] -Navigations can also be collections of related entities when used for the "many" sides of one-to-many and many-to-many relationships. The methods are used to access collection navigations. For example: +Navigations can also be collections of related entities when used for the "many" sides of one-to-many and many-to-many relationships. The methods are used to access collection navigations. For example: [!code-csharp[Work_with_a_single_navigation_2a](../../../samples/core/ChangeTracking/AccessingTrackedEntities/Samples.cs?name=Work_with_a_single_navigation_2a)] -Some operations are common for all navigations. These can be accessed for both reference and collection navigations using the method. Note that only non-generic access is available when accessing all navigations together. For example: +Some operations are common for all navigations. These can be accessed for both reference and collection navigations using the method. Note that only non-generic access is available when accessing all navigations together. For example: [!code-csharp[Work_with_a_single_navigation_2b](../../../samples/core/ChangeTracking/AccessingTrackedEntities/Samples.cs?name=Work_with_a_single_navigation_2b)] -The following table summarizes ways to use , , and : +The following table summarizes ways to use , , and : | NavigationEntry member | Description |:----------------------------------------------------------------------------------------------------------|---------------------- @@ -185,7 +185,7 @@ The following table summarizes ways to use returns an of for every property of the entity. This can be used to perform an action for every property of the entity. For example, to set any DateTime property to `DateTime.Now`: + returns an of for every property of the entity. This can be used to perform an action for every property of the entity. For example, to set any DateTime property to `DateTime.Now`: [!code-csharp[BlogDto](../../../samples/core/ChangeTracking/AccessingTrackedEntities/Samples.cs?name=BlogDto)] -This can be used to set the current values of a tracked entity using : +This can be used to set the current values of a tracked entity using : [!code-csharp[OrderLine](../../../samples/core/ChangeTracking/AccessingTrackedEntities/Samples.cs?name=OrderLine)] -The composite key must be configured in to define the key parts _and their order_. For example: +The composite key must be configured in to define the key parts _and their order_. For example: [!code-csharp[Using_DbSet_Local_to_query_tracked_entities_1](../../../samples/core/ChangeTracking/AccessingTrackedEntities/Samples.cs?name=Using_DbSet_Local_to_query_tracked_entities_1)] -Notice that, unlike , `DbSet.Local` returns entity instances directly. An EntityEntry can, of course, always be obtained for the returned entity by calling . +Notice that, unlike , `DbSet.Local` returns entity instances directly. An EntityEntry can, of course, always be obtained for the returned entity by calling . ### The local view - returns a view of locally tracked entities that reflects the current of those entities. Specifically, this means that: + returns a view of locally tracked entities that reflects the current of those entities. Specifically, this means that: - `Added` entities are included. Note that this is not the case for normal EF Core queries, since `Added` entities do not yet exist in the database and so are therefore never returned by a database query. - `Deleted` entities are excluded. Note that this is again not the case for normal EF Core queries, since `Deleted` entities still exist in the database and so _are_ returned by database queries. @@ -534,7 +534,7 @@ Notice that the deleted post is removed from the local view, and the added post ### Using Local to add and remove entities - returns an instance of . This is an implementation of that generates and responds to notifications when entities are added and removed from the collection. (This is the same concept as , but implemented as a projection over existing EF Core change tracking entries, rather than as an independent collection.) + returns an instance of . This is an implementation of that generates and responds to notifications when entities are added and removed from the collection. (This is the same concept as , but implemented as a projection over existing EF Core change tracking entries, rather than as an independent collection.) The local view's notifications are hooked into DbContext change tracking such that the local view stays in sync with the DbContext. Specifically: @@ -579,10 +579,10 @@ The output remains unchanged from the previous example because changes made to t ### Using the local view for Windows Forms or WPF data binding - forms the basis for data binding to EF Core entities. However, both Windows Forms and WPF work best when used with the specific type of notifying collection that they expect. The local view supports creating these specific collection types: + forms the basis for data binding to EF Core entities. However, both Windows Forms and WPF work best when used with the specific type of notifying collection that they expect. The local view supports creating these specific collection types: -- returns an for WPF data binding. -- returns a for Windows Forms data binding. +- returns an for WPF data binding. +- returns a for Windows Forms data binding. For example: diff --git a/entity-framework/core/change-tracking/explicit-tracking.md b/entity-framework/core/change-tracking/explicit-tracking.md index 2a8d862d0d..f6786cf9c7 100644 --- a/entity-framework/core/change-tracking/explicit-tracking.md +++ b/entity-framework/core/change-tracking/explicit-tracking.md @@ -8,9 +8,9 @@ uid: core/change-tracking/explicit-tracking # Explicitly Tracking Entities -Each instance tracks changes made to entities. These tracked entities in turn drive the changes to the database when is called. +Each instance tracks changes made to entities. These tracked entities in turn drive the changes to the database when is called. -Entity Framework Core (EF Core) change tracking works best when the same instance is used to both query for entities and update them by calling . This is because EF Core automatically tracks the state of queried entities and then detects any changes made to these entities when SaveChanges is called. This approach is covered in [Change Tracking in EF Core](xref:core/change-tracking/index). +Entity Framework Core (EF Core) change tracking works best when the same instance is used to both query for entities and update them by calling . This is because EF Core automatically tracks the state of queried entities and then detects any changes made to these entities when SaveChanges is called. This approach is covered in [Change Tracking in EF Core](xref:core/change-tracking/index). > [!TIP] > This document assumes that entity states and the basics of EF Core change tracking are understood. See [Change Tracking in EF Core](xref:core/change-tracking/index) for more information on these topics. @@ -19,7 +19,7 @@ Entity Framework Core (EF Core) change tracking works best when the same You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/ChangeTrackingInEFCore). > [!TIP] -> For simplicity, this document uses and references synchronous methods such as rather than their async equivalents such as . Calling and awaiting the async method can be substituted unless otherwise noted. +> For simplicity, this document uses and references synchronous methods such as rather than their async equivalents such as . Calling and awaiting the async method can be substituted unless otherwise noted. ## Introduction @@ -28,11 +28,11 @@ Entities can be explicitly "attached" to a methods. +The first of these will be needed by most applications, and is primarily handled by the methods. The second is only needed by applications that change entities or their relationships **_while the entities are not being tracked_**. For example, a web application may send entities to the web client where the user makes changes and sends the entities back. These entities are referred to as "disconnected" since they were originally queried from a DbContext, but were then disconnected from that context when sent to the client. -The web application must now re-attach these entities so that they are again tracked and indicate the changes that have been made such that can make appropriate updates to the database. This is primarily handled by the and methods. +The web application must now re-attach these entities so that they are again tracked and indicate the changes that have been made such that can make appropriate updates to the database. This is primarily handled by the and methods. > [!TIP] > Attaching entities to the _same DbContext instance_ that they were queried from should not normally be needed. Do not routinely perform a no-tracking query and then attach the returned entities to the same context. This will be slower than using a tracking query, and may also result in issues such as missing shadow property values, making it harder to get right. @@ -99,7 +99,7 @@ Notice that the key properties in this model need no additional configuration he ### Explicit key values -An entity must be tracked in the `Added` state to be inserted by . Entities are typically put in the Added state by calling one of , , , , or the equivalent methods on . +An entity must be tracked in the `Added` state to be inserted by . Entities are typically put in the Added state by calling one of , , , , or the equivalent methods on . > [!TIP] > These methods all work in the same way in the context of change tracking. See [Additional Change Tracking Features](xref:core/change-tracking/miscellaneous) for more information. @@ -312,7 +312,7 @@ This is exactly the same end-state as the previous example that used explicit ke ### Explicit key values -Entities returned from queries are tracked in the `Unchanged` state. The `Unchanged` state means that the entity has not been modified since it was queried. A disconnected entity, perhaps returned from a web client in an HTTP request, can be put into this state using either , , or the equivalent methods on . For example, to start tracking an existing blog: +Entities returned from queries are tracked in the `Unchanged` state. The `Unchanged` state means that the entity has not been modified since it was queried. A disconnected entity, perhaps returned from a web client in an HTTP request, can be put into this state using either , , or the equivalent methods on . For example, to start tracking an existing blog: [!code-csharp[DbContext_versus_DbSet_methods_1](../../../samples/core/ChangeTracking/AdditionalChangeTrackingFeatures/Samples.cs?name=DbContext_versus_DbSet_methods_1)] -Notice that is used to create a DbSet for the `PostTag` entity type. This DbSet can then be used to call `Add` with the new join entity instance. +Notice that is used to create a DbSet for the `PostTag` entity type. This DbSet can then be used to call `Add` with the new join entity instance. > [!IMPORTANT] > The CLR type used for join entity types by convention may change in future releases to improve performance. Do not depend on any specific join entity type unless it has been explicitly configured as is done for `Dictionary` in the code above. @@ -97,10 +97,10 @@ Access to entity properties uses the backing field of the property by default. T Sometimes it may be desirable for EF Core to generate side-effects when it modifies property values. For example, when data binding to entities, setting a property may generate notifications to the U.I. which do not happen when setting the field directly. This can be achieved by changing the for: -- All entity types in the model using -- All properties and navigations of a specific entity type using -- A specific property using -- A specific navigation using +- All entity types in the model using +- All properties and navigations of a specific entity type using +- A specific property using +- A specific navigation using Property access modes `Field` and `PreferField` will cause EF Core to access the property value through its backing field. Likewise, `Property` and `PreferProperty` will cause EF Core to access the property value through its getter and setter. @@ -127,7 +127,7 @@ EF Core creates temporary key values when tracking new entities that will have r ### Accessing temporary values -Temporary values are stored in the change tracker and not set onto entity instances directly. However, these temporary values _are_ exposed when using the various mechanisms for [Accessing Tracked Entities](xref:core/change-tracking/entity-entries). For example, the following code accesses a temporary value using : +Temporary values are stored in the change tracker and not set onto entity instances directly. However, these temporary values _are_ exposed when using the various mechanisms for [Accessing Tracked Entities](xref:core/change-tracking/entity-entries). For example, the following code accesses a temporary value using : [!code-csharp[Model](../../../samples/core/ChangeTracking/ChangingFKsAndNavigations/ExplicitJoinEntityWithStringPayloadSamples.cs?name=Model)] -A post can now be tagged in the same way as before, and the join entity will still be created automatically. This entity can then be accessed using one of the mechanisms described in [Accessing Tracked Entities](xref:core/change-tracking/entity-entries). For example, the code below uses to access the join entity instance: +A post can now be tagged in the same way as before, and the join entity will still be created automatically. This entity can then be accessed using one of the mechanisms described in [Accessing Tracked Entities](xref:core/change-tracking/entity-entries). For example, the code below uses to access the join entity instance: [!code-csharp[Many_to_many_relationships_9](../../../samples/core/ChangeTracking/ChangingFKsAndNavigations/ExplicitJoinEntityWithStringPayloadSamples.cs?name=Many_to_many_relationships_9)] -Finally, another way to set payload data is by either overriding or using the event to process entities before updating the database. For example: +Finally, another way to set payload data is by either overriding or using the event to process entities before updating the database. For example: [!code-csharp[RegisterInterceptor](../../../samples/core/Miscellaneous/CommandInterception/Program.cs?name=RegisterInterceptor)] -Alternately, `AddInterceptors` can be called as part of or when creating a instance to pass to the DbContext constructor. +Alternately, `AddInterceptors` can be called as part of or when creating a instance to pass to the DbContext constructor. > [!TIP] > OnConfiguring is still called when AddDbContext is used or a DbContextOptions instance is passed to the DbContext constructor. This makes it the ideal place to apply context configuration regardless of how the DbContext is constructed. @@ -63,7 +63,7 @@ Low-level database interception is split into the three interfaces shown in the The base classes , , and contain no-op implementations for each method in the corresponding interface. Use the base classes to avoid the need to implement unused interception methods. -The methods on each interceptor type come in pairs, with the first being called before the database operation is started, and the second after the operation has completed. For example, is called before a query is executed, and is called after query has been sent to the database. +The methods on each interceptor type come in pairs, with the first being called before the database operation is started, and the second after the operation has completed. For example, is called before a query is executed, and is called after query has been sent to the database. Each pair of methods have both sync and async variations. This allows for asynchronous I/O, such as requesting an access token, to happen as part of intercepting an async database operation. @@ -250,7 +250,7 @@ In the `Executing` method (i.e. before making a database call), the interceptor --> [!code-csharp[ReaderExecutingAsync](../../../samples/core/Miscellaneous/CachingInterception/CachingCommandInterceptor.cs?name=ReaderExecutingAsync)] -Notice how the code calls and passes a replacement containing the cached data. This InterceptionResult is then returned, causing suppression of query execution. The replacement reader is instead used by EF Core as the results of the query. +Notice how the code calls and passes a replacement containing the cached data. This InterceptionResult is then returned, causing suppression of query execution. The replacement reader is instead used by EF Core as the results of the query. This interceptor also manipulates the command text. This manipulation is not required, but improves clarity in log messages. The command text does not need to be valid SQL since the query is now not going to be executed. @@ -392,7 +392,7 @@ Notice from the log output that the application continues to use the cached mess > [!TIP] > You can [download the SaveChanges interceptor sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/SaveChangesInterception) from GitHub. - and interception points are defined by the interface. As for other interceptors, the base class with no-op methods is provided as a convenience. + and interception points are defined by the interface. As for other interceptors, the base class with no-op methods is provided as a convenience. > [!TIP] > Interceptors are powerful. However, in many cases it may be easier to override the SaveChanges method or use the [.NET events for SaveChanges](xref:core/logging-events-diagnostics/events) exposed on DbContext. @@ -493,7 +493,7 @@ The general idea for auditing with the interceptor is: * If SaveChanges succeeds, then the audit message is updated to indicate success * If SaveChanges fails, then the audit message is updated to indicate the failure -The first stage is handled before any changes are sent to the database using overrides of and . +The first stage is handled before any changes are sent to the database using overrides of and . [!code-csharp[LogToConsole](../../../samples/core/Miscellaneous/Logging/SimpleLogging/Program.cs?name=LogToConsole)] -Alternately, `LogTo` can be called as part of or when creating a instance to pass to the `DbContext` constructor. +Alternately, `LogTo` can be called as part of or when creating a instance to pass to the `DbContext` constructor. > [!TIP] > OnConfiguring is still called when AddDbContext is used or a DbContextOptions instance is passed to the DbContext constructor. This makes it the ideal place to apply context configuration regardless of how the DbContext is constructed. @@ -35,13 +35,13 @@ Alternately, `LogTo` can be called as part of delegate that accepts a string. EF Core will call this delegate with a string for each log message generated. It is then up to the delegate to do something with the given message. +`LogTo` requires an delegate that accepts a string. EF Core will call this delegate with a string for each log message generated. It is then up to the delegate to do something with the given message. -The method is often used for this delegate, as shown above. This results in each log message being written to the console. +The method is often used for this delegate, as shown above. This results in each log message being written to the console. ### Logging to the debug window - can be used to send output to the Debug window in Visual Studio or other IDEs. [Lambda syntax](/dotnet/csharp/language-reference/operators/lambda-expressions) must be used in this case because the `Debug` class is compiled out of release builds. For example: + can be used to send output to the Debug window in Visual Studio or other IDEs. [Lambda syntax](/dotnet/csharp/language-reference/operators/lambda-expressions) must be used in this case because the `Debug` class is compiled out of release builds. For example: [!code-csharp[BookEntityType](../../../samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs?name=BookEntityType)] -This attribute means that EF Core will use the specified `IEntityTypeConfiguration` implementation whenever the `Book` entity type is included in a model. The entity type is included in a model using one of the normal mechanisms. For example, by creating a property for the entity type: +This attribute means that EF Core will use the specified `IEntityTypeConfiguration` implementation whenever the `Book` entity type is included in a model. The entity type is included in a model using one of the normal mechanisms. For example, by creating a property for the entity type: [!code-csharp[DbContext](../../../samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs?name=DbContext)] -Or by registering it in : +Or by registering it in : ```csharp protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/entity-framework/core/modeling/keyless-entity-types.md b/entity-framework/core/modeling/keyless-entity-types.md index 4dc89282e4..f1c22e0799 100644 --- a/entity-framework/core/modeling/keyless-entity-types.md +++ b/entity-framework/core/modeling/keyless-entity-types.md @@ -94,4 +94,4 @@ Finally, we can query the database view in the standard way: > Note we have also defined a context level query property (DbSet) to act as a root for queries against this type. > [!TIP] -> To test keyless entity types mapped to views using the in-memory provider, map them to a query via . See the [in-memory provider docs](xref:core/testing/testing-without-the-database#in-memory-provider) for more information. +> To test keyless entity types mapped to views using the in-memory provider, map them to a query via . See the [in-memory provider docs](xref:core/testing/testing-without-the-database#in-memory-provider) for more information. diff --git a/entity-framework/core/modeling/relationships/navigations.md b/entity-framework/core/modeling/relationships/navigations.md index 44ede4e862..1200dcd177 100644 --- a/entity-framework/core/modeling/relationships/navigations.md +++ b/entity-framework/core/modeling/relationships/navigations.md @@ -35,7 +35,7 @@ Reference navigations for required relationships can be nullable or non-nullable ## Collection navigations -Collection navigations are instances of a .NET collection type; that is, any type implementing . The collection contains instances of the related entity type, of which there can be any number. They represent the "many" side(s) of [one-to-many](xref:core/modeling/relationships/one-to-many) and [many-to-many](xref:core/modeling/relationships/many-to-many) relationships. For example: +Collection navigations are instances of a .NET collection type; that is, any type implementing . The collection contains instances of the related entity type, of which there can be any number. They represent the "many" side(s) of [one-to-many](xref:core/modeling/relationships/one-to-many) and [many-to-many](xref:core/modeling/relationships/many-to-many) relationships. For example: ```csharp public ICollection ThePosts { get; set; } @@ -52,14 +52,14 @@ public ICollection ThePosts { get; } = new List(); ### Collection types -The underlying collection instance must implement , and must have a working `Add` method. It is common to use or . `List` is efficient for small numbers of related entities and maintains a stable ordering. `HashSet` has more efficient lookups for large numbers of entities, but does not have stable ordering. You can also use your own custom collection implementation. +The underlying collection instance must implement , and must have a working `Add` method. It is common to use or . `List` is efficient for small numbers of related entities and maintains a stable ordering. `HashSet` has more efficient lookups for large numbers of entities, but does not have stable ordering. You can also use your own custom collection implementation. > [!IMPORTANT] > The collection must use reference equality. When creating a `HashSet` for a collection navigation, make sure to use . Arrays cannot be used for collection navigations because, even though they implement `ICollection`, the `Add` method throws an exception when called. -Even though the collection instance must be an `ICollection`, the collection does not need to be exposed as such. For example, it is common to expose the navigation as an , which provides a read-only view that cannot be randomly modified by application code. For example: +Even though the collection instance must be an `ICollection`, the collection does not need to be exposed as such. For example, it is common to expose the navigation as an , which provides a read-only view that cannot be randomly modified by application code. For example: ```csharp public class Blog @@ -135,7 +135,7 @@ If EF needs to add an entity to a collection navigation, for example, while exec - Otherwise, an exception is thrown. > [!NOTE] -> If [notification entities](xref:core/change-tracking/change-detection#notification-entities), including [change-tracking proxies](xref:core/change-tracking/change-detection#change-tracking-proxies), are being used, then and are used in place of `List` and `HashSet`. +> If [notification entities](xref:core/change-tracking/change-detection#notification-entities), including [change-tracking proxies](xref:core/change-tracking/change-detection#change-tracking-proxies), are being used, then and are used in place of `List` and `HashSet`. > [!IMPORTANT] > As described in the [change tracking documentation](xref:core/change-tracking/identity-resolution), EF only tracks a single instance of any entity with a given key value. This means that collections used as navigations must use [reference equality semantics](/dotnet/csharp/language-reference/operators/equality-operators). Entity types that don't override object equality will get this by default. Make sure to use when creating a `HashSet` for use as a navigation to ensure it works for all entity types. diff --git a/entity-framework/core/modeling/shadow-properties.md b/entity-framework/core/modeling/shadow-properties.md index f8ef0f8f72..0a8f7ff72f 100644 --- a/entity-framework/core/modeling/shadow-properties.md +++ b/entity-framework/core/modeling/shadow-properties.md @@ -23,7 +23,7 @@ For example, the following code listing will result in a `BlogId` shadow propert ## Configuring shadow properties -You can use the [Fluent API](xref:core/modeling/index#use-fluent-api-to-configure-a-model) to configure shadow properties. Once you have called the string overload of , you can chain any of the configuration calls you would for other properties. In the following sample, since `Blog` has no CLR property named `LastUpdated`, a shadow property is created: +You can use the [Fluent API](xref:core/modeling/index#use-fluent-api-to-configure-a-model) to configure shadow properties. Once you have called the string overload of , you can chain any of the configuration calls you would for other properties. In the following sample, since `Blog` has no CLR property named `LastUpdated`, a shadow property is created: [!code-csharp[Main](../../../samples/core/Modeling/ShadowAndIndexerProperties/ShadowProperty.cs?name=ShadowProperty&highlight=8)] diff --git a/entity-framework/core/modeling/value-comparers.md b/entity-framework/core/modeling/value-comparers.md index 25233d3a5a..e6b9940dc6 100644 --- a/entity-framework/core/modeling/value-comparers.md +++ b/entity-framework/core/modeling/value-comparers.md @@ -13,7 +13,7 @@ uid: core/modeling/value-comparers ## Background -[Change tracking](xref:core/change-tracking/index) means that EF Core automatically determines what changes were performed by the application on a loaded entity instance, so that those changes can be saved back to the database when is called. EF Core usually performs this by taking a *snapshot* of the instance when it's loaded from the database, and *comparing* that snapshot to the instance handed out to the application. +[Change tracking](xref:core/change-tracking/index) means that EF Core automatically determines what changes were performed by the application on a loaded entity instance, so that those changes can be saved back to the database when is called. EF Core usually performs this by taking a *snapshot* of the instance when it's loaded from the database, and *comparing* that snapshot to the instance handed out to the application. EF Core comes with built-in logic for snapshotting and comparing most standard types used in databases, so users don't usually need to worry about this topic. However, when a property is mapped through a [value converter](xref:core/modeling/value-conversions), EF Core needs to perform comparison on arbitrary user types, which may be complex. By default, EF Core uses the default equality comparison defined by types (e.g. the `Equals` method); for snapshotting, [value types](/dotnet/csharp/language-reference/builtin-types/value-types) are copied to produce the snapshot, while for [reference types](/dotnet/csharp/language-reference/keywords/reference-types) no copying occurs, and the same instance is used as the snapshot. @@ -34,7 +34,7 @@ Consider byte arrays, which can be arbitrarily large. These could be compared: * By reference, such that a difference is only detected if a new byte array is used * By deep comparison, such that mutation of the bytes in the array is detected -By default, EF Core uses the first of these approaches for non-key byte arrays. That is, only references are compared and a change is detected only when an existing byte array is replaced with a new one. This is a pragmatic decision that avoids copying entire arrays and comparing them byte-to-byte when executing . It means that the common scenario of replacing, say, one image with another is handled in a performant way. +By default, EF Core uses the first of these approaches for non-key byte arrays. That is, only references are compared and a change is detected only when an existing byte array is replaced with a new one. This is a pragmatic decision that avoids copying entire arrays and comparing them byte-to-byte when executing . It means that the common scenario of replacing, say, one image with another is handled in a performant way. On the other hand, reference equality would not work when byte arrays are used to represent binary keys, since it's very unlikely that an FK property is set to the *same instance* as a PK property to which it needs to be compared. Therefore, EF Core uses deep comparisons for byte arrays acting as keys; this is unlikely to have a big performance hit since binary keys are usually short. @@ -71,7 +71,7 @@ It is recommended that you use immutable types (classes or structs) with value c [!code-csharp[ListProperty](../../../samples/core/Modeling/ValueConversions/MappingListProperty.cs?name=ListProperty)] -The class: +The class: * Has reference equality; two lists containing the same values are treated as different. * Is mutable; values in the list can be added and removed. @@ -88,7 +88,7 @@ A typical value conversion on a list property might convert the list to and from *** -The constructor accepts three expressions: +The constructor accepts three expressions: * An expression for checking equality * An expression for generating a hash code @@ -107,10 +107,10 @@ The snapshot is created by cloning the list with `ToList`. Again, this is only n The background section covers why key comparisons may require special semantics. Make sure to create a comparer that is appropriate for keys when setting it on a primary, principal, or foreign key property. -Use in the rare cases where different semantics is required on the same property. +Use in the rare cases where different semantics is required on the same property. > [!NOTE] -> has been obsoleted. Use instead. +> has been obsoleted. Use instead. ## Overriding the default comparer diff --git a/entity-framework/core/modeling/value-conversions.md b/entity-framework/core/modeling/value-conversions.md index 77b6812842..bc5edcfd63 100644 --- a/entity-framework/core/modeling/value-conversions.md +++ b/entity-framework/core/modeling/value-conversions.md @@ -19,11 +19,11 @@ Value converters are specified in terms of a `ModelClrType` and a `ProviderClrTy Conversions are defined using two `Func` expression trees: one from `ModelClrType` to `ProviderClrType` and the other from `ProviderClrType` to `ModelClrType`. Expression trees are used so that they can be compiled into the database access delegate for efficient conversions. The expression tree may contain a simple call to a conversion method for complex conversions. > [!NOTE] -> A property that has been configured for value conversion may also need to specify a . See the examples below, and the [Value Comparers](xref:core/modeling/value-comparers) documentation for more information. +> A property that has been configured for value conversion may also need to specify a . See the examples below, and the [Value Comparers](xref:core/modeling/value-comparers) documentation for more information. ## Configuring a value converter -Value conversions are configured in . For example, consider an enum and entity type defined as: +Value conversions are configured in . For example, consider an enum and entity type defined as: [!code-csharp[BeastAndRider](../../../samples/core/Modeling/ValueConversions/EnumToStringConversions.cs?name=BeastAndRider)] -Conversions can be configured in to store the enum values as strings such as "Donkey", "Mule", etc. in the database; you simply need to provide one function which converts from the `ModelClrType` to the `ProviderClrType`, and another for the opposite conversion: +Conversions can be configured in to store the enum values as strings such as "Donkey", "Mule", etc. in the database; you simply need to provide one function which converts from the `ModelClrType` to the `ProviderClrType`, and another for the opposite conversion: [!code-csharp[ConversionByBuiltInBoolToInt](../../../samples/core/Modeling/ValueConversions/EnumToStringConversions.cs?name=ConversionByBuiltInBoolToInt)] -This is functionally the same as creating an instance of the built-in and setting it explicitly: +This is functionally the same as creating an instance of the built-in and setting it explicitly: [!code-csharp[ConfigurePrimitiveCollection](../../../samples/core/Modeling/ValueConversions/PrimitiveCollection.cs?name=ConfigurePrimitiveCollection)] -`ICollection` represents a mutable reference type. This means that a is needed so that EF Core can track and detect changes correctly. See [Value Comparers](xref:core/modeling/value-comparers) for more information. +`ICollection` represents a mutable reference type. This means that a is needed so that EF Core can track and detect changes correctly. See [Value Comparers](xref:core/modeling/value-comparers) for more information. ### Collections of value objects @@ -547,7 +547,7 @@ And again use serialization to store this: [!code-csharp[ConfigureValueObjectCollection](../../../samples/core/Modeling/ValueConversions/ValueObjectCollection.cs?name=ConfigureValueObjectCollection)] > [!NOTE] -> As before, this conversion requires a . See [Value Comparers](xref:core/modeling/value-comparers) for more information. +> As before, this conversion requires a . See [Value Comparers](xref:core/modeling/value-comparers) for more information. ### Value objects as keys @@ -647,7 +647,7 @@ This can be mapped to a SQL server `rowversion` column using a value converter: ### Specify the DateTime.Kind when reading dates -SQL Server discards the flag when storing a as a [`datetime`](/sql/t-sql/data-types/datetime-transact-sql) or [`datetime2`](/sql/t-sql/data-types/datetime2-transact-sql). This means that DateTime values coming back from the database always have a of `Unspecified`. +SQL Server discards the flag when storing a as a [`datetime`](/sql/t-sql/data-types/datetime-transact-sql) or [`datetime2`](/sql/t-sql/data-types/datetime2-transact-sql). This means that DateTime values coming back from the database always have a of `Unspecified`. Value converters can be used in two ways to deal with this. First, EF Core has a value converter that creates an 8-byte opaque value which preserves the `Kind` flag. For example: diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index 164759812c..4ce3e30638 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -15,13 +15,13 @@ Note that context pooling is orthogonal to database connection pooling, which is ### [With dependency injection](#tab/with-di) -The typical pattern in an ASP.NET Core app using EF Core involves registering a custom type into the [dependency injection](/aspnet/core/fundamentals/dependency-injection) container via . Then, instances of that type are obtained through constructor parameters in controllers or Razor Pages. +The typical pattern in an ASP.NET Core app using EF Core involves registering a custom type into the [dependency injection](/aspnet/core/fundamentals/dependency-injection) container via . Then, instances of that type are obtained through constructor parameters in controllers or Razor Pages. -To enable context pooling, simply replace `AddDbContext` with : +To enable context pooling, simply replace `AddDbContext` with : [!code-csharp[Main](../../../samples/core/Performance/AspNetContextPooling/Program.cs#AddDbContextPool)] -The `poolSize` parameter of sets the maximum number of instances retained by the pool (defaults to 1024). Once `poolSize` is exceeded, new context instances are not cached and EF falls back to the non-pooling behavior of creating instances on demand. +The `poolSize` parameter of sets the maximum number of instances retained by the pool (defaults to 1024). Once `poolSize` is exceeded, new context instances are not cached and EF falls back to the non-pooling behavior of creating instances on demand. ### [Without dependency injection](#tab/without-di) @@ -92,7 +92,7 @@ EF supports *compiled queries*, which allow the explicit compilation of a LINQ q | WithCompiledQuery | 10 | 645.3 us | 10.00 us | 9.35 us | 2.9297 | 13 KB | | WithoutCompiledQuery | 10 | 709.8 us | 25.20 us | 73.10 us | 3.9063 | 18 KB | -To use compiled queries, first compile a query with as follows (use for synchronous queries): +To use compiled queries, first compile a query with as follows (use for synchronous queries): [!code-csharp[Main](../../../samples/core/Performance/Other/Program.cs#CompiledQueryCompile)] diff --git a/entity-framework/core/performance/efficient-querying.md b/entity-framework/core/performance/efficient-querying.md index e4eab9de86..2e9756d17b 100644 --- a/entity-framework/core/performance/efficient-querying.md +++ b/entity-framework/core/performance/efficient-querying.md @@ -156,7 +156,7 @@ Whether a query buffers or streams depends on how it is evaluated: If your queries return just a few results, then you probably don't have to worry about this. However, if your query might return large numbers of rows, it's worth giving thought to streaming instead of buffering. > [!NOTE] -> Avoid using or if you intend to use another LINQ operator on the result - this will needlessly buffer all results into memory. Use instead. +> Avoid using or if you intend to use another LINQ operator on the result - this will needlessly buffer all results into memory. Use instead. ### Internal buffering by EF @@ -165,16 +165,16 @@ In certain situations, EF will itself buffer the resultset internally, regardles * When a retrying execution strategy is in place. This is done to make sure the same results are returned if the query is retried later. * When [split query](xref:core/querying/single-split-queries) is used, the resultsets of all but the last query are buffered - unless MARS (Multiple Active Result Sets) is enabled on SQL Server. This is because it is usually impossible to have multiple query resultsets active at the same time. -Note that this internal buffering occurs in addition to any buffering you cause via LINQ operators. For example, if you use on a query and a retrying execution strategy is in place, the resultset is loaded into memory *twice*: once internally by EF, and once by . +Note that this internal buffering occurs in addition to any buffering you cause via LINQ operators. For example, if you use on a query and a retrying execution strategy is in place, the resultset is loaded into memory *twice*: once internally by EF, and once by . ## Tracking, no-tracking and identity resolution It's recommended to read [the dedicated page on tracking and no-tracking](xref:core/querying/tracking) before continuing with this section. -EF tracks entity instances by default, so that changes on them are detected and persisted when is called. Another effect of tracking queries is that EF detects if an instance has already been loaded for your data, and will automatically return that tracked instance rather than returning a new one; this is called *identity resolution*. From a performance perspective, change tracking means the following: +EF tracks entity instances by default, so that changes on them are detected and persisted when is called. Another effect of tracking queries is that EF detects if an instance has already been loaded for your data, and will automatically return that tracked instance rather than returning a new one; this is called *identity resolution*. From a performance perspective, change tracking means the following: * EF internally maintains a dictionary of tracked instances. When new data is loaded, EF checks the dictionary to see if an instance is already tracked for that entity's key (identity resolution). The dictionary maintenance and lookups take up some time when loading the query's results. -* Before handing a loaded instance to the application, EF *snapshots* that instance and keeps the snapshot internally. When is called, the application's instance is compared with the snapshot to discover the changes to be persisted. The snapshot takes up more memory, and the snapshotting process itself takes time; it's sometimes possible to specify different, possibly more efficient snapshotting behavior via [value comparers](xref:core/modeling/value-comparers), or to use change-tracking proxies to bypass the snapshotting process altogether (though that comes with its own set of disadvantages). +* Before handing a loaded instance to the application, EF *snapshots* that instance and keeps the snapshot internally. When is called, the application's instance is compared with the snapshot to discover the changes to be persisted. The snapshot takes up more memory, and the snapshotting process itself takes time; it's sometimes possible to specify different, possibly more efficient snapshotting behavior via [value comparers](xref:core/modeling/value-comparers), or to use change-tracking proxies to bypass the snapshotting process altogether (though that comes with its own set of disadvantages). In read-only scenarios where changes aren't saved back to the database, the above overheads can be avoided by using [no-tracking queries](xref:core/querying/tracking#no-tracking-queries). However, since no-tracking queries do not perform identity resolution, a database row which is referenced by multiple other loaded rows will be materialized as different instances. @@ -193,7 +193,7 @@ Finally, it is possible to perform updates without the overhead of change tracki In some cases, more optimized SQL exists for your query, which EF does not generate. This can happen when the SQL construct is an extension specific to your database that's unsupported, or simply because EF does not translate to it yet. In these cases, writing SQL by hand can provide a substantial performance boost, and EF supports several ways to do this. -* Use SQL queries [directly in your query](xref:core/querying/sql-queries), e.g. via . EF even lets you compose over the SQL with regular LINQ queries, allowing you to express only a part of the query in SQL. This is a good technique when the SQL only needs to be used in a single query in your codebase. +* Use SQL queries [directly in your query](xref:core/querying/sql-queries), e.g. via . EF even lets you compose over the SQL with regular LINQ queries, allowing you to express only a part of the query in SQL. This is a good technique when the SQL only needs to be used in a single query in your codebase. * Define a [user-defined function](xref:core/querying/database-functions) (UDF), and then call that from your queries. Note that EF allows UDFs to return full resultsets - these are known as table-valued functions (TVFs) - and also allows mapping a `DbSet` to a function, making it look just like just another table. * Define a database view and query from it in your queries. Note that unlike functions, views cannot accept parameters. @@ -202,7 +202,7 @@ In some cases, more optimized SQL exists for your query, which EF does not gener ## Asynchronous programming -As a general rule, in order for your application to be scalable, it's important to always use asynchronous APIs rather than synchronous one (e.g. rather than ). Synchronous APIs block the thread for the duration of database I/O, increasing the need for threads and the number of thread context switches that must occur. +As a general rule, in order for your application to be scalable, it's important to always use asynchronous APIs rather than synchronous one (e.g. rather than ). Synchronous APIs block the thread for the duration of database I/O, increasing the need for threads and the number of thread context switches that must occur. For more information, see the page on [async programming](xref:core/miscellaneous/async). diff --git a/entity-framework/core/performance/efficient-updating.md b/entity-framework/core/performance/efficient-updating.md index 97e8e91eab..842aab9b1d 100644 --- a/entity-framework/core/performance/efficient-updating.md +++ b/entity-framework/core/performance/efficient-updating.md @@ -13,7 +13,7 @@ EF Core helps minimize roundtrips by automatically batching together all updates [!code-csharp[Main](../../../samples/core/Performance/Other/Program.cs#SaveChangesBatching)] -The above loads a blog from the database, changes its URL, and then adds two new blogs; to apply this, two SQL INSERT statements and one UPDATE statement are sent to the database. Rather than sending them one by one, as Blog instances are added, EF Core tracks these changes internally, and executes them in a single roundtrip when is called. +The above loads a blog from the database, changes its URL, and then adds two new blogs; to apply this, two SQL INSERT statements and one UPDATE statement are sent to the database. Rather than sending them one by one, as Blog instances are added, EF Core tracks these changes internally, and executes them in a single roundtrip when is called. The number of statements that EF batches in a single roundtrip depends on the database provider being used. For example, performance analysis has shown batching to be generally less efficient for SQL Server when less than 4 statements are involved. Similarly, the benefits of batching degrade after around 40 statements for SQL Server, so EF Core will by default only execute up to 42 statements in a single batch, and execute additional statements in separate roundtrips. diff --git a/entity-framework/core/providers/cosmos/modeling.md b/entity-framework/core/providers/cosmos/modeling.md index 2406943d1c..2ceebf6728 100644 --- a/entity-framework/core/providers/cosmos/modeling.md +++ b/entity-framework/core/providers/cosmos/modeling.md @@ -11,13 +11,13 @@ uid: core/providers/cosmos/modeling In Azure Cosmos DB, JSON documents are stored in containers. Unlike tables in relational databases, Azure Cosmos DB containers can contain documents with different shapes - a container does not impose a uniform schema on its documents. However, various configuration options are defined at the container level, and therefore affect all documents contained within it. See the [Azure Cosmos DB documentation on containers](/azure/cosmos-db/resource-model) for more information. -By default, EF maps all entity types to the same container; this is usually a good default in terms of performance and pricing. The default container is named after the .NET context type (`OrderContext` in this case). To change the default container name, use : +By default, EF maps all entity types to the same container; this is usually a good default in terms of performance and pricing. The default container is named after the .NET context type (`OrderContext` in this case). To change the default container name, use : ```csharp modelBuilder.HasDefaultContainer("Store"); ``` -To map an entity type to a different container use : +To map an entity type to a different container use : ```csharp modelBuilder.Entity().ToContainer("Orders"); @@ -27,7 +27,7 @@ Before mapping entity types to different containers, make sure you understand th ## IDs and keys -Azure Cosmos DB requires all documents to have an `id` JSON property which uniquely identifies them. Like other EF providers, the EF Azure Cosmos DB provider will attempt to find a property named `Id` or `Id`, and configure that property as the key of your entity type, mapping it to the `id` JSON property. You can configure any property to be the key property by using ; see [the general EF documentation on keys](xref:core/modeling/keys) for more information. +Azure Cosmos DB requires all documents to have an `id` JSON property which uniquely identifies them. Like other EF providers, the EF Azure Cosmos DB provider will attempt to find a property named `Id` or `Id`, and configure that property as the key of your entity type, mapping it to the `id` JSON property. You can configure any property to be the key property by using ; see [the general EF documentation on keys](xref:core/modeling/keys) for more information. Developers coming to Azure Cosmos DB from other databases sometimes expect the key (`Id`) property to be generated automatically. For example, on SQL Server, EF configures numeric key properties to be IDENTITY columns, where auto-incrementing values are generated in the database. In contrast, Azure Cosmos DB does not support automatic generation of properties, and so key properties must be explicitly set. Inserting an entity type with an unset key property will simply insert the CLR default value for that property (e.g. 0 for `int`), and a second insert will fail; EF issues a warning if you attempt to do this. @@ -95,7 +95,7 @@ This is similar, but allows EF to use efficient [point reads](xref:core/provider ## Provisioned throughput -If you use EF Core to create the Azure Cosmos DB database or containers you can configure [provisioned throughput](/azure/cosmos-db/set-throughput) for the database by calling or . For example: +If you use EF Core to create the Azure Cosmos DB database or containers you can configure [provisioned throughput](/azure/cosmos-db/set-throughput) for the database by calling or . For example: [!code-csharp[ModelThroughput](../../../../samples/core/Miscellaneous/NewInEFCore6.Cosmos/CosmosModelConfigurationSample.cs?name=ModelThroughput)] -To configure provisioned throughput for a container call or . For example: +To configure provisioned throughput for a container call or . For example: [!code-csharp[BookConfiguration](../../../../samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs?name=BookConfiguration)] -Normally, this configuration class must be instantiated and called into from . For example: +Normally, this configuration class must be instantiated and called into from . For example: ```csharp protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -2728,7 +2728,7 @@ public class Book --> [!code-csharp[BookEntityType](../../../../samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs?name=BookEntityType)] -This attribute means that EF Core will use the specified `IEntityTypeConfiguration` implementation whenever the `Book` entity type is included in a model. The entity type is included in a model using one of the normal mechanisms. For example, by creating a property for the entity type: +This attribute means that EF Core will use the specified `IEntityTypeConfiguration` implementation whenever the `Book` entity type is included in a model. The entity type is included in a model using one of the normal mechanisms. For example, by creating a property for the entity type: [!code-csharp[DbContext](../../../../samples/core/Miscellaneous/NewInEFCore6/EntityTypeConfigurationAttributeSample.cs?name=DbContext)] -Or by registering it in : +Or by registering it in : ```csharp protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -2775,7 +2775,7 @@ SQL Server [sparse columns](/sql/relational-databases/tables/use-sparse-columns) --> [!code-csharp[UserEntityType](../../../../samples/core/Miscellaneous/NewInEFCore6/SparseColumnsSample.cs?name=UserEntityType)] -There may be millions of users, with only a handful of these being moderators. This means mapping the `ForumName` as sparse might make sense here. This can now be configured using `IsSparse` in . For example: +There may be millions of users, with only a handful of these being moderators. This means mapping the `ForumName` as sparse might make sense here. This can now be configured using `IsSparse` in . For example: [!code-csharp[LookupByAnyProperty](../../../../samples/core/Miscellaneous/NewInEFCore8/LookupByKeySample.cs?name=LookupByAnyProperty)] -This lookup requires a scan of all tracked `Post` instances, and so will be less efficient than key lookups. However, it is usually still faster than naive queries using . +This lookup requires a scan of all tracked `Post` instances, and so will be less efficient than key lookups. However, it is usually still faster than naive queries using . Finally, it is also possible to perform lookups against composite keys, other combinations of multiple properties, or when the property type is not known at compile time. For example: @@ -2130,7 +2130,7 @@ Queries using `DateOnly` and `TimeOnly` work in the expected manner. For example --> [!code-csharp[OpenSchools](../../../../samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs?name=OpenSchools)] -This query translates to the following SQL, as shown by : +This query translates to the following SQL, as shown by : ```sql DECLARE @__today_0 date = '2023-02-07'; @@ -2173,7 +2173,7 @@ Combining two features from EF8, we can now query for opening hours by indexing --> [!code-csharp[OpenSchoolsJson](../../../../samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs?name=OpenSchoolsJson)] -This query translates to the following SQL, as shown by : +This query translates to the following SQL, as shown by : ```sql DECLARE @__today_0 date = '2023-02-07'; diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index b0a47e750b..cfdda27887 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -416,19 +416,19 @@ Unfortunately, Azure Cosmos DB does not currently support the `OFFSET` and `LIMI ##### Old behavior -Previously, calls to were ignored by the EF Cosmos DB provider. +Previously, calls to were ignored by the EF Cosmos DB provider. ##### New behavior -The provider now throws if is specified. +The provider now throws if is specified. ##### Why -In Azure Cosmos DB, all properties are indexed by default, and no indexing needs to be specified. While it's possible to define a custom indexing policy, this isn't currently supported by EF, and can be done via the Azure Portal without EF support. Since calls weren't doing anything, they are no longer allowed. +In Azure Cosmos DB, all properties are indexed by default, and no indexing needs to be specified. While it's possible to define a custom indexing policy, this isn't currently supported by EF, and can be done via the Azure Portal without EF support. Since calls weren't doing anything, they are no longer allowed. ##### Mitigations -Remove any calls to . +Remove any calls to . 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 a48c9bb0fc..36c45ce656 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 @@ -79,7 +79,7 @@ To learn more about querying with partition keys and point reads, [see the query Azure Cosmos DB originally supported a single partition key, but has since expanded partitioning capabilities to also support [subpartitioning through the specification of up to three levels of hierarchy in the partition key](/azure/cosmos-db/hierarchical-partition-keys). EF Core 9 brings full support for hierarchical partition keys, allowing you take advantage of the better performance and cost savings associated with this feature. -Partition keys are specified using the model building API, typically in . There must be a mapped property in the entity type for each level of the partition key. For example, consider a `UserSession` entity type: +Partition keys are specified using the model building API, typically in . There must be a mapped property in the entity type for each level of the partition key. For example, consider a `UserSession` entity type: - - - \ No newline at end of file diff --git a/samples/core/Xamarin/EFGetStarted.iOS/AppDelegate.cs b/samples/core/Xamarin/EFGetStarted.iOS/AppDelegate.cs deleted file mode 100644 index 035e987717..0000000000 --- a/samples/core/Xamarin/EFGetStarted.iOS/AppDelegate.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using Foundation; -using UIKit; - -namespace EFGetStarted.iOS -{ - // The UIApplicationDelegate for the application. This class is responsible for launching the - // User Interface of the application, as well as listening (and optionally responding) to - // application events from iOS. - [Register("AppDelegate")] - public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate - { - // - // This method is invoked when the application has loaded and is ready to run. In this - // method you should instantiate the window, load the UI into it and then make the window - // visible. - // - // You have 17 seconds to return from this method, or iOS will terminate your application. - // - public override bool FinishedLaunching(UIApplication app, NSDictionary options) - { - global::Xamarin.Forms.Forms.Init(); - LoadApplication(new App()); - - return base.FinishedLaunching(app, options); - } - } -} diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 98f4d035c8..0000000000 --- a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "images": [ - { - "scale": "2x", - "size": "20x20", - "idiom": "iphone", - "filename": "Icon40.png" - }, - { - "scale": "3x", - "size": "20x20", - "idiom": "iphone", - "filename": "Icon60.png" - }, - { - "scale": "2x", - "size": "29x29", - "idiom": "iphone", - "filename": "Icon58.png" - }, - { - "scale": "3x", - "size": "29x29", - "idiom": "iphone", - "filename": "Icon87.png" - }, - { - "scale": "2x", - "size": "40x40", - "idiom": "iphone", - "filename": "Icon80.png" - }, - { - "scale": "3x", - "size": "40x40", - "idiom": "iphone", - "filename": "Icon120.png" - }, - { - "scale": "2x", - "size": "60x60", - "idiom": "iphone", - "filename": "Icon120.png" - }, - { - "scale": "3x", - "size": "60x60", - "idiom": "iphone", - "filename": "Icon180.png" - }, - { - "scale": "1x", - "size": "20x20", - "idiom": "ipad", - "filename": "Icon20.png" - }, - { - "scale": "2x", - "size": "20x20", - "idiom": "ipad", - "filename": "Icon40.png" - }, - { - "scale": "1x", - "size": "29x29", - "idiom": "ipad", - "filename": "Icon29.png" - }, - { - "scale": "2x", - "size": "29x29", - "idiom": "ipad", - "filename": "Icon58.png" - }, - { - "scale": "1x", - "size": "40x40", - "idiom": "ipad", - "filename": "Icon40.png" - }, - { - "scale": "2x", - "size": "40x40", - "idiom": "ipad", - "filename": "Icon80.png" - }, - { - "scale": "1x", - "size": "76x76", - "idiom": "ipad", - "filename": "Icon76.png" - }, - { - "scale": "2x", - "size": "76x76", - "idiom": "ipad", - "filename": "Icon152.png" - }, - { - "scale": "2x", - "size": "83.5x83.5", - "idiom": "ipad", - "filename": "Icon167.png" - }, - { - "scale": "1x", - "size": "1024x1024", - "idiom": "ios-marketing", - "filename": "Icon1024.png" - } - ], - "properties": {}, - "info": { - "version": 1, - "author": "xcode" - } -} \ No newline at end of file diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png deleted file mode 100644 index 9174c989a9c8b8a5ca133228f4ed7c173fffd2ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70429 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 z zCn)b8&=oMu6ygwwJfdasJX|@L6?m1Dv0X9t>JAWO^UIj0#&(3UrHx;vP^3g= zL{(XT!?`D*pP8)WoGHYEZZc$!odTzb8n)q0|88*>6P z`?6&CSv_W7r2yF0beQ2*?V^_%pKktVAo`)T^26X@NpK_*-ni{D7{Sp{C0A<|16l(; zOL*xGW|*sKsiwHvE!h3QXe@^a#6W3}8!DQu-h?A_4gkeRYkt4NC~GR5P8eyp;9kVQ8$QG$5ad7Fo23Z~ak1jY~RXG{v?3G$RarFe`XePu3X{R+=mBOw&X zks)|Sc$RcG-jhn!`~-x|vg!&DA&@}QH^RNdyy9nq56yrU$^qAaS+F_NOaeFb)CVaH z?!UvPajgrK&zqdAs>&Def#wkcG_UhmYOVw^M`VZz@+4IWAVzK%`+za9rm2SD9={u@ zlx5D6UDL;lc7#9`+%vnlP3PescU=N`DHQPt_N55GNBMkVCRMR4?fvp zAFsvcHN4c9rb>J@{*IH>RTr9de%9i4Gd(cbFa9SP4anhoP;TA0!oZyB8?lNMDHPHK zCaOaFU9?x2A!o>p>mCF9r+hKs9Czu_P1l$LWU%}q#)=T3p`ZnYyeHmsewqw`}L^4LuHqfo+CG6<2n7#l^3;H^^!1 zsaieYFnN)Kc7Mv}^xE)4kXUw8<9I+jMB@QV9T9I8haLDt1Ne#exWUfGYG$4uMoEu& zo81#2up18Y40h%tIsOZglp(ltVsE*j1~$lVd|;rN)&${~o~-%KZnJp&3|OFR{^8E9 zJ;fCu53Ysw%}@VYWE*z7r)&4P=^B-SF%a@>*9g84<4aFUZT7x)qdsS+#2tu5NbpU@ zg;EwV)l-#sK>#r9>(0Figx{9lKm>KvRj;y<8 zc8SxMW4<11(s@QMV_}n9MRzA*62->vzxmHh1)GVASEJY7LVtRw`Rv{v`(Fuc00(&o z%m>gS2aJekmdNQ4p<{pD3HqZ-%4hdU1__xYhLi9mTJXD|E zE`t6SX)}l_DY5vO0Xrs#O6_DKtPKn0f+e~SprDYmJL_`<053iA5P`zn z4<5etc%aF58sHFr#M;U-9|=;l)J#Q2vS!Q9(d(EX6fubL%uA_lqa2%!cpNIv78QZ}Ayo(>C(ZpsRtKhzD--fpuoCch87cX-Bna9_{z%$b*dHM0?+T&Hk!+^UM`r|vq z2Id$??bX^|tfYaE+h#Nik(ZcN+wt)28q^gWe!y8jDCXrD<2qV#49x@5$8&Zrd5NTs zNYcix;9fe#PQQ;T?!6hG>9K{K+RCPqiGc9z%t{=`QaX>7O{l(+#7mJ1>Rae^J?82e z6cLqLypskTCyu>uc~$0-XZ^1Qvhwr+pKQ#CKImhGu*MGM*ZrROuAHWuT*yM$ieEy8*KLFMMdLZL|D+yDmy@3_PELTEVMI6nwfcYA3ZQ9wwKdtkT z;`;z7fU{U6>CS7kr3=A-()_G*G(Mjf2wXKe

Fpy)y!S(AQHSG#udd_8#b4sQu!R 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 PgFh2POM|ilu9yD@)d*=D diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png deleted file mode 100644 index 9c60a1761dbf62cc2a45ff98b9fdb63ade16e4d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3773 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 Dh-f%Y diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png deleted file mode 100644 index 448d6efb577d07e227a5c62545173ddf6bd86b55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4750 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 diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png deleted file mode 100644 index 8524768f8d764da7e9c452a444208708f2d18ff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4692 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 diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png deleted file mode 100644 index 60a64703c0f11d08705cd607f7751338707f5919..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5192 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 nB>N_)Q7iwV%v7MwAoJ}E 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 T3-0p800000NkvXXu0mjfSlal| diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png deleted file mode 100644 index 1ad04f004b638bf781012290d78e4138f97bbe5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1761 zcmV<71|Io|P)4P%ubY|S^%$zf~ zmwTOa@12BA$oV-Y9!V&U%c=j==#_}M2ylE}1m>yyDoGsZ#Yy zNX}RO*f(MzmKS&u`qiajIyW{Y_LC%m2NqT@Ic|QpvYqwNgBK7n5X%c(3k^?2>EOA` zqGaXjE7H9BiJ55fh0iJRW}@=&(@R^E1hLB>kE%PS6eP@VZVdtn(fh;5DPKg!j;fJZ%)wH{Wn#~V&#n(o1URS zsyS`0Tu2m;-H}z9O^h`!UZAFr@?0a7Z;pYOi0uZhgzh=rOEDi`FIkKtVu*gEcSM!h zmb#_XR$akjlg$JI75MXgWkG7IUnYJ+X=1J!qJ%jXVj{L1I2QU%?=?DgV^U?)92DZm zV?>``xT1#kZdgUt!2n?|0>*6ae4tikA9FAlJ}kjmMQm_z3LB5sZYHBKdbex9_Hv@K z%Y?q@9-)b7vJ6X$3h0B4tH__=#*`9^efY@IQfghn*=E2Nb8sR8lrQlu`Ca_Rmm6>Z z7bkEe^w8M>x;hoNUvWu_GZJPVpI;bMTsBpf(@U$Ch(-gk0T#WpsaB1{7ISQ~Y48mW z;Nk?@LjM_?q{BV-D=veoOmJoncVDC1GwGGz(O5@o7ZkGCIJMPO(7K9b6M_wF?Xqd< zo4J6KF0_U2<1=T3x0qc6G6#g+^=N{QTpChC!GZuCY*|eU{Rw)LMN7a2wwbaCdn_dE zzy+Lip(XU4-+SoTFyEcnH3?HRV^%-;Ylx;|>8v&^Dy459ZJ_1zio`68!6s8SO(6sq zaN75WUKiF9+8MruR3=w5)hzA^Z1clVBuXc)+8@e);xX7bfygR&FsIIt-gQ+==(c;S z#J*CO1qZBF&M&6TRmskZXaMOU6&?jn_(BqY5 z>Y|^?uOh;yp6w0QR1`>tiEz_-{Zu!N#(nhRndJV$7;LOgPyZQ*J2yCin+~*u!qKj# zItsG2IDi{ZH+E6j=D|ht=qWxKNxaA6E>3Wna>=z1gy?*#>|g_1^BGspGro&OWRc(k zPP)(*y0WZ7Z-kICr3#g7($P*LCjE>7S`Xh~s!b~bPTo0XSkRm2T(M`QZbv-`Imx*Ulqk*aI* zaqa*=>61?nFb8w3wuiA&zyVyGz>!cm-pY3xEsMEiY)Th4FVrtqWp%V~gxW82)>4^N z*H{>GR?m$^s6BN^M=4^iEjT7(gM(8z7K#9Sn(M_`)oSH2zHDCla&cmK)bb|4nAMIO ze4S3gI9L8AD+T9c#C8K8JF)I68NBWK`5pE`q^OR#h~-u!e7P2i$UDq7^*uZr< zbp8sR<$nYxb8EKH|BltapZ^j3+PZt_u^PR*lT6;TCNxu^yFH$j(!JXvbmHfQ>a0>O z+2k{tOWD%ln$M`tD&>+*KBKvmEgi1;jOwgXF4_DG_&r&PcxYTT00000NkvXXu0mjf DptxI> diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png deleted file mode 100644 index 2dd52620a8f15577e56ec7fe8e671988dd17ab0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2537 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 diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png deleted file mode 100644 index b058cae2f440e5a5875e45c036c99f1fb6356046..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2332 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 Kc&(xHv;P1B$EH01 diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png b/samples/core/Xamarin/EFGetStarted.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png deleted file mode 100644 index 4954a4bd33f613d45f74dc0b12beb516e3b38661..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2758 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 z - - - Debug - iPhoneSimulator - 8.0.30703 - 2.0 - {CDC252B5-A191-4131-8B4F-8983A370DA5C} - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {6143fdea-f3c2-4a09-aafa-6e230626515e} - Exe - EFGetStarted.iOS - Resources - EFGetStarted.iOS - true - NSUrlSessionHandler - automatic - - - true - full - false - bin\iPhoneSimulator\Debug - DEBUG - prompt - 4 - x86_64 - None - true - iPhone Developer - - - none - true - bin\iPhoneSimulator\Release - prompt - 4 - SdkOnly - x86_64 - iPhone Developer - --linkskip System.Core - - - true - full - false - bin\iPhone\Debug - DEBUG - prompt - 4 - ARM64 - iPhone Developer - true - Entitlements.plist - None - -all - - - none - true - bin\iPhone\Release - prompt - 4 - ARM64 - iPhone Developer - Entitlements.plist - --interpreter - SdkOnly - --linkskip System.Core - - - - - - - - - - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - - - - - - - - - - - - - - - - - - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F} - EFGetStarted - - - diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Entitlements.plist b/samples/core/Xamarin/EFGetStarted.iOS/Entitlements.plist deleted file mode 100644 index e9a3005f78..0000000000 --- a/samples/core/Xamarin/EFGetStarted.iOS/Entitlements.plist +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Info.plist b/samples/core/Xamarin/EFGetStarted.iOS/Info.plist deleted file mode 100644 index 2f4be326e7..0000000000 --- a/samples/core/Xamarin/EFGetStarted.iOS/Info.plist +++ /dev/null @@ -1,38 +0,0 @@ - - - - - UIDeviceFamily - - 1 - 2 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - MinimumOSVersion - 8.0 - CFBundleDisplayName - EFGetStarted - CFBundleIdentifier - com.microsoft.EFGetStarted - CFBundleVersion - 1.0 - UILaunchStoryboardName - LaunchScreen - CFBundleName - EFGetStarted - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset - - diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Main.cs b/samples/core/Xamarin/EFGetStarted.iOS/Main.cs deleted file mode 100644 index b2caf35b22..0000000000 --- a/samples/core/Xamarin/EFGetStarted.iOS/Main.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using Foundation; -using UIKit; - - - -namespace EFGetStarted.iOS -{ - public class Application - { - // This is the main entry point of the application. - static void Main(string[] args) - { - // if you want to use a different Application Delegate class from "AppDelegate" - // you can specify it here. - UIApplication.Main(args, null, "AppDelegate"); - - } - } -} diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Properties/AssemblyInfo.cs b/samples/core/Xamarin/EFGetStarted.iOS/Properties/AssemblyInfo.cs deleted file mode 100644 index 708fdf0d62..0000000000 --- a/samples/core/Xamarin/EFGetStarted.iOS/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("EFGetStarted.iOS")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("EFGetStarted.iOS")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Resources/Default-568h@2x.png b/samples/core/Xamarin/EFGetStarted.iOS/Resources/Default-568h@2x.png deleted file mode 100644 index 26c6461e50acdf5342b6d3de82513ad48e562c4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8884 zcmeHNi93{g-=CQ#hU{_dTcL0;WhYcblkM1xFqD*S?8_KSh)_n9CEF<>Tb4rBv4yNf z*%^{8%S?=Ydw+Azxt{Ai@B6&(AMiZSb=}v6`+MK_@AvzDKi|)H6aAZk4kJAeJp=+_ zL|xS~hCpDU5D45I0Rwk7Ry-}h4{q-(*S$?Jcf9@VJRKmHZe#2ngix+_jt<5ScDDmO zJ~~{0Ku(#Xv@V(Yk1kKBxv<~MY@Fu49nLbOemioy+euWR=?QB2AzW;<)$cP+rL@9x zE=*jkZ?2aREHi?GJ{6&*mZTRc1K(JoALBJTr>F9A4gW!f_>Rv z?}aCF#`qrmC=S+8&)S_E>w|>aXL!*;E`~zE1%c8~FE|(VVnI`{KL!8JvcHt_PxbO| zBKs2%{{s_$1Ixd>Y*-ZXw*&uo@Ax-C!T;w0e!tjqVx=@sKY##Y-=v9&oVV^G5eRL{oI4+GDZFV(3-XOLGO^q%1eb z7W-rvG*W^QM-GwQ0V5y6(K47P9wvcko-5=R#k|_6lYD zq3)%Fl;ipn<8_|Gg(XA1K5J8}$s z9-mTGl&)q%AfJ+G4!+8F;hc{QFAVbd^0T1NK5=om?QcpwlsZn30mk4^Ez?JA_@N@# z^nD{X^Bs61cEl>V-7=S=cxAJ6HZ2&=MT04lzaZ-|;&Zp3u>IR+$E=D_Ba-~{6K9*I zexjOZ>f;BH7NH&O($sRDH-U-SZ;rtjj(Htza!Oy8)yG$rx62Gcp^^8;!*qV#cP&>A zN5i>dhLlMiJVijbkN9e!}$2D z9{o7Wgb0Wxt5}Jx+`%(^Pa0z=L{qqh=qwErto52na6Av^>VKY5x+2?-6cvC*Mp(}G z_2}Q&{dmsJrW$P{0ApCxR*q|$)-ul(Zj5(&C=2w@uN2KGf zNMyhMQ8sLn+Pj@$p~iUI`9=%y_>KAZch_lH&>hZh{jpk}odOeJFH=By@iR0k_9~JG zrM`U7$jpk~tXjuy-H>wH_kWpAgjp88B=8DXvteh9icD+6qLtk_m z#g?ohWN(Gv1=8t2Rr^#!pbU%do1)_s|E@<^IF|vzDDHY~G_5L}i~j3KeTQ{|NI7lo z@=xmP(_CIAl|f=FLc_ES(8z4y3U3Y6PURFeB#8(&x_=3;wXH$CQczTOLb1UZ2q|^J zpGC}K?4BvZ7zCL^N~#g;Grf;>GdEe#N^+`pV~!Wd!i~Qb4eoe(nfQvo{4I)CEA3|# zWWark-@HZW`g$Z};BH1etL2+xAJ%^yhvrVV*sdFKr`*T`i^(N^e9e&lbsmA#|3lf0 zXyrXNXs*Yq{$opQ1nniTdHF$}%rZnoIgTf4m5Q^0r_-cY970d8ZYnJti-wqlBo4_~ zVzu(UnO<(5;(_L_&WY8pW_y=MHK$ofzXu*5-_Y~;I#x^h#xsK^J+i!`^7c`fNwX=$sXy0D<(84J>?Q zVqLy_$B1sn=*EX5%3fKG!uxtZ@`h~#X3Lrw=SO9a9cF^m81d)i_k|f!FvG5DGk0BB zuF%NudFjN%L!Y<&+XKI3*1cIGOsx&9G@f?|UtHFh-FwR9fR7HgVnsVSG!)sEeqidX z8YNjM`2N`HtNJ=wGD}=CkyUu89h#qb9<$9EEbX#N0*$+>YV!zrZyu)rw z9|SGyyp*7|bJ(Z=PMupIFn&;eIb@W4+9Q)NVtvB;_RW2=-|P)?f3_2Ug#4fA)7#Lq zAzUxceTRQobbv8F1Qy(!j)N;g_q9tv|SF(pCWHr&K`EZ{hWq$sUVh^dmY8} zlGXezzDpQLH2_`^MIn%8o){Hv)hK7Wv|nAI z_io2@J8hl)WVDG@$WLh;{T9x_uufxK2;1!PD?CNweaN0u&JZSoAP%V4syUq2;3xSr zbD2izx*MU{vBb$*hM2zg zD$!nbmfhIpw)L|N#Tu?wD?n=|<`t>upMSeKe2tHzuBPl{E#>vQ`HS5C5b%SzdBL8d1y=_R~anb?ZOp^fmIze+pZbD+o1%U!i6s+2y&!<`$T-s zQD}fq0r)q1p%z@Ls5Tj+CSTI6b3AW53H!$P%vj#AEa097Q)fJJ^+BJw*{{-)&7JF2+($AO6(eB!>nvVV9R-<;UezOgj! zOf#DR2VaAQh0oTh6*qUm{RudXVaHAT^u}bd`UiuEoYCZ40YTK)Q)@^Q{zP$Ll<=yeea_m09z^7_3tDY->Q z=2i$g1~ucLKxNF7Z}RR|4Zu$_;^+-L7BB<3VmZUoj8K}Y(OVG&Pr)gprs=3d13X^N z-NRt}7B`F`50J!ow@R6kV@i$=FB=B`sM7au8TAaK}Oww)a|7DyZWxzUI2rd2W5S<~#PA%@VOZkCxxbZxP1=JYjn-=-1D;4GEOiXlJyhCuGWyjOU^@EmVF zU*;T6P5TV8fi2aF*-D;JDnWEYz) z=pU4LIDJ7q4ahV|2f7;2IH}sl9xP_PY}6E`iqRsi+12-?7NzKfF6u7rD-YbPt-j`< z{s$EFRipdOE{BSbE=z&i=c(uwkofV(LfD=0jX)T42?AL?Y)3dVO?(=~$HAwbhsEMr zE!eD&Xg*|(-G>Yye1}P>m>}id?)lL>wMP*lyZL0yL_OI{l?Bc7-aT(s;k-7zL-5S^~c~L1G5*~$yHf}oB*?Nu5!&)Yh2EZd)H1?^>V7523b)z zx68TVBX`GAo#TEAZyD4nLzQen=W|%0bIbSRh8%?b#)bul2LS$b@y2>&w@Hloeo_ts zSz#aB#3DX7;T>S=9&?N_NR-vSjpj1~naAMmlF2E$f8}zrgZ0(Y^+@gjVPlsYF_3I- zzI8d1eWNBxx+DSa!$|d>cMM^y=(tX8<%aoK4)t;6gV$3w^G-f3kLuP!Bv{ZAm_dOP zpN(CP<2rX=etn!l&e8FmMEK47HOyWL^{~AvgOi*}jH91)BFS7~4k=DY3D>^5V=2_Q z|84Hs3Ac*q)k-guD|{T|vwVx0>TJG~S6ltm5Xe=;m6XRexV1&`69?%d?rdHq`!&Li z>~b())_yvo_KyxK<>U!~G#MrGhop(yD_`frVjR8Am`fC??i>lO#;6@CuDujyc-e9q zHWOZC|KjB48R1P=r$>Z9FYol*HV8EG5>a}wvD4eme3>0-+4ccm!u7Hm5&cRjd#mHx3wG!9W@75h5F>PMTgMag!sP7o zqe*gNtbs-#7gRgc!{lrQJJ<<-73FS`{L=@@o6I4dBQ2D5yu7$u7h znG}({7L!r;d@HSju-5%Z0iI%#>Nk+LOeaQ-0MPR3g=Lnkw_J&l8V_6^fErlD? zo9fckOKi3;&L6H6*1MITQ{yKv)|!~n&eD1u=)txATgn3Xb3 z&-9*W#L?I1EhnX5kF2yUqloLS5zHZ8y-t~Fe2f|r!wr1Z0*+$>j;v_xr+|BRB&Q}X z;3(%eX*ZQ~l=ojx<>ZZRGLSa%9X^l5A&_cBSAE{apHD<5UJ!O(DM<`p8_bNr(8K{Q zsf4YfwsrSTM;*?|a@H%)f}~J4q2`b=hRDDN%@sG#T=AbBwoVEo%gS12Geu5IyA};UI@mo=ZJi*;G zLv!L@RSAt^TT;%M4(YD)Y6}F?BYetYwerk`=j=fX81;dfVsemj9glL7R0|6_Oz?*k zN@cZL6uHVUmv4#tLKy` ziln1YoMlIvVjn|F>l$1aSz&sYneH4F$$^&yoT5lwb_ux6A!b{qIEd!jzUd0;uCpx3y}1@ucw6jqc48zPHY7lCuh~mbCJiSrJ$X?YP3-^WS#Cv?EO8wL!p7%t9Z-@&7vx&kO>YwG)y)A3D2*?HJ&tfNPD%$02gRDGB zK)8|N`pSHR`2yIGifmc<*6izpYaY6I7WB0jlSH`161d-tr(fkWHyR649#k0Xxk-zM zn5bk7d92hNel73;Miuv+p(ma%5>c_Oty{AK(qDWs;@N_CO`zaFCmRHPteM-bCx*{$ z(L-~!Do066Rs10eMJ3+=zP$}@m&>%LX00FO8m(?%JO9P5+i1)f({j!=FF4 zCR)Ri`w+<4U(GYz45u+Xu@@+cTM#wiI4VJkpBq;!SkV&M3buPW{saC5K7a=|F)YeB zqah8E#RBTlSJ)yv193Az2z-$jo~I=7o+f;XV@&;YI?MQJ!jqTopkjHAn zK#VFg^YNi=ipmpkRoXy6b5A8@x>5z;3^tAVTzLKx=I2Les-Y!{*i^aXsEAx0f6sm>Qf9hqlAyBpv2J587GmNm$*U?# zjIcY`1WKZnI*%ImJc2C-em^;|;?bhu{dxH*ZA)0eD# z>8G7P+Txf+V0x!Pxo0tZm5+yfZ`>C9g9@6q>j9M}(WgCL*B_V3Vny@h)cZ}fwKqNs zNHm3W8Gm%cC5fE74#M=*DWOKWC(n`@KE=3FpDXlQt` z|196#of2;3ddT(gx7RHu_+KMHb86izT@=MWKb@T{4TCYbJ!J2s1j4z3pG>e!oD^>h ztKI_XIhMucir7ccW1zBDOUdo3E9>@G3qYZ~*6j#dE`~a1%p>Fbza01!O{IPUm1ucx=X%RU?(Tc zo!IVv%?CF37O%CI<}GJgzcE@xK|mt~ZY%2ZY7G!_e4NKv&`d`ad+ASoJ%;2KvH+k_Q)jT;nCru26tP2gOo9I8xp6BgQ9bTr;05J;`^ z+(g;p;Z1I6qfDS# zwROy%Wqhi=r1B#ffn<2}cK&%jFxKtuSV#-{#<9_he?$PgsdC;j5{!3KrU3(D7eh|` zM4T(j1m6j!4`6+f@-Yuz6JP%4ja7%B?WzlYw{>eyOtQWTx|;G(*hqr zG`XX6LiWdwwtY)0H-aeP$$a1iQ-uq=yD~&)cc~@kArzeJ+R9GaM95L!(WbOz(4|m2 z*hjXy0=Pp8%QgQ$}14Cp5B#+nJGA?{N>Lj%9=K zT*)Fee>TId6@K{C3Bed3uV$^z{cYa%Peu*@n8p3e%96pz^nXnr|90Ac`6<)ir>=iH z`=0}+e|;4EXB7Sajp40f|KW-MAmsl>$X}H4k5TPH%Ml$Ck}1TO>&3^e4E_xTg1Ta$ K_2x1xB1HqzL^^^>5kwH_y+{!Rq#2s1R4GzJM*&f(f`CYq zCLIK%gkCfV1dvXEBzNO`)>-%7_nhyZbAFt4zi)l~0ahk^&z?Q=%*-=8^p?i;qjV?f zAP~q=l^aU8ArLC?Clvt!1HXK&)luLV+e2l&huY3I4?WFYtsx3l&KA}vmHXzl*0-(A zt-M{@tfe6kJ}(s|1s$&u!nlmO(R}*UbS<-){&FLV;FQN&kZ=#HQgf}q}%)F6Cr{v)hA8+Kn{I(>nm|8A)YH;K#QKO=0blB$` zafs-}5n+%ukZ%{6x47SpnTV1T-2av941p|s4^o3b5I|8V9D)jfK;TG700ag>%0nP9 z1VkPJ{reyOBQk$p;Gf*&FAMy6oqt5je?;bQ9P^(y#s588{!f?sw+;PIc*TEO;9qmA zg9ZNgYx(bW{z~{i9F_mc{s*DDu-%=( z)K6u7siMP;Esy5sA8i+xVhFcEAkIHI0)r#tbT4_#PLoy=Y>p)c7L8ywx7sLVzP(&E zXk`iAk+p%;Pn&WS7X#7*1rbjt^145fp`h|m;=vd1c%0gsUZIGyt#h7CT>nKLr>wRF zY0@K5=QCQuw@XH`i=PLiv9+W|xi_{*`CH|?t0UnK$(3%}RF5IB%_lTqjpMf+oD@ky z!!*0Oa^gm`K+34=ts$Ni-7;tIZrWOyBE*B7-@h&^EXbIV9!lfYdHAodr>JTKN_fPs=(Y8AgnkRtD9n? zj?^6u9if538;6oJ?s1h_+snOY%}H}Ou4i#^#eBt9Qi#*Y;G7$mx7<@1bUnX z+vzfQ`o7MrPNjyzD_a*@bhN`d_w>Oj%)rf+r|xRJPh&^owdr68npO|DxIh1CHe7$xE=2&$*6!SpKfGkOv2o`lWlJn0anRc+Ifue z#pv7yzWw4OEfk(nbCs3+vH@sbeqcMFcVfOFXOv|%Cvc*rU@#l6o3luJv z@O)fPUuZjNWOalEjx0+Uh&uH0TdYJK0`=x?l9Ys@hHq|RH$7sVcpai}6n8u_Sp*ga z2^?_|gkY(H!5`iaDN-y@1Gi)JkZTYHyhfy1xe8cuk7WsW$8D_V=i^y=Da`mW^U8t&EYuPu{M=+=rX zoJdVqbnSz#Dq819b*UfmoSkEpm7-D;IGHUR&?QOQWWP3>f=?UYXd8@@Bu(ode^kOy zi;rSiiQhm>5VF@CcLl87GVXr*FT3|-&-G*x{m9b;Qekn{zQT} zpm}buv6NHmi$E;6Hy2fDpfWcGe{sH!IOw;`Ft#{;wP%BK^d|?NboL6yI-)y4``{Gs ziX4kPdj`}r#XTd9f*I16>gZY1RVK-Gm*g~jR@{L5z7p8WBmqE%%H`DfS|NWvDVvkK zi!T!6{o(ua2rT5Jw-=@AHrm&j`)nSO)<{=Q^QzN6_0WXmLJqGtC60V3OXV$E$9t0R z3FH;??qSc^5(;yN+cD_TA)L$vNCVv&3HdMylhZW&nejIBbBr16Nb$J)uwiyFQZhI-RHH6+ZoM!)=`~sMTmj|hl)V)21%M>W%B5~s!f*QnvDZTBV{Y7o4{}x}Dk{#JY~7J+mwQOG??)kF2%p1uXNJZQ-V&lpni-VSLgQ8R zS`!qpV+R3acG+OvU2;>#h7u1B+U;a8;P7#K;lAy*UL3>MFa;DG+2p{TRkllx&}XWf zC?Le_U~^VBL)VTsw{w2`wh}4(w5%n&Z-@C-m!fl4 zBCI|%>}mPdtGe~Y9LVS;vllIeJ{Qgvc<2#DwWS*QVsq?Ec*wwg;ou?W{<8;1K{?}= z>bhHmgOV`P0>#ef^u6(-{~s z3PV5NDo8$B&ls@Paaaj@;bXyWC){dV`UqaW3AGu#_$d>l{5PGnTzwxwe8g3>j9sF) ziqG~`S1D--ICFAcEJ?4kz6KTWCM{XBbVsT4T=XflYBk!TvyG#Gc*v7vYWSe}U<=mE z{erS>^#Ky}`lPsrrcK>WCxwFFzIc8S!@K7~e}#tw3V%}eNysj_Id_QL3VDyzY>t+> zFy5@sz(#)0ur|k`Q=NMaQXlZ`*VD)0tzi$u4vwNT10DIvK|}Bv=6tH=L+|geU;PdU znH>lnZvP}S)h<2iZ~Tg9b-rqQX(?pLqgzofs$u|W6F^=w=)q+SnFbzrk=N^dI`i0T zcYiJ*bhMnj7l;)xl!s`!46^#`>jn$&o$>JKpD~Rvc{GBPq2EyurtMEiJgUYhKP4&U zDcr9yRK=smM6p_I3CQR(U9?gqCq9k183=imJoz%c6n(~K#11XPw*$OqR*K-^rl3}; za-ZP>&~h`qbWX&v+5$M9i^bz9M7LdzxDnMm5 zzc&Di0tx+)3v(1_M?l(1V0hI*R)%HOYxy!J{w~96n!!5`h0pS@W4tI*Sus@R&WAyQCqsKr z&MF*|io{&7+D_~FixW(m_eCCgvZvR5O6@A7KDP%K{^8k#3)V<45e4UU)sNOa8D>pI0E&c+T%oe zIc8pE7~K7n%Z{x{dE{@d2buEQ=s^wg)Tr69;M;_37#loHGHf6y)w^T2@5D8Tmg%{q zFGk-3a+mV`V13!8Da$pFQnoeUbJ;>fC?FVRT2B=U;Xs++A@|a64cF)O0 zxq+}>Rh|;a&Rtg&JI|h3?gRSM$i{MVXE5n2_#b2XFRK*8tK_Gz55!rnh0>= z_2fOEg?8tp8fLFg+gn^w!?)tx`(nFg??X_f6IK;$$4-Uw*^r%e!-IW~By5&TsjolNSjUdPL&`_9G|EwXmM@>nzJtm=oXcmkS$B8Y7qfSM>aI9n!49bT1;1W}XpPu@#JM!e zHM5kXXF!cmyYK&NgV-Z1#hGkrNY~8^%3aOSlaoZt<;1U z3V!h+Nx7+>#l$auC*}KVXMm8%+l35Q=@Eu29De48nb0u(DH;SSbIf9bd9yFJfHVY^ zYYl1uO?Yi#X$sAL9B2+Gve_T5VBXeg1HQnNsa$Yznp7pc9&rWOu1XLFLy%oL-5J}@ zJL(Sx*ECpmo0Hso*?#Pu^Il8=ko%TE+8{_HGbL$QYD{$GCRe~EfITxZs;hCcoGVIIw$T|B&Y70x~)khg=T~7^ZC-I$)g!% zz4_DM{jY&`5q@jDd86J|lREXeQ48P1HJ_zY0^?N=Im zTXdT*p&#twCf!3FNyM^n5LHh#od-D*TMTZn<%{$77;bZj9D7rWaWqiTx2m^Cu|bt2 zGbXlVYT_HOZ5Jm}tisV5H%@xcFUA&dk|GitL>lG5M*NtOE#~~=Jvfl1MJj8r^zsr; z>+YRNQ0&xl0p&^a>!RX@Q7;$PuWwl-Ux?;q#78TjL>`Bs!*y2bkn(Xvw(d_U7NFi0 z?!iS}^l0#La5`gV+C=EKH*E@Z3p@o2aqU=WLEU=MtRA9ojCJHb%d#)$SH0u=xvmd% z4msZD&5kP1Ab~z?aQ?OX=gh>_L1$U2Hrca2jTN#pu`SP6f@o2ToATvj>k{LiwRLFR zCtKzH-0vHU*?}z(Ufa9{$k{0|^4|FaY{CY1E=fG5cW^AH2a{3hCSqf%MEmr_FYh)} zI)E_3uZ?>~JL7pbq^tcU%v7pH(aBwDS?TNG7&?rjo1eOjY{fNogy{SKO8ZvS6;V(3TR4jR6qEc# zt?nfn0#>Fmxzgu{XwTf&=g3+bMuV>28X}E9 zL+e@;6$`MzkFV2b{n?sUze zip?DlGy*t;O=GZ3cx!93JZ6;4-m{mxQGpjZbp?$nn%FG@Wo|mP+Xs$I`|Dn-d#$GS zQ>QMZ_eZwS+qQ;&RD#r-rk8iowB`s_1q0lr>Fgj5<7z|J8L2du`@M^COfZCB|Age) z2bo{_j?UMstwWOH)k?og-%O75_GkGyDBbbZ!X;QYF zo^VzSD&Tx9c3?!TS4|V(HrEMPPrbU?K1ZgnCg}7nV{l$Maeo zbOGn;)cZJ(OR1j;m>SDn!rpXvcfkg)dX~*N(qPvw9ZMYQE;#kA<&v2WfJSR;s!xmI zN##tX%%nUH^u*yEzV3o5*&cCFakclChp2d-M;PhrfO`dcB8dif`^1M zq&}ytA}U{|HWORr+WBxckFxkoy{lZiv01-26cU)%>Ll`|2Ym+bwRG*$2>-&b9$Hc} zaTdy{w!Intlki&OGU&2jIxktXxIJwJ6=1kOpYBzf#~=lKIfsr8O$VLUgQMx?b%J04 z>{Z@EKttwVR1&?_Y3IO0*1IBq6bc{uu)R=F)?(__9jU)7+oU~-cJRJ96EcXU8d6gjO3S+eWRTB7~pecL)K2PlorE=OWQdT^xlkA{T; zrGPXbgx_;qD}5dTy5i{5EhLPv+INHXW6CB6x63#B<(&UY+o0w}kfvz%n(d89Md_tf z7-H??k5dMeJDu>j0lXDku)nNVwHJCO!MUnC%Jo6xdsBes zPkJ{QEXuKqD+1WKZGN$s7g%3LcI1{r9EK|d5@@v1cdWyqarvV#uiEzokR_pK_0q;I zEn`W1(=C&LI87ZkyDwsutlWuv<=wH6E5<1t+;-@#I5l98YVBovP@q!3&Sf|c*Go@9 z=rNhDTlTQ)10oQyl$JHZQNk+HW#MjK^5VJ9Y#7h){>CtG71^3R%?U?7b(cTtzlgPC z))$U@IKSteU=tfK#8|hY{`d7Dp;Jic0Wha5oYX$n~b@T(vOok*3p}!h#W2R_-%nSO<}rVrYA+N8 z`rcamsK#y3{qG0+mt1SWIk#ka;)sLriY-2o(OTlsr>xp*CZwixbUt0_n$n@53JiVEVRZ+d}T6(wAum zc4&Az-0IUw$iRx6p*wFgmRE`~%6Wn*JzumW2^h@th5So(Om3gQ1MojFLHyNmvh4=w zaPivKLF&6y1~wE_KxXtim(sRnQDIv3FRAoedL3L~Q+k*1kTsS_5+I?p?pRXd1!rN) zqIrh_LSzHd4RAO1t*1U?-NszqJr?#NwSiG@{e0x5zcBZWpmD5tL#Aqb$o?;GK`H`` z9j|(6c9py6O8u`r-g-tEoP*d4Dzf_;wO0k zzhk{KHwox}Ff=fJTsOF{Gj)Okfm(P~eRc~_THaAzO{vscXP~k59fqm*Tl@gGtJE%a zFJqvGf%2<@DE4)s!RkJ+e(sCsfUZuQ6!Z6@IH?qQ<4n&tvh15r2g_B`>1-5=?-o%u zbQ12G=_D15PPL!j1C>$9yYF^!$V^q*4p8w$@_U@*Y0_K&4x+I{1OZQEa$^P~ zh1R=&@Ir-DMoqZ)rlY?N&BNLgeAr;c;9x?tApI@f@!`@OjcKopm*u<^AhC05jAy7C zP(gEWI8x{4?lS2U+Virhtwh-dI}{$j?<7&tErfT56>MJH$N zJlfaO0C4K|-*IFIwVAh-8{>Pq>2Sb)OI#zrt&Ct{h64xk+cK#s<4zyBBDFbg561N0 z`az{A1J%|9Ma@G-AgrxVavY{a>;k$~n3f(2FB_ZyBy-ui)gmtopxm8kCa7;!{Pa8k zMf;vb$U>uoDN_E|DQEbb(A*w>@l^mg`^spU_uSa_MQ73j!hwY*hmS|LmlAnFuGFFE zK`LnZJ66$v3S9?Df<7qw-Qb1{z@aDw6u(^-=H9#%_~)-izvJpb7%G<}1M%>|{9~^T z2CL5P0N^WcU9%J*#BY)1FbO7i4}<|Zw&-*!?hmVj6uZ#v zLg;=R3Fazgv*Xa5^7(I`K#ZD%%X+&g&jz?d_uN{rZl3qqg1Gec^zMo)d z?nA;H808f@keXletj2{OGX_%@h*yey=m*cp)cM08g-rc6JKr;4_M>hYVEUBll`GE& z=3pbT0HLs;qa3xls_kf-Te}w*2!ZtserpHKf-$%tAv2r1x2!-rZS(Fi$P^zuQ<*ds zWN^D}%3zd89Ji^q&U_&LDL9e@gTf`(UOj%LGFjv7oU(TWhH%9jQ$1S){p{;Gp!*nT z(;^CSUynCTpf>qZ~SY7V=vHu#%go+OXF9`Y-;eqB7sB7HD+3OCz%cy zW%US5SSiJ}>bCxYF&o?&CIHC@riLqoVYJ#LI8JfC{^L%ee9ts>T7cO^lwZmG{(TD| z_uKkG`3Kfl#0Am8kw;7qJpL4u)|INaIV-^FP}|v-+uRoRd-Lmw2a~b$bk018;!4ZI zuE62AN#1Y44fug^$L`^@qkwJ41F`h(ww}M3=hkI?(*8DOz>U2XG+SS#MZlMC;V!fj zS--DVuB`#$?6?7DuGI=fb8lt9@N78P5Dr+LH;-9$Nc$E3Bnh_;FgBu5B!L+l-IzR{ z%EcP+7I~blJt1lkqTR}AYlcxIA^510BWo+Ki`)u`xR42Vy(OcxoaX@1@C^H;Ckr(Bct zr4$!-NT5D7&EJ1Y^WTQ{|Mj`WzxS!Z|KY*U-_`Q}zq9$%tEqqQ3zkI4KlEbj&lmXr z>}#xl&Hf|Re|785d zgnbOo@+QK^R!?1X&tvWmo|n&Dv`5-!-EHlO2ItQ>+MC#)IqU0DYp;&b^;-ry+NM6O zqa79Q{|p6wm{NQz%;EE%V>LC4jn4CZcKW-s1z*OGH@ljo5`QPG(%lQL>{&h(e8GM1 zd9>iDGCnGj^Hr+n)Ag9W7gAV5^Xc9P9lVEX)3}01p5{*2uCMAJ-vKRNXOeo{#IzyBa`{{1B0{`-kS2!H>MN0MEpAy z!ZZJU@ZS{ZKUpC3A1)C3Pe;&y_5z{*Y$rnh`4RM=Petgz;NZXD0K&xof`k8p11wwk zFPZo+H~<*@7aaT-8~_ad{{{!I+o&#RGHI6EyR+oGPeKZ{qI-6Qe!$;#AKLk`I{!rI_{>o6Q5$rr8ABip#K zz?!agYO(s7p!+giz2ugntCVSJTsNZ@ZDRNXZT{N%P(;xO8i&J??5@PVmi9hT9FHo^ zq&$2y_hni|Zq5`ATGu+lwm27|#m|N~4#2v$v5d54NB=J;w9o|$G2V*homAINvt`Na z_c;*Kf&WpyO0&B;JUPI=j`Mk$cP};>o{3`5jY>4Tp350sK0ilSxj&9cVSV0v&RC0P zId>&^DRDO*24IIbQuUvInqZu?=f*yK<*wMGfa9<4skLORPf5^@t}WiDos&eQv?4nO zq?)Q8`5<`lm4L9jAOn&$u!nnZW}%u{8<4xMP1aN ztbOY+H|0pP!tPjr3Dp}~nIUxQ`9HHOYr%{6ZqU#xlatAsYb)-poJ`0`7H-}tb?8Fc z^6W&pvp+pLHTL5k>3&+tbsTziOO}EtKc!Z7-p}SiROwGAmHQ$n(ZREV?_tLG(q4%4 z+-H%UWEMB~Jj)KD^V>n>*}s2lAxjCkr}Nm&XLrM&QaW%DSvXC1gD;F1*aB;q!M(b{a11#LqV)Ga6Um@ipu*AkbS`a2r1XP33%@&m6k&fruz^ zTp<5AHGq4+a4RQ{vM$+Bk`;{5b5Zz-^l|r`<1_5h30gR+@kkfQ8osJDd^3&E370*p zvkaoBOewuN5XXqJVqtvN;g*H2#}&w&HIWhix{f`n`kWnHI>&_i)G69!XE;!0BM^d> zhOswj^BN443Z1FiJK6{x8j$-3nHT3f8YjrIBXn*DdZ`L$f9W|Bo*j(3&#OE+VEqAy z4)qz*A@j_UnKBph3qb-ZP0fnF|LyW7JTeymL6|2@pXja5U=&1?a`uUyLaCF4mU-Oe5P1?-V-q{Yb z{@%O|nTK5*oLKZ}BO)8zIhQ3IQpdzAqqDDw1DQuI{mFoV?Bei&Zg8QO|JVo0j>w?Oz&93*X#70c z{Z|q~_tLZSU$@Yq@k8+I@$;Jdb`g;IE{ic7S`dRL3m4}{4QA-jy^8)@(S>lhqTM)z zitcZ0rt)TcO4td`Hifi5tPcj71(7$~2;ZzZDcJF#9x|FE#33xaT)7tZB3 zgltEZJ4#gZd4$mgHSC#mZ|`~cfAA#M*f}57c16(oGEj%^6KAo3D(2(+baKwOY?XshmkNhe@>5lyz$TOltr4iV3SqnBq zQj42ga`3bP1gpJy$cQ?J`nF#w&_<*~QPG7D=LAsqbL^7UEEC7J;?b-2IxrWNYS<&Q z1VGPGCbVq>J#FA!Fql=C%yVy`$MYbd=Ya;QY&*RTq2Rv%iyqY!_0fLjo zY{AZqh;^Tff}J=}{iX3)9CZNpavqO}^`7Q!o$ScZ2-Zz{XnczehxWJhu%qQ8@IXin ztU6%#&AGJ=C{xqmN(OT`07EJgbOe{>4hO40X5U5AE_35R964DF%>({`Weq?uiT%gJ zb3fu3aj0I9@5o}80uvhC3cK`k+N0_!0>5Lo@2Jq^0*Sb{FVT^{JsNdC{{75(*y3*c zHTfHOI<&SOX8BfkkP!@#hF707td7ad?`%Nn*cUC>%EfI8+s45j&R&IE);K!9Ubc0c z0Q`A+A8X}F60C3{01bwJ9w_;-0q4Ot7d6N^tcVf-kelr}82qGouh$cHRBHMaFWJn9 zNPDo^E7R8DF5Na({jJW7C>P|}SDu5y_`F~ADR~2;x(KJ{$O!;BO&)hB2PfzR^ARu` z)53^Kzt^sxxKxJFS@4WR)0UYoi$GMl5<5cgNRK0lORJ-+#R26b4noN1#l^AZa-I0wYb@_p-uY7@Rg^p#;NRu{L;%qdB`j z%`u?*BOo|W)3P@wEcY(*A@jV8Ws2!47^L;#2e%TUHa~>3ygc0J*Sn1AW4&&Y03tCa z{tqeOhDL5(lvF_Vve-oRuAVlqrlI8$6z^2^uqn0*yZh6zBl9;G*AzFP;u!`|*=91| z{TC{elAlhZuS7g${G|&W>BeczuI#^Cj7~XyBX(p9qJp5&VBMyLgI*rP*9DQ!={_0C zMN6;{;6~84-!cB+(*J^GTelP*c~*Wtu;2m~>C~Bk(vH(GXbkK;i80m~3~}q(egLtP z1_6PXr_C9A;5Qco8)a_Ue=&XhDOWDJK7e*|FQOOIg#+YinHo zm${Ca{geyywO08hwIsA(;kDO4VkxN~BVWc|-@>)q&{%)h5H4Lp17{zL6Sb?_8#2Wc z`ND=n*RblTUX(;6mC=FYw@{S{cg!?<%Dypkxl7Vh{$I@&q|KHbU%X#x(fYRI@pAdj zhspQLnyviH&XrAk&nUs;P^`l^r!XSr!i|z}&a12__DjvX1KNlZdIv5jG+ebfdZJ?s z6QY_XMBSNJXF!shLA@kz*Nj=Te0o$^p!YnXn1MqOLK9B4qlmb@eF`mfl!jJ+b)V7tLh@BBB_E z`5virN0i@pVHExLV#cK@f!Lsk+N4QVK}H z2MmLP=((8~*k04So5$cUZtM{u;=7&qI~*$5GLsY!S9k?WN9dmM$|16z$MVsM9f)7X z*b4E#?33s{nXf3qfk@d^J;8P0Dc)kT#JTJ_n4h{;z8sM>bmb}W>^O8~J2nM(YVbdS zjA+<3Fvx@h*^shGsFLED(4~x>uORK%<+d3SM5V#@ZAd>yz3GsGJf4EX#zDJEt zm8rokX^6n|8n1FENie&c&3Q~>R6P(4RS)*{#X)!t%ZpSvW-{W+6xTUuwcg;Acp6&+jD^@bvOTOPzTBk>Y8S&O28CX(< zh&_MRAEpYERIj>tdGCjqi6QF*s@$Yrep$leksA{MNsTv!j!FSU!Q&}zi zpmG#kST!v^7>AtUe8i*qiV3n`d~o!L|LGt-$BY6ZYJpJoUyU=VqRRUIGl&#)LLL#d zl^*-6dYKVHO^E$x6ou)~G`1tcIqyUqijT&T3@}wQ0x-Aq`dn`i9Z_8W_%k8i(oqKoE$95F6LCE8l?0&==nvd*GPcBQ|_IgBVG7;=p1 zP&wu?f^6)5hrs&rX*kjlELM5BPIEb94TmUi1W;@g96R8{hK)fA)^rpT49M<-O>x_> zBjY2MS~IU#g69UjP4Yyw73T5C!-!N!GCGsM09fZ`Z$afEytFc%yUlM;O1G(%)mfFU zn78qR@o3XjezJM@tlQ~*J|1z2rOV{c$y!NojcG$&4$t$sjC${^B%FL$k$hfgU4|b` zss-;}xJ(=G3RoWqC4;8~apYCd_-GGElLxY`gTAbP2oAJrqc46DPN<~KetXF2RG+FZ zy3S5prqzD6NG9~krcyMq*TM=2ta zcGuCG&j8uU`BtgR^O+YP4V? z=Zo8yHPg7aAx|F>e5G~PS7#-C&2Q`97QBc0UwX}+;2_?Z`C0JPcJm!`)3!u)Tg}4N zv!@}bh=FT({Y&h%Qm^iv0Hd#Qk3a74-aV0cs_Ck5%f2_aP3vlFMW%21TIMV6Tv~5jq=NS9Gs&C4~Zi^K+kQL{*=zn?Xbj zGzG8sYB(r{$mIx195gw@HoC3EtC}l^(z~)d+{cF5K+y4j%)ZVi^U;v)9H|3vPd+qqEA%^^^d+vGCpu~pyqXz>PGQ@ka%<&lS|oqt%QnXO*wItH zQ?9=h51kFYiyunqUn;LQc5$7Vbkx@8?#((YUB)q^r4fMA1@k45%Llpreg+01o<~>I zy|oW?=YPyXpjBu27t>yCqUb|1Xcf^Tu zBq*Vv(fufcKD#g)CShXyg?W?NL@PA(`VpSmlk(e3sa*UE2I+}DcjRfS z#%q$HvhMdTC!ZrhF8OvzOsK4HjGJPZA8}hd-zQFvm$ri$9e>i`Rm`s?c66&~+5$>f z-7SrFe%>$hJ|)+txXe4I>0AhPSIS#2rDE|4eiggbtJ;_R*eN?_uF_HSMn%rXEAbvK z^qM`$kzPONx)7W>w`8DgBWYV+^lVBA@z@_HPz?P7CT>|?Ws9o`9U6^)wo_H&lqR!I zPyCYSa1Kd934Gc7>K2rF5RPhiDnEjw`HWP?1EZE9=Z3_%lVU5A?F^Kl+u+bH+A=;) zZ06P;6+Qh(2t+I28CbXZ>nXgp^H{Rg>lpNhulMP|9^GzH7Ia(`lD)pH=f4d@vc3-M z-f364yqE!hP^`^k?JQC;D3o zzT5FB$3`9eIb<6!+g@`?5H0J$4q3`xMmZc3pqY?7ENkWrg8aY9x0Pf(mPrZmQpyvr z_+>x#CTd_0n!OL;i+kL}qMKT!TP%s=PNh&~ye(hU{)|2K7MtsB~Klumf2KK{1#=(G9uXNPU4wE7<+@(FC-6G|MWE6KY~J$U%?p+dv>)U|6T zSi}TO^`5v)M|cy{jp4_TZF|gW zRVf!@_&mx=F}c|vVw^V4LP*61m3im?I2U3wn6l3+;I?(-6uG?fZac7gg) zV`Dj}EJ`npHsHu#{N;UfXnnPh+7JK_^oZ68HUZT=)DU@os#izn4$HfyH;fpxI)8M3#)l$(t^vf z0>;9RESYui_9p4?+m#GY<46s@p9xg%J-k9J_&A4L8OvCdC;d?Smsg_L_xu~GXgO*Q^7%t+-0kAvn1j~k|sDyVzucJFz z@PWOt2E~}#Q}@J9(oqN1Q<3B=$SP@zlz!bVN4)U(%sHmer#1(Dkzv@{{p9tnu$Qoh8Bqx=97_AEW<|F zycis9vOe|5?bSnk zOjrK>iLvfy(u|JTqtzwR_&Y>iRl7%cRnZBYq=2*x;y#$>o1jZrd;(5eTmLMdN=C|! zs@LCl)WW?o;a9cm9PO-FkuJpNq%&E+Wa+JWBA9qN8>{5Te|_2H``1eHKcwEapf`=?VpW;Gs~97Qa1V749pC*kV-l(e=z0{^Kjc7xQl4mh<-dFz&W^&$3xBkN<|~j_t|u z12qAB=z4Y5Cd%Veg;zN4n(OQHm6SY@Qdn&OS+z-^kMcFiVtpSg1NbP7;3RCEQilE} z^5L^}`h|fI-Yv$+HtU-8Mt9I|i}#l(PS8`%C|shmacW|}J}zUVA|on#)3P(SO)x0` zvR{iE_mLpQ@v23-r)^jSgxIcuk{!rZ-<^a7V?^p9KgXx}Z4bM2+`~HT3TRPk3VXpV z`>(U2E0EJvR_YE>;`T)_UEoSgEV6_9^Y;Ic;|^I1n9F2N@e7v}X~*}oQnY9O;3_|} z$Hs!&ms!2oS$vOa_#Ni+DS~;-43sl3m+_S(NVaZi9r!k$cE|O{{{5V(*1uH!b})t8 zJ_?^=D0&mm_#uEFG3bI@2-(O;>kmK*Y1AY-tQ1_v8z#`mrfL}}e~5FzMw5-?>}x@= zu}SfMx%{@?;uEvy2f0bV)}KtO5Ap)*llOVd{y-FMg%~;;n+^Lg8*&jpWXtC>%8;fB z{oam9r-kL_7{3O(85F!bZJ~VW5 z7c!-TD!{AKzw^Og<=s-sUEscs;nF@1ar$#^3Lw^-XA=vNus`u zReL#mnH9oTvVRBBQD2BcaxJaKbmrv=M~O#82HYj@zgaZnk7_6GGB$%-sfp&-Lo@a$ z^KIL96v$O@<%j5vw>O`Kg6D77f2{55e7zA!nV`~1PbnS82 zv(PU!=_JuG%br||N5gx4=N_+Vx8|$Wu-i;N>ZYSwt6QQ$R#@IAc5?7mN6(Ku-^EiL zoVvSBSZ^!*V>F4Ymv^{~W`EN=G;Q9`zv~G7_iDE(%tq?ak0x5Z7F3V1P7C)rK(q8pu6ONFb8*%McV|pyP@Z?~-vu(4_ zs8CwzycTU;gqf0y|0LPpFs_IE3;-=jr*h9Rv)E%%qUgUYf**c;KtK01LA^O)>=* z%r~9wjjV5(CW_~QoJA7$`gx?!Iid0 zz2t4aAX@+E%1#jk`s&B}jnD{xrSap_5gmVWpFiqR+k0-w(%1WnqY4VZ6j9}MP5_F1 zmswqY7K?u#6TC;)RfH(Mdr&|e_BH2`;AD)9kqiNt9P9{(l;l^ZrICm3Q1Z-Ai4gq& z?+-qR+qy1aqXbvP35ol#=6+r+^^)bF=d6g{FoLf%gRMEJS8Y4D&A21|z9AgtK1ce4Uj{`xL+*=uKRBmk zA@lHt7VG|$qKV#h#!nym1yQkm9|Hv_nsmF55Woe6D{JDF{aXdFD$rjXtI^WV^7`Ih0Cbd%HeRq{m5l<=^ghCjDM~ z^oyOnj3lfI|0e}THYaqvt@VzUm(gMWwa4ZFk@^laUv!C6 zcPsT*oDofTrth!!S-8~RO!BH;J-t;61yxxHA+4tY$ke)t%PJ_P&MZ@QlQX03LX~rb zsfX4`8{LmWkp{*}b_fF}Estteeicc-kuK5h8p)y)3eqaPoVKGzH^rU3Nw4mE+!S56 zKWOTrcpqJ*#<%G6!eu;HHCs8m&MwcB$|QRkD;IqBqsb$m7)fh78fT6i_+IL>pa=kG z))ChE7oJp@DtcEC3Wx?Uclq4mKdy;f47;K|)g<^%j@-AVPq`tIv|$?8SpQHXg;5s- zI+bSo4B6&*=C01I>vNSfEf~w5SZEy2eR|WM@1u18*a#;DbSG{bT7UZe@Zlwto{v$J zwr!b1#^5@(+Zb7UC_WLdct%k$W!6^Z#K1U*p&HV1KY@t+2(VH*tlj*lN zfcVQbD8A|_7+aUm7N<=|CT7)1(cc^H9?k6Fjvoh#seYYUQDiK;jC=f@Dc~>>E$Vd+ z!vFDdP_%9_e>Q%E*Dt`la+N!^M>8&qE{JQ!*A9;=rgTuZFx0@-o$S3aDjUl-tb!pr zCwczv&gvuRrW9%QYSJ%85j0VSV;m!84=Yn;VU~d4-SaKgNr&0#7bNP{I2X|>mPWqz zN)4vCn?G_p3;Zl+7-1mWxCH~F=r7toFTwcxm!B=e-k_0exLMWU=gMU7~DQDqs~p}E>TsB`alrbAa5wb5sg}R z#hgVv+|RHpd}Hj!$X6FPUkCLKLVj_3LCyEEg3qm|S*tGVeDC^y`cDzQ=^IqHfJ>K$ znw`M8_VT#wx|8*E)8V>TkJ}y0%YLE~I=QV)KwKhXg*+_;ce$cC!AMO~$DvX-Cc^Eu z#=0Vp9at2UA7ds=*zf8mGF~B8;u})s@&1`GWqEp@fqV??MQ?&r0U*HvN= z$<{~3FKA)G408Ecw}tv_BX+EhGn%-4G(^8X<5CxASl7_3-l8Z6v*<*~!wuq=B5)U> z^v6If<+tc*F%#;Q4XXYxDtq$7-b1QK55s9z2DR(Ui0F$x z3-1_TNxP4qIw`Y$==#&HOT6P~0*9Vr6F>OzCVYe9?XHRC)Gu66|I~T9S(RaGX2RfV zQ5WTL*aGEvSpaf@Xoq?*#ku=#>swN^&hEF>LmOd0=M!#nA`oC6+eL4#9G)?vn)L*d zc6(5k6?*8JKDMp~#spH+z#c?Ohj0Fx(|ROiWbn_A8>7I>$b}L-f~x}=>OXtfACV$b zS|?vKkRf&}-V}oTb{aCvXnEvG{+MrQJGI_kA|XI~c5~&>kS4Xcr;H>oO!0$&Go88M zN=Q(+34S9YNbfaTypn%nWk6gjb%hdi%A=Tx%8TKF=)&0cn{GCOQ>>#UvjJjd_Tnd= z!u7^eLDc)~q`3!2@TQNh?X%%XiKU3AIzxD!SN8q$snx8ND>)3|ia zC+ei?jBRXeH%;t@z;3pd^gfpfDlZ$jAJj4~L8WYr0X!KR59&x4x~kDLBNu*EiO6WblYsaL$;3vg&x8)5i=?VFf2h)m427 zC8 z;LZ)pcx+RgId-p0Jz(s9g5 zdzBWlLZ7ahwumx6uxue+`=!CeZJ;F5OjbBDn$V?HCNuYqqbs;2hW`rhf^A)FQprH+M+ zZ2$H2u}#7+4dGPEr}V6@1%>MTHiNCyuy5{mTqI>|(y9&WpT*$(j3=X`+1Rs6`->o~ zm6g9NAS$&+^(vS^UqTWB`4=9?Z4znx{L)>N0onJx;gybp6|Ix)d`VrTJIP&BNjTCQ zNY`Rd_s(a#R=*P$D~zZQifCk$k(mX0 zoTOL@(|2&|Ge5l^m!~ZTfkv-hJWZo4up<_zg;KAc7!c3HXe%I(RNp~W2Y<&2p!&Ex z8JyUf31_v}i(7lhC#KeOGq)>jlw)EKW3n>nB~kx?k!bDRx&#FTO*M$>Il2x72(Qv15u~1uY(--EdxE>33QCs!(k)um*|qz4Q~N?-?6K1mMiV%DzKQMU z3~{*Fn>?ZvPG=}`Vo3{%<0xUWJH4ZVZ$i@n68y(O>{D~SE5xy-u~{K9&y;4*(k8MH zCcQkYm`C|U=1f)l*YV$&F6bR` zz)$nW@*86}OD~a6BtC0~-Ezb6 z_t5y@wTWy$m6TGukCeML6~{6@q_t)d<3i;<(Jvl(Io#H99l*M>tlTs6p?P~n(XC!T zhV=J7d=t`$`@V_{CDbAyYhH`Yo*VXZwMvR&Y7wYO|5BNHjNv$EbM9H*?m&8qh=Me| zlPnOh4bGBar?W?)1BH_;Rj!SM<~UKdQY1 zo8>7Byy)hB5F!;)ZF&W2PAu7=S*rO`N6a^#%Ya~_;b+6c{eelU;UmX;geKSVqy{h!+)eMAx>)e!b1oTa{(sHr`zTGl)wM`XNDi?{xF5?=*IHGh-A)p7&eTlMLc#blEaRgnCGXo zS|n^WJGQq0Qu}=HS7yN~>sG6QjY%yYiTEbV(h463I_~H@V5VXQ3?gV~J1^%62;5#@ zx_GA`Xi0f!qAEGMLNB36Q`QIP6OEJHx%)T;e=&f!`^7y+j5Ge%NPxRH2$on6Sk;)0 z7`fOo9*iaw5k2rEWYQ-Z3UJ2krD&_a5bJXDn|0UKH;Xexa=6kD$P}_|=)DkSnoRw5 z)XD5jLhN15j###fN1$#DUvnp8U$^X|n{>pQ5^fK6j}G5B5~z0M$_v8hIi_w625KmF z+JlMbC@&&(uWdvLuL5W157H8~B1Y;(_$r&7BR7*}4%$;fegFKDsZ`1SYGiJ%?+JEy zezb4JeZ3IayrT6URYLcOkg?%yJa>2@^bQ&BaAB3#+R7KEW6|}iuL6?#3!K$+X*JLZ zY!8hKWCZ~hd_Wh(Wfz^p|8?Q=>z1pu#f3k7&6cNwkxw#Ck`>ZJWT?x0Z+uk9`Ye=H z&(kIr9an=JCAH}hsU^M)kI1S}6*ywfRh>dxw>H96X$2o*xNV%q>~#Q&$dWu86F6g) ze$FwCiq)RvqE3iI_JEFuIZ!e3=bG~1lgSxJgTi0^`IIXKHI9f|D$YWd098+boK@%N! z!~;zd?xZPN++C9MT~=!=?RQVm>cZlsBB2d@Lw-lXB}&r~Ca*b3rf1kBIM^v!B-9qZ ztk|X2us&0?0rS6FfWbT!t7P1E^70nRcxAlmd-^`=v_qL#FiaVhBrHC^l7DYqG8|ex zVr7j~?yeiHE-m^4;`*?Z2Vwdt0~d<-oBH{6D}^J9P#E0_C5Je<%QG+b(%*JnSls{q z5T=>e#4ydwz1_ViL%IiK@u|~CW<7`9n$?ziC#t(7#vYVSa3j*nTJ>&0st<;zPg5tU z<0*H#zitHo$rV~n71nwli7o-mKEYG#_zk{ZydGV9bqQ)jKZe_NptjsTc&Vx@`rDNe zp2`(g(h_EMn<|t;7+hp{w}3Z+qzZG!&JLv#$)N2H`3+iU!FW~cBtA9oy80XxNLJ(%A7;?UaC zbIBaLf|nu1FIR-Azp$moyGK8X;K{5I64jLG{M&J|{QtZh+zbnW95E%=X@(@_;LKXZ6%rKdRC(D5@h;bY#*!*=Ck20ka63_W0fi?JY&w-(YC~PfXE|+tj!Z9I{ zK*MiXR|Cl?oN3&tp&#GQk^hdum_HA^B;yaCBEufl z=#g!e{>&Q;I$6XIhmPk3`#B#~Y5+Y(qrt+mS80S5urQd(3Ih)*Q>Ks0xAVf9dm z0$(q*hdM#od8Iu1?#&U69Dm9#C{R-aK;VXZhh9f;NR}kVu-4Y;{H^htgiVN*NB2GO zsEDl^xO{p6+4s*1k(R*O#?}LnEw7TCy%JKam~}$2<}8!9yzOTF;;mhLOAt6Zi(`S~ zmWk~sHe#z9$>97xKi1f$`34JZebcJy`Ng1~6_GDF#}F2bGC-FE^=VRBfIHuIo6*b= z=-qnR=iRe%b0T`RXE}NWRsN!{Bx1|{>i>OC8yVVv{%h)3*4DDW883^yVW-^04pNF8 zWVCcns_i=mzhpT73)^;)3dq6>v~G?<^!zS3I;jh(_y_6HgwQ8oc&UFNFU-T(Oaj?S z(P+%&pLo}7(UK7}hdKP@Dua3jPErJ1NX$h_d7D<*t6vYCJp5$*115~5%A5D%IJ)E^ zlPJ(Xfse)9EWPI^m(#2Svc96`nEBvgpf#T>mC%CoRl!b`PpvX!&a9ruVWY0r)#G;B zV&Fq8&Le|SMA1`0yR3?y_V;nGHaZ<>we=*)rSAWY_-#vc+VWpI28*n z2U2zQolZ%5LcMXrCCGf0fOT^TZhG6}`DBmQxffMyuLih<>m3cR<4rM4ZPGcQol2kt zgp)+O^5&J*q+%)WXiwjL% zim`4t10G{7ZzNWMBnyhvRD}f)Vyehb%7t;_9}ALx1HjcA;QEA*R9sX6+=!oSC+i~) zhIB@_D1mU!ZQeupvZo*Pi=jhxOq8_kZ~QDuSz+TBPhCO7n2U9Y353mB9aY;4onFvz z7`Z`AH7ny9Wy=C6Rwl*lRI9pDoXbHe9M!C8vk{-zh2iqW4yh2&uIla}y6dDNP0I2H z878Y26e5T<9Biu%S3LsnmfW!)+gs(#G(GaDsNpl?q!1zrVEf9uz}VjO6EiBWQgGvZ z7(cgPqzq9WhAjn`!uu8S0D0vCtfWNA(UH2lQQ4RTN4-Ko!8}tOF-jg?z=nICvzQj5 z-UIx)?Bv}tuS8(r)csyrHc)fRbi}1I_{Rq6!@ZE)pGcbiHRan$>*>%7LFwDE9kgkb zzYIhCD$D=tEAEjNk=sb6iQ^TPo78c=3}_$Rj?Y#OCgOeQo{KpUE>P%h4^#twY8wRQ zV|(vdx8Ly4!vERs%T9K8Xhq77TW}xG{dG^fRL*#;Fp6k?HWoE#k0xp9chYsACqT8n zlKo!-8HN`OTEtHwjXWE zD_o&D{2Z9TsyoKLLG(e#X615X-iFC^W?N*DuEXwtuvj23sMYEjE!P(*(L){->%xbMN# zd7WU%i|cGzMj#aOa@lJF}tocyOSNeiMLRd;Fy_@ub`_G z25?Ls@&DGV+jELYHCia6zj_wP!Pmy9-hYc(?h&qqi6nw%(`b2x+qX7c_c^$-#b;lS z_Nd@-%EbehqvatV#_HjNe>)wx7jkz6k%bK}<0mx$1_Ad^b(4jmAcNnZ@Go;5rU^}E zM$ix`4y^SIRns;p=z=#0Dge@Br1dI0Nx{@AmiuK zNEp(dZWQe4c++H4xH-n%NnJu{8mf%M!gTf=*yy2H_Lm3tei?m|+$zil?+84B%F3$h zru}hKS9UfOGE%VSd(jrGJ%zg8dvvqW2HVzSUA)q6bS8cCng-H`WE9#24V(%UOb^5| z05JqL5Kv!lD*MSt%Ybf3iXez%4Fvy)=;SwhO&-< z>X%rdlCyekoEyd8pd)KxD@P<=_4nr7p8+aZz#s1fEu(78m6I4sr|XKKJh!4T?oTbX zT_5`+gfdFsqWZWFySb~6vr>G!fmSAoI)R+TSifG&+oiI7dyM4x3J_u}gjjN2$z|nr zdMc|!9r9rgNoc53>ln_e?oSEt(tGrY7HwmLyr4E?62kdyvSP z{jH1dD(3~m9hQ-d!{Jw;1pNbg>no$Gjox)|Z3=n(5vVxXd9hQ85zEs%@JI29nwzkG zkeVxj%GHnSZG$lBU=8*p<57*mA|~A*ZbFOg`>k(cK_@T>q}Y$cqdF@K2ZPi;@QqF3 zB$MLJ{JrVwSsgy2*-MO*U#nUX+tYNtD#}qM7E8DxgBjeKZ-@L0<dmUKGSTe(W z)%tr;%U+z=fT=7h!-0R z#;6RPkX<)B0o~9;n;TuRSj(oIjid{lut`>X8y;9Yw89Z@{T07zP`n zyvmBp-2>Jw+VOG%RW;0Lc(TN8(Nf}KDEqQ}|A#%b@ZKa$#a0Cg%(KvXiCmwTmo9GS z2p?s6!I!4dxbH3F8rMuuyf7W90${J8kifD(xN7sejmY7pDxcSHJwnPs)it3Sf=CEg zK)sfQAq^=Iu^A&_I{(}&7bf1&7jt7TAEZ9;2ua_brrB7%*h3JW4Ki9C?ehZu`^SZ6u&y{+FX{K<|>Tn9Qs)+E60S|a@opWVnt(4NYOd2CPY-z_R@z= zF)+yXSCk0Q@Cr7tRiC90&cgSVF74gnX`y2<9ZiqX}l-#;)G z7y2&d6aT*X#1?fCf7^&T+cPm?A_o69xk#>2>I}3@l|P3~zsG9hWGM;cj9GwkF-U|u zjqsJi&_9+IsCso(bo*QARl7JPPN*d7?hEPQVr9NP5%lJ(w@j&6_`w&zRO8>OKsOz8 zic;dPv(0$izAAOI7EN@$_Anpiaht!J-tIrSJ5Jtn{n4YP1-*(MhF6s^xZ{F|{e_C( zpu6oZFl!w0dII?O3%X<7fBPObS@FS3U2oYTel0YPxSgEPKWV2}QBVuRvHlhg+cV$y z;{zU=oE(Z>-ww1;_p2}uX1^h*1#&JRZY+$sc4j-Sd>kC3_B}~~62Rcc;4ez2cZaJ= z!~mOO{o7L->0*B8jJZDL#jzEw#Ey2)_ZfG_Yb3;sx}gsZaff5G*upH_5_Z_@A|h}9 zQbJ6G+8#nBB>R|sOj|p4#OSw*Vsu;)BUK+jCCSaoJZT0*|3drPZ4s9@dI!t~e`2u# zybTchN5iv9{X`EmTtb9Rz2JSz?!!z0iR^z=>sQLD1n5D9cicRsjiO}^iHL=J7?xf7 z*g9ht?vHNPv~2-iYNKtvz+7kV-V*STp#LRzq}!W5wO`dSN#TD1-9wTbO$jFV5ci#v zvgq0@ApOht^n$<55F7ou5@&#R!N6SI|PPU=&0Y`19RWsWGhN3jpa zNz!qr87g>(_(~&t$mvLDbfrQdS0$0vc(*iev=sQcVeh(eo);?TCAdiRKR2|&kxc>B z+^t|83QRMgk#hr(Q5KJz;k_=eJkbW-$ z76IYLj;Eem8O$b;w_4;3ob^7l`!H5duzB>P#`Pd>gS(bYOqW{45+mwtEQfxfs!D^~ zN0#@TX~vI823)<5Oh~4^r^-*<;@se~sj=_|$0&^BQ~vd2i!@u?Mv4VJ*^N2QhVC2W z2-Ooqw3zZWDK#-dWA>LWcL|)$uO9ACd1p;I4U9h-eFF~XlOQ)rO?{?dpL&&4475=P zh3BR%ynMEQ=h3v$mI9JZCo`fuTf;(f&X78M5_|FI>P99MvOm0<)+b?vdup=(+OC^R z&yqAyEY=s7%By^BO#JEL*cXOrLpyZ~fMnK8+~3Nd9?4?Q+4tPGoEh0;_!+YPDRT=>c{Feo&$I<}$f^t{|?=XW=N36B3{T!JPd^ffX6K zYM8>$Xs3Sl;_2sR@ZwPh_5)@=9NE+8`O^r2k#pW=$M8p4!ju$+T8|%T*q4nb@qo)D zGkf4G-S*$aVgb6hIt@0;cM;js15Y%14%dG}QEvay>e5E$V<@vykO#$`QQ5AW8e&uI zl;vWkY@fHhE*-QDUBqB4nUuwxZm-r44&!y zkA_G06)=+Guw|tnu!5sV3NSqzi9P1bL`cn7dg6LKlV4a_FHPT8Xb8}J+}4|g)aQ!5 zTE%jJ?yaXG4XUa&KNjfU?KKFOl42(Pz-HR_&8oclRn-2lk@|voae)l5jgk|}?M@3X ziRZH-9aXr0pYn8Jr(|L#>h7rcQ>H!a)~x$Q3TPRj*gLmVJX8@nE-`YTYmMZWkLA<#=;Bb$gri@ucHb&i4kL zwOcRwcS#}jLL4=%)E-B6PTVEajDK5MHTQbQRII4LvxB{+>0nF^!n1W0gZ$ij-)ur< zc6&fF8$1(R-B)N?G8K4cay)mjVpYfaxv7O=ZnqyDB?&w6w2@VyQ*b3Qr(i?FsV8?H zFT?=Yw?7Evw$Sci^KA@jMbuBA8R^%s0D{yt24wf)C#J(T@X8!VWLms1zLJbdn)R;% zsFw#`U+n~!?v*B|Se73ZKLw47MTZ}yyD$?1zYlTE84yuA{D%;bi`~Ma$ho!Y=cIZ* z7g}0)>tF+sXV|t{ijq@v{M-5E?K#gaqk?hiSSP5olKQ}TL4K7y9ERs{huBUq+IHrenDS-H2 z@VX480yP5Fs-~Nugay6asO&7?8P!ckGoBCn=Bf@X8~>gaDucW$pNPoPaG^~`O1uGB z%i9Gz?=8^+A6$BF>ft9}V^Ne5PpekvK*LpaT$EF-c@J+3y^K&uY}9J9 zlvxL-ZBtsk3dFMxSiw^_YeE}}c#3({n8rj7=R;_%i9=q6>bpC~uZ1Yye;e*=T}MMy zH%#c+PBQ6FQHM#4YGNyG((M1VbM1dIZT$BdU%iepfx9p`#HF+nUIzq*>0dX|38Vp-txYf+aws>Pb(7vyaFH13CN`?|7F zJV>|}C9SVfqn!7v-o$;LEgR_IMxNsznkkpM4X=5!61pl9ra=w^&kJc%k|?{I-%g3Hf16f4H`HyuWRcaTndM@~%nu?(&_Vg* z{MU~Cn6h)M;)D6?nx-6|VY=)@=+!k5C%oGi6-@bJVVDMZ#0n(U75%~vhR`#tH4@`& z4m-Y>cyVe*o2CFylCZwBPCwje2#@vO9}21T{sO+t9#uMY~+j@aPw z)6Vk~*M}K@@;kKF5|5oa;IZFcd{etK+uZNuFX>s2pQi|CzJHq7^enE6E9qFT9#*7Z zy5phriNSkcbh30BaCZfa0j@0XeY_iAk&Zla6VjVnM$DwQY}a+JPP{zyjoY8noz$;_ zA2v$2KWm3nN9o(@Hm)>trS#C+pCGlpDU$nGEAYT>6Ah`sqt?hai=j+RYOgD|wOiHl z-?HWpNViID(+XIFnUZqptcPDVN=i@AnwmGJq*z6#l>M=W`@zJoUn;R4D7X5~&C%J~ z=6pO!`qm#2AbBlq$1^>6`nKiSNK?@_vlQtArY2yb*4I}wQa<J$9=(#I z1`aj!GmJTBYSvmFq+hE!pg2ZbhvryuHq++m2fq@%gG0BZ5O})Lc)yBG)f3x>4HkZr z>oz5T+K0x^nJ(?y%Rk?n{^sWM`Id()f4%>0>&q=Ev9)*G=iIvAwL?@0p*FXj9KzOMli1rTgkhb}uj06gd3a0e2ZaFUcE#{idba_Ku>=eVAEYT#rT+p*;N zI6ACcjrBSjIl3F7KZ~@((V!@Hy#EYjj@XE>YrSN4sprx4Rp_o+%fAo$DZ}#hSl^>7 zCL_B2wk1}tyULCg4j^et4SESSg(OhGD}&U9{fiWHgUl8Tb#&W7-B8s!h zGTbqwf(~B$bg)At?Ep2c_-yye!fXKTm(w@A?_Lb8L)b%5*rzvN-za}=Mx`%h78afs zF@Qe}F}pKpa=v9Ea?uEs?|DB`g+()Qc4{KK*W<4s<5f1>N0_e$>_qI@u~Upk_65Oe zV6+w`H(Xx$y9<)m2((Hp${F#{=ZAWme``e^f6f9BoLY8h3|zpy5`wV@HVmG*p-cn* z>a0Soc$08!ikjxrAF7;-)UFM|nX|*#Tm3Z(I5a3nO>t}klo_aN{#F0;3#QUIN3dVs zW66^k>n7Pnr5*OT^yg9Prk zgu!L;vB1|Mg_}YS?povu%mp5LGy%Fb;J-^~D@ePA_2vpKJX|Yqp1DL%3mR5jT;4dX zMOzW#*7AJvBX=GK${W#+I^^I!RdAx=@Xj_f;$HhBJDby?f=%0IxHU~z1ZRrWeX;Cf9TKUe-(i>COTteO z=k)0+Iig6YCubtE7;&o25H{5uVdY>5c_WdPwHqrrul z*j7n>qfhk6Ic-$j{_KF0df-Huew=G7T3<}SsJvHHiF{Z__So_iF344rd$Gut;vL(; zAV`sw8?`v;{o_fD=DwP%qavlVcB9Ii`V+cx?@-wCRHSsL3s7A|Ep5SR-EHEo3MTIP zJt=bVk}BXAIh@*(R%GrG3?ro)VRBotczMBs;ItQ{7Aoyh=0>3QBT!Oj2Sg6kDZ!t+ z${M7YUy*5-pX^HViy2YiWJM}EBV06g0;eZ&l_H4HN?0*IrK8@2_b;AV>APo4NR2>qNY82t ze^RVIM5OYZ*nRrb6~=f-%^<%#NP2WaA4_+5)cIk`MDTLC0rB#a9`OCL3Zwj$!3n8d zU{;k3FZ|8urS*aJ9OoLxn(<7A7yis2c&R0>(Bbg-*#n(QaA9iq$y}2NU@GBUCpGcb z;DGE>go~pR#2v?qCrg&H+CQVyr5GpuOEMT^fr;x5XGh%${|vHc0X*Il6ujeON+UX9 zexKINW57aVg<1DZ@=O(hqc8I;te;7d=|T@%kG;~J(0W9-a^hu#?<}-Y)+_Cy;(eP6 zkNt}JTO$m<(%$L@_6|7F60-hCwD%FrRaZow#&sX&I4K_!rE^f14asR2|Y z4zo9k1ROgl&OP-_+id}x0WgF*tx8Q8sT+&TmAU5P*RLq3LcD{iz0ctuz7_1{vsFrh zu`z}V(7Mqhz#`t6Od2h96Y26|`|XEU&5Y3av}R{W3l$ZqJs1R2!|KD;LeMzE&DB)l zGMRV8O2s2syo=2lTMLn;%VOV3d z3uS_lX-t?k_4QC*vjRMyg^DiDk!1l6IV$lOpwwrRB4HTyiwa$VW$^;s2KxiZnUigCYHpyYcm`0Tlh#!`8W5ibt*6xXD-%N zQKGX(a)v!{lxL_kL14tq`$7zXtIz^6-}NhiDr&9oj1C3?miMSop=+?aW@8ybS~!rN zU|u;Vqa8{ANc-N-f1(a`IjTFLjIgeSphj8)ORN=%^hZnlci=bWW+J6kIvQ;h6KVzh zFPpyStK%*@A{5gD2NMnL*8uSZa-S-ur^*(?Xg@|C23j>R+p)@AWu{ zq@7L^b2}9v*&3xv7V3wCle+JUPca$TQP5c|TfU=VRXFhdvj#D3Iz)QR{^3dZhQ2xj zwz|;giaqk<23r44E(X4m??{sf<>CWQfo;D$bQC9EY*(%fCzJt= zWc6)|>0X2sn?zf-+eb{SF^2wUy6ZGL@CjjD(C_9{mHu(yU-JAUTOd#)Jup0F9{v?? z1u^1QThdzC#{8RPCmiqKw7ceo`6g&wz%Cv^D&16m%nKzkhb)Wvjtt! z{GT#Xk`(lj8&rp=>{d|F8x{xHuC7+Lhk-+0D{D(_!oNFf|WRL;Sv zxI!tJ9hekgc1GnyEdp8SX&r;26(%actJOHvt383{S@FiOTo!r+m&q#DpDy2)6==Fd z6~t8C&x(@uII}YiBo0%v~`8=(bL_tFe4-Nw+pATEW_0>wHz!FRl6JkfdzqL zz3@#0+KR65N>N6PEP2EDa<6dNmkS1<8S7Stia-tVlCWp5lJC39%siB7taktLBxm#A9{HIP(4T^{0AOapDQJldkXDOC@?pr>gR z^=>Vi{!sGI4-7X5QkX=|-lwsUu-1B!DB@-NF>Hp0H83Am9NhfX?lsCXTE2e9Z=FsY z_&K_}@zbLcCQx^X{_bFkVFR%FRQC?o4ot#qv5VXdioi^$>n&Q5hcuO(+qfF3ld#fV zbof$nX3>JDuYJZTK;54$X1ImLsQJLTJ`p2xoC3A|ZjS~&x)fp`MnY6??RjJtX1zpZ zBK<`1ITvXo6VhV_T3-}%k#NO}h8DWn=kPCo1WLDjANJw8{57o5J0G0ZXH{~$6S7I_ zxfls*e9hFs*=6~V6g@`pT}{W>l-5HHKpC!1y0kmT8iwkYSIFV z(AxA&arb%m=EI!@VNf@`j9J@K~`X>BeG zc&;`b1!?=LS0q+QRggRgF`a%VXj*p2;<*xU=c&@ZcX|vrZvRs!V4pO98yILl7qbkU zTm5iBk>sXS{QgbvRy!KhHhE+on~woo6RD@Eb*Oh{k}9o8Jft@TTSw+9(_0<-ZMUJy z4#!FwP$ni}0JWc|E0I1=;abGfxczgij3+>|Z>YZ+x3fr^(o)~92lh{<;|gr|Y3V%e zrbyLkb>6o6c2E5Ayx|1a7K{*Axu1JNZ>QiY!KES8#oomG#;xU*R{gtyrBD(sK^;a) zfYlx}qK>}>iEDJ1uY^v-Qz}kXl!b%fbUl}=< zFw}cTm6o->ioqT38?4c*lyXJq^oF)W>gqNc_sHO$!t0gdhHb|Ae;u@3&3(FLb?MV@LjCpeGXI6&E-97s#76a>)xu^&r=W91j1ltf5LewklcYF*Yqj;7A(8)P?_u^k89)_C+|S6133=lwjlQh zAoq#5ElZ9Axem}9%5fmq0SSt79LRMb#{toR90zh8$Y3D%iE>+z0YM%cq+k`ajR>=gsr>esMnMbFOo)bFSa_T)*$Ny*4(~W@hAM1c5-zx;h#rAQ069 z;8d36pSa%8^>%V|HF0%v3G*LxRRn>!(7GC`k3;Q=SSCMv z*P_om(djZ|y$mVu{A@OH21emVwy~PUm;_74AI)tS*D+IcT0i=seP(g0!R%VY?|R@d z3+_CL=wS$<$5GXGb5re_ZN&?Q7EMNjIi$fvdHa3x=3z;3ik+xm@h_#BGx8DyLpClS zDfk^;vZ{EtdX@?93Y^OX#i&;Fj)EL7QZe*^saayIXm5a;7#@J0vc`bE@`I>yH9^!8 zi6B}>wtpY^7l;41KL}ezthUrF%t$=(^n9o#RO#|8VCX2wZ@f{>Y%K*zQXqT2kMY^8PWu%1D@V{ZYCQd5Yfv=3hQcYf^f>7?P{Yfxv6tE@z2dX8yiOrcfj^Qc`SBHMGS_U;&+H57cL0f zj|3jYE%%*$Q19rySJqp&gdMr3a!eU;!8-8h9mvW0`(!Dekw5D-vq$wUW%Qc;Vx`J; zMt7#+QK?;q+2Gpq@SgsR96ljeLBW5N2XEbNVCX4a=gWIL%qDXsN^);)NJeM1r%fea z>y#x%PKto7lXpMFSk?Dl)1TSQ|K|`%R{ckI=&@`nLk~A5+E2~r(9vd_Q8K8Lth&ft zeR7HI7ZX*kr1es3W0!3V2 z9h*i#9O!G>`wzN@V+C9;<8`|WjBh+fb~O>BM=`2VfEDjyndjn!mQ$G6Xf2GN2_YYU zv1)*oNlR!0rmu13Wj1t$_-r#ivO+(34}q3F7<#h%9Q2jSJK)`sd4p`dT-%E~cAYM8 z{A21_ZP3aC^4QDypqr-nwumU*Lj& zKu_QLe6DQ(XBib?uG*@mcLl6)%Sn8^Baz6^b77s6GY2i^@>4(*t{BB;*|LY0kvwx5ve%k0i1s3e$Zm;~{x70$@2k{(x9QD^8$T2qp}DO0F^ zP=S^C=AA($4w@AzWTthbcb^@eN4<#H^G@!)RzAzT`ZWXR#HN7&=ods(tHUOwF_*}; zKYD60sjR}p(33ey>chOUM6(Jgbag&^4gp@i&(L#q62ad2y31%*Z^gZ6C0(-_Icg+F zEzytM*v`rRnzf5aUtmONsI(z{G9o_`%n%3PygL-`mctTG1Tql&O+vI5rN6uGi&J>BPI? zyID4!#oOCSAXCq7nSi$CSnpognj*5^Aqszg(O|0b*f_MFZymZ-Iqhedp*P(;+(=$k z;Mm=IAC2ca3wPM|)z;pS*1lbNCsFq*$uiVidy%xt?Oy)yAx%nVX1$d{UB;xZMTX|_qu{`5d=9MD}7GZ zn7hajN89OR*9a!QR&bH{5s%NV(SrT9UnT2*fB-9g#ld^29#*SOh+hCpS!+T3=7ZMQ&ZRv|j76Muel!=AxR&s~jl2_ZmmrSs(9)6w~R`sRj%#QoA z%8TRac!ST0#{7KcU{!7AupHeJ>abLx!g8`WF}@bBUq!yDZlw=piMjh8`x3?^7|`!A z(wlXFjZB-af7Pwp{7lR1YIl2$NZVz;$fxZqHM})bsGPTy%f~Tto9lvsrmZi0u2bb+ zmM{8FG}T2fCb4xF=vwaEgX(ceqsor6e!|32$RQJx6XBeGFVn^?702(ZIY@xGSKmcO z$pc?~XZNzXpfUKGA*LC}pnG&NuHI&n;HGDw3XhQJs@YyiaXMW7rW$=;zOMM^`F6s5 zSTD>43$-tptW_vg2UYeIKR>V#bQnoqMank^PEgSMqvXNi&K>T{QHM0diA6t-4!DoF zXZ73P&egCBODCVF6dF(hoV1P~k>T4zruoN+bmUl9ESy+~l%-6Z3#Mx*Z6bx7JN`_E zV&pMj9cznNE&atO&h0_$XX?Dv6{;+;J;cyMOOOimdp5DfUnoscG-22HSbIk#P1LS$ zw~0v8o8@kMq7yGApV`RmBlKq_dkEMSUmHZeXyY(zGm-pqw2m*3D_f|{;+^-zLPKxZ zPKd$F3Y&Fv?*x+7!VKTWUaYkKBz*;J7F9(dWhS3qoP-*k@V*1z1~kTS;&lrC5lVEfOUC{)B9fpmsLQ!67Ax1B!fQTrgG3Kgik>@sZRgGO~W9ik0^J!eT98zrg|L`5K$r!0} zV_1Ey!vMC6&d&=5RJHGj^^Z5>67))@t|h|7HiVmob>O1~*0=5UxTlGyzs-l9q(1-+ z=*N~1A3g1M(+tMUJDiZ@PQ~6ddJgIR(l#Qqd4G-t6y2r3JO*ZA(Q#5L_Oj{I(Vjfj z)3N;aw2ohqo68gZBRHgxf&&GHlbge9vIgf@PJUm>N0jbe_-^KEXE)uS+K9Sjcu-ag zZg=Zfo1HXj&23|ixi_(DB7oD^M$@__lS;?1SDmiG+}^>3H`W6z%dVIPsOiZEPqn$% z?kY=ku)>C=HNJ9FaR?9@JLCoDKG+h(-h`zXD7j%IjV&^Q%w{WQN?P_%M<1X4_dgh8 zdDM=M4_IREjW3Li905`En(ZKOca2+;5>3#3D~qhY33K~l{KSpV(gQR4EkBTA-(9)* zpT>cbUem|Z>tuVFj*?}IgA}mE&u0`-GY{Kmc6SvUNB?T5!pMF=9CiJg*c z%Bn;y@r3g#Wuzmx|Kq~LmMM$uL$nAaN7E7`xt%S9QX^mZZXb<$vuUzdm&kXvT`bp| z^-Q6n{vnPiJ29}w62m%aElZ>>6hfh&xPy=Tpv?b7X0uniEi@fz{o3J)HFQ<$JY6)Q za6bI{iJapVLfRJa*1tr>akIW)lGKf%ll6s%ZP|WaTr;scvn|<-O15qtCi#YVGFOfc zJq<7G2aAjGB$J@+dptOu0z|G3YYgiIf}MC;pq&#YQ&sG=h=>pJ!NT~eyPUjAAQzGp z_9+U;DtQI8r>$*tFf7TK?Fzv7{MMuUs7l7}BVYS=-s-3}w*_bMOY|0}-DWB03f(-6 z_9584=h9Va((}NA#x-AvulTKpmlL?F;exytiU+GjWxnC1a}M3iHh)V0c#a1?3_rOx z9B)*(EWW)BmH?Lt?gn9r4FWX`w?3GMh;Mw1G?& z7-(41a9Y#k;IN^>q_G1aF!t*CQvPHRy=La#gP=$@j=yehi(U3V8HhYBdl4Qzx6yDp zzM?`C#pvD7RUlHxR=~nb#X-fxbl-eA+B5i8Bra^M025b%R*c%yPmNeq33=#cchHGO z@z)CS>+<>W3MtXYxW07J`N=?e4R=Z2}k%-Qa@5DM>um9nU>*p`=xcP;x%l@;+D#KiM(UjA* z(Hn+|e`uCWv>3Hs06+vAMWLK!L$jhCpf0KSF-dSeUSTQMTF!&?ezm+6>@DJ{sG>sN)Q}%4E(arRwoqx9 zn2bf=GPk)}{+zQwYz0Ei zeGLxM27fj|o5S@v@bbQ0c)fezB7Wr-XX7Y*RtaX<>(r~E9jl>x1LXXUM-P7Nul!It z>HyLJ;emKruS3nZG<`j`(TWO1s+)AX%W`*9rnh0+$_}>Hu})Bi9*#AcfC`z*$5q^Q zmQmhib6;FgZu{%3rDA_=4A;h2cZ&!P??KS_3$TWt`u29rQeOMGcP|Z+^h?N;QTv#U z$m_u_rLgvR>uGe!6b!8aX-yz;p4SU0TZ3nU(Jppq6$-PB^~=1QAm>v2Sd-WAFK3)g zC>!D9C!&3f*W36CSUZ#-2N_+TT6E8mOlX$14yjlpWr8W1M{kcSopprohQDTZAaD@+ zCX+02#iQ%eb=h-%pNX1)K=*tJtD+O;q!!tN(dPZ6J`PM%cDT zX>SX21#@#`Xxp!a2!EL}v$Y#3x{JLZ;CSo!jxmijS}*#i5D!48W1^9mwJbzVC=iP# zef@|LrLY>S54&AOhIH-mfPqu#1O1i9;nCuM6w~oTa`AhLu7z*VwN^_AIYAj8=)t5i%Jd9dpHAlx+NRDaVs)TH z4Mb@$(W!H>7yHd^pLcen!IEUT5=#F;#%=~HjPep3k&hp6B}yutR$tp$f)%sW|EBbs z9u@hlw_*1;PEH}gw>wYYEY}eVRc%eTL+Z=(%;~-c%3h)C*96_xs8T@12f4l>H?B+B zv0wcNt+0>oUxdM%!=tPqAHo7NPhEvz9I(=Nl z8@>bfR0jT6q2AS_Je3{UbU$4kbX&j5!^4XRpZn0&-LCD)Q>@o%-q8JITrvS2KTs4- zzb=+7)xQ7QC;E}l<`SI-kj3O0PSSU5kF9!p>Hb|ib!^9SN*ud13v=1 z3~dFm&`U=uv<*L^PGAF)_xhma*V+9Mq@UP{UyZ_YSODBzqH8>x#>WXP7zNWDHcD>< zA|jrrQ2pB^fB|d$xw(n^g9c_+q%pwdi1)86hSo6-Sm! zfXYQ*N@`P075rh#_p60(irp~4AA}5@?zGAbzE!tMg7*xxufrWgi1efheYTwi9^ISW zHLI0|(JpMw?0-^+B1d`Ndd8a#KG_G>UNGvFflJ#ySL-#lA;uoLa{ZhVVzMF+ya;6Q zWA72UChg$3U_*KNaixw<`|4MRbK`>qFUTUMj`evY?LsEZ`;b zh&+%(Uzk70uPm6jHP6=9N>%Bc6QZtiN{|`i$`^SdG9LPLOLeRJzL*o6kakCpEi|H& z96l+Ne@Nh?KPH6bs^lr31B81wqc9;YVQ2N~3Q=#BX&v7X*7U3T&X!)?Kxm`KY=5uu zdcZ45;`JOkRk_&}?$}(mI|AXzpY_AnhZ6Xxas#Yo*k<~mS5xC0UgbmrH9r?1gVK0B zM^2~R}{+AG&+xM)TM0xm6jT>&lGrIucwz`(alO6h}S?{hPW6pOOr&M5wLLu8%6dZE+#(% zIx_mc9Y1#tMq7K{2R`<}d?&Pus0Z(mTy5u9Z5CLRv^Bf`WOlj$*!f2t9oPQT?nxus zw79!?`pD`mqU8G+QSf)@xxfd$pTbLsS=f`Gsqvro>TU62_05~)5gKX}bxo;egui!d-09r}F<-&ML4EFDTAVpfu zJH}R&Re+A#I3joF_1$*jYZA}{(==K`FAe&1E6D7|hDf?0#k}_`4Yw=`gRS*3$>G7G zSo>X|ady2MJiyeOMJ6)B9V?Mce|_>8KL3RsH_lxvCZ45zIwn3BKJY>$_dM~VQVt@= zmLC-8X>X@0*5($z%{aNg|5?5wBv+aorU_d4{*#%)UKcrdcAZ2DhZ~(P4~pfPY0m1| zv&P6(n*L;mYAqMuPolNMo_1q*LsW2rzc)M}`EIn1-#lgqx_a-)k+Ma1eMbXwC%nSi zLmq!4YmLaL;O;VUGIV!{0Buz1b-@d{h56|;eHkWZ_WUJQiZ;sIl~6f&JO4pd3t^mE z#g{J~9W^D|jf)&pnaR00D$Noz;7&6d>zwhA;=N^d10(twQ4#T}*vf~;m6vHtME|z_ sL+SsW1N=Mg_;>8{e~rJ&G)^ytC$n6~3@=Rsvp$fnrlAI0&GE&505K@zKmY&$ diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Resources/Default@2x.png b/samples/core/Xamarin/EFGetStarted.iOS/Resources/Default@2x.png deleted file mode 100644 index dbd6bd3e8646fe4dfa515cf345cbcb30271ae103..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8368 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 GkpBQzOK;x* diff --git a/samples/core/Xamarin/EFGetStarted.iOS/Resources/LaunchScreen.storyboard b/samples/core/Xamarin/EFGetStarted.iOS/Resources/LaunchScreen.storyboard deleted file mode 100644 index f12b936801..0000000000 --- a/samples/core/Xamarin/EFGetStarted.iOS/Resources/LaunchScreen.storyboard +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/core/Xamarin/EFGetStarted.sln b/samples/core/Xamarin/EFGetStarted.sln deleted file mode 100644 index e2418d5398..0000000000 --- a/samples/core/Xamarin/EFGetStarted.sln +++ /dev/null @@ -1,57 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFGetStarted.Android", "EFGetStarted.Android\EFGetStarted.Android.csproj", "{8969C333-0071-4893-91BE-18050B0343C9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFGetStarted.iOS", "EFGetStarted.iOS\EFGetStarted.iOS.csproj", "{CDC252B5-A191-4131-8B4F-8983A370DA5C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFGetStarted", "EFGetStarted\EFGetStarted.csproj", "{E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - Debug|iPhoneSimulator = Debug|iPhoneSimulator - Release|iPhoneSimulator = Release|iPhoneSimulator - Debug|iPhone = Debug|iPhone - Release|iPhone = Release|iPhone - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8969C333-0071-4893-91BE-18050B0343C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Release|Any CPU.Build.0 = Release|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Debug|iPhone.Build.0 = Debug|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Release|iPhone.ActiveCfg = Release|Any CPU - {8969C333-0071-4893-91BE-18050B0343C9}.Release|iPhone.Build.0 = Release|Any CPU - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Release|Any CPU.Build.0 = Release|iPhoneSimulator - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Debug|iPhone.ActiveCfg = Debug|iPhone - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Debug|iPhone.Build.0 = Debug|iPhone - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Release|iPhone.ActiveCfg = Release|iPhone - {CDC252B5-A191-4131-8B4F-8983A370DA5C}.Release|iPhone.Build.0 = Release|iPhone - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Release|Any CPU.Build.0 = Release|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Debug|iPhone.Build.0 = Debug|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Release|iPhone.ActiveCfg = Release|Any CPU - {E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}.Release|iPhone.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/samples/core/Xamarin/EFGetStarted/App.xaml b/samples/core/Xamarin/EFGetStarted/App.xaml deleted file mode 100644 index fc7e54510a..0000000000 --- a/samples/core/Xamarin/EFGetStarted/App.xaml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/samples/core/Xamarin/EFGetStarted/App.xaml.cs b/samples/core/Xamarin/EFGetStarted/App.xaml.cs deleted file mode 100644 index e2d1985eeb..0000000000 --- a/samples/core/Xamarin/EFGetStarted/App.xaml.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using Xamarin.Forms; -using Xamarin.Forms.Xaml; - -namespace EFGetStarted -{ - public partial class App : Application - { - public App() - { - InitializeComponent(); - - MainPage = new NavigationPage(new BlogsPage()); - } - - protected override void OnStart() - { - - } - - protected override void OnSleep() - { - - } - - protected override void OnResume() - { - - } - } -} diff --git a/samples/core/Xamarin/EFGetStarted/AssemblyInfo.cs b/samples/core/Xamarin/EFGetStarted/AssemblyInfo.cs deleted file mode 100644 index c859952e34..0000000000 --- a/samples/core/Xamarin/EFGetStarted/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using Xamarin.Forms.Xaml; - -[assembly: XamlCompilation(XamlCompilationOptions.Compile)] \ No newline at end of file diff --git a/samples/core/Xamarin/EFGetStarted/EFGetStarted.csproj b/samples/core/Xamarin/EFGetStarted/EFGetStarted.csproj deleted file mode 100644 index 886d2b90a2..0000000000 --- a/samples/core/Xamarin/EFGetStarted/EFGetStarted.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - netstandard2.0 - true - - - - portable - true - - - - - - - - - - - - - - diff --git a/samples/core/Xamarin/EFGetStarted/Models/Blog.cs b/samples/core/Xamarin/EFGetStarted/Models/Blog.cs deleted file mode 100644 index 56a6373d81..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Models/Blog.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace EFGetStarted -{ - public class Blog - { - public int BlogId { get; set; } - public string Url { get; set; } - - public List Posts { get; set; } = new List(); - } -} diff --git a/samples/core/Xamarin/EFGetStarted/Models/Post.cs b/samples/core/Xamarin/EFGetStarted/Models/Post.cs deleted file mode 100644 index 153481cd2b..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Models/Post.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -namespace EFGetStarted -{ - public class Post - { - public int PostId { get; set; } - public string Title { get; set; } - public string Content { get; set; } - - public int BlogId { get; set; } - public Blog Blog { get; set; } - } -} diff --git a/samples/core/Xamarin/EFGetStarted/Pages/AddBlogPage.xaml b/samples/core/Xamarin/EFGetStarted/Pages/AddBlogPage.xaml deleted file mode 100644 index b47f3bb25c..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Pages/AddBlogPage.xaml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/samples/core/Xamarin/EFGetStarted/Pages/AddBlogPage.xaml.cs b/samples/core/Xamarin/EFGetStarted/Pages/AddBlogPage.xaml.cs deleted file mode 100644 index e403ebda2d..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Pages/AddBlogPage.xaml.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; - -using Xamarin.Forms; - -namespace EFGetStarted -{ - public partial class AddBlogPage : ContentPage - { - public AddBlogPage() - { - InitializeComponent(); - } - - async void Save_Clicked(System.Object sender, System.EventArgs e) - { - var blog = new Blog { Url = blogUrl.Text }; - - using (var blogContext = new BloggingContext()) - { - blogContext.Add(blog); - - await blogContext.SaveChangesAsync(); - } - - await Navigation.PopModalAsync(); - } - - async void Cancel_Clicked(System.Object sender, System.EventArgs e) - { - await Navigation.PopModalAsync(); - } - } -} diff --git a/samples/core/Xamarin/EFGetStarted/Pages/AddPostPage.xaml b/samples/core/Xamarin/EFGetStarted/Pages/AddPostPage.xaml deleted file mode 100644 index e1f11bc797..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Pages/AddPostPage.xaml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/core/Xamarin/EFGetStarted/Pages/AddPostPage.xaml.cs b/samples/core/Xamarin/EFGetStarted/Pages/AddPostPage.xaml.cs deleted file mode 100644 index 9fecc6b449..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Pages/AddPostPage.xaml.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.EntityFrameworkCore; - -using Xamarin.Forms; - -namespace EFGetStarted -{ - public partial class AddPostPage : ContentPage - { - int BlogId; - - public AddPostPage(int blogId) - { - InitializeComponent(); - - BlogId = blogId; - } - - protected async void Save_Clicked(object sender, EventArgs e) - { - var newPost = new Post - { - BlogId = BlogId, - Content = postCell.Text, - Title = titleCell.Text - }; - - try - { - using (var blogContext = new BloggingContext()) - { - await blogContext.Posts.AddAsync(newPost); - - await blogContext.SaveChangesAsync(); - } - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine(ex); - } - - await Navigation.PopModalAsync(); - } - - protected async void Cancel_Clicked(object sender, EventArgs e) - { - await Navigation.PopModalAsync(); - } - } -} diff --git a/samples/core/Xamarin/EFGetStarted/Pages/BlogsPage.xaml b/samples/core/Xamarin/EFGetStarted/Pages/BlogsPage.xaml deleted file mode 100644 index 98980f0fe8..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Pages/BlogsPage.xaml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/core/Xamarin/EFGetStarted/Pages/BlogsPage.xaml.cs b/samples/core/Xamarin/EFGetStarted/Pages/BlogsPage.xaml.cs deleted file mode 100644 index 3b037bdb29..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Pages/BlogsPage.xaml.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using Xamarin.Forms; -using System.ComponentModel; -using System.Threading.Tasks; - -namespace EFGetStarted -{ - public partial class BlogsPage : ContentPage, INotifyPropertyChanged - { - public BlogsPage() - { - InitializeComponent(); - } - - protected async override void OnAppearing() - { - blobCollectionView.SelectedItem = null; - - using (var blogContext = new BloggingContext()) - { - await InsertStartData(blogContext); - - var theBlogs = blogContext.Blogs.ToList(); - - blobCollectionView.ItemsSource = theBlogs; - } - } - - async Task InsertStartData(BloggingContext context) - { - var blogCount = context.Blogs.Count(); - - if (blogCount == 0) - { - await context.AddAsync(new Blog { Url = "https://devblogs.microsoft.com/xamarin" }); - await context.AddAsync(new Blog { Url = "https://aka.ms/appsonazureblog" }); - - await context.SaveChangesAsync(); - } - } - - async void blobCollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (!(e.CurrentSelection.FirstOrDefault() is Blog blog)) - return; - - var postsPage = new PostsPage(blog.BlogId); - await Navigation.PushAsync(postsPage); - } - - async void ToolbarItem_Clicked(System.Object sender, System.EventArgs e) - { - await Navigation.PushModalAsync(new NavigationPage(new AddBlogPage())); - } - - async void DeleteAll_Clicked(object sender, EventArgs e) - { - using (var blogContext = new BloggingContext()) - { - blogContext.RemoveRange(blogContext.Blogs); - - await blogContext.SaveChangesAsync(); - - blobCollectionView.ItemsSource = blogContext.Blogs.ToList(); - } - } - } -} diff --git a/samples/core/Xamarin/EFGetStarted/Pages/PostsPage.xaml b/samples/core/Xamarin/EFGetStarted/Pages/PostsPage.xaml deleted file mode 100644 index a4025bb7ab..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Pages/PostsPage.xaml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/core/Xamarin/EFGetStarted/Pages/PostsPage.xaml.cs b/samples/core/Xamarin/EFGetStarted/Pages/PostsPage.xaml.cs deleted file mode 100644 index a93ae62735..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Pages/PostsPage.xaml.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using Xamarin.Forms; - -namespace EFGetStarted -{ - public partial class PostsPage : ContentPage - { - int BlogId; - - public PostsPage(int blogId) - { - InitializeComponent(); - - BlogId = blogId; - } - - protected override void OnAppearing() - { - using (var blogContext = new BloggingContext()) - { - var postList = blogContext.Posts - .Where(p => p.BlogId == BlogId) - .ToList(); - - postCollection.ItemsSource = postList; - } - } - - async void ToolbarItem_Clicked(System.Object sender, System.EventArgs e) - { - await Navigation.PushModalAsync(new NavigationPage(new AddPostPage(BlogId))); - } - } -} diff --git a/samples/core/Xamarin/EFGetStarted/Services/BloggingContext.cs b/samples/core/Xamarin/EFGetStarted/Services/BloggingContext.cs deleted file mode 100644 index ef1adf8307..0000000000 --- a/samples/core/Xamarin/EFGetStarted/Services/BloggingContext.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.IO; -using Microsoft.EntityFrameworkCore; -using Xamarin.Essentials; - -namespace EFGetStarted -{ - public class BloggingContext : DbContext - { - public DbSet Blogs { get; set; } - public DbSet Posts { get; set; } - - public BloggingContext() - { - SQLitePCL.Batteries_V2.Init(); - - this.Database.EnsureCreated(); - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - string dbPath = Path.Combine(FileSystem.AppDataDirectory, "blogs.db3"); - - optionsBuilder - .UseSqlite($"Filename={dbPath}"); - } - } -} From 38ae71c3c9504d3a81354336ace6842c29050ced Mon Sep 17 00:00:00 2001 From: Stephan Nielsen Date: Tue, 11 Feb 2025 00:21:11 +0100 Subject: [PATCH 110/224] Use consistent migration name in example (#4948) --- entity-framework/core/managing-schemas/migrations/managing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/entity-framework/core/managing-schemas/migrations/managing.md b/entity-framework/core/managing-schemas/migrations/managing.md index 40a8e490fa..0d576e97a9 100644 --- a/entity-framework/core/managing-schemas/migrations/managing.md +++ b/entity-framework/core/managing-schemas/migrations/managing.md @@ -34,8 +34,8 @@ The migration name can be used like a commit message in a version control system Three files are added to your project under the **Migrations** directory: -* **XXXXXXXXXXXXXX_AddCreatedTimestamp.cs**--The main migrations file. Contains the operations necessary to apply the migration (in `Up`) and to revert it (in `Down`). -* **XXXXXXXXXXXXXX_AddCreatedTimestamp.Designer.cs**--The migrations metadata file. Contains information used by EF. +* **XXXXXXXXXXXXXX_AddBlogCreatedTimestamp.cs**--The main migrations file. Contains the operations necessary to apply the migration (in `Up`) and to revert it (in `Down`). +* **XXXXXXXXXXXXXX_AddBlogCreatedTimestamp.Designer.cs**--The migrations metadata file. Contains information used by EF. * **MyContextModelSnapshot.cs**--A snapshot of your current model. Used to determine what changed when adding the next migration. The timestamp in the filename helps keep them ordered chronologically so you can see the progression of changes. From 484001481649b5c59690141d2eba96754e3c8d70 Mon Sep 17 00:00:00 2001 From: Theano Petersen Date: Tue, 11 Feb 2025 13:36:59 -0800 Subject: [PATCH 111/224] ? (#4946) --- .../media/schemawithdisplaynamerenamed.png | Bin 6511 -> 10037 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/entity-framework/ef6/media/schemawithdisplaynamerenamed.png b/entity-framework/ef6/media/schemawithdisplaynamerenamed.png index bcdec944366a34c75f87ce2325e8c2ec5cf17db0..117a6e9c419c9cdb8daa62e0f8f7e2b5ca6ae172 100644 GIT binary patch literal 10037 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 literal 6511 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 bW=QeBWIyTK8ISna54DMr`ITCPOTzyE9B24( From 939cb0d84873f4236718d4d5ab97cde39880bdbf Mon Sep 17 00:00:00 2001 From: Jon X Date: Sat, 15 Feb 2025 16:46:04 +0800 Subject: [PATCH 112/224] Update indexes.md (#4950) Co-authored-by: Shay Rojansky --- entity-framework/core/modeling/indexes.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/entity-framework/core/modeling/indexes.md b/entity-framework/core/modeling/indexes.md index 3505a66246..5bb71104bd 100644 --- a/entity-framework/core/modeling/indexes.md +++ b/entity-framework/core/modeling/indexes.md @@ -106,12 +106,12 @@ You can set the name of the index created in the database: Note that if you call `HasIndex` more than once on the same set of properties, that continues to configure a single index rather than create a new one: ```csharp -modelBuilder.Entity() - .HasIndex(b => new { b.FirstName, b.LastName }) +modelBuilder.Entity() + .HasIndex(p => new { p.FirstName, p.LastName }) .HasDatabaseName("IX_Names_Ascending"); -modelBuilder.Entity() - .HasIndex(b => new { b.FirstName, b.LastName }) +modelBuilder.Entity() + .HasIndex(p => new { p.FirstName, p.LastName }) .HasDatabaseName("IX_Names_Descending") .IsDescending(); ``` @@ -121,11 +121,11 @@ Since the second `HasIndex` call overrides the first one, this creates only a si To create multiple indexes over the same set of properties, pass a name to the `HasIndex`, which will be used to identify the index in the EF model, and to distinguish it from other indexes over the same properties: ```c# -modelBuilder.Entity() - .HasIndex(b => new { b.FirstName, b.LastName }, "IX_Names_Ascending"); +modelBuilder.Entity() + .HasIndex(p => new { p.FirstName, p.LastName }, "IX_Names_Ascending"); -modelBuilder.Entity() - .HasIndex(b => new { b.FirstName, b.LastName }, "IX_Names_Descending") +modelBuilder.Entity() + .HasIndex(p => new { p.FirstName, p.LastName }, "IX_Names_Descending") .IsDescending(); ``` From 589c185795ff6fce0016cd2d7b1a7f597883b1d1 Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Wed, 19 Feb 2025 01:36:02 +0100 Subject: [PATCH 113/224] update whats new for preview 1 (#4953) --- .../core/what-is-new/ef-core-10.0/whatsnew.md | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index dcc6fecb37..f02a5b006d 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -24,13 +24,40 @@ EF10 requires the .NET 10 SDK to build and requires the .NET 10 runtime to run. ## LINQ and SQL translation + + +### Support for the .NET 10 LeftJoin operator + +`LEFT JOIN` is a common and useful operation when working with EF Core. In previous versions, implementing `LEFT JOIN` in LINQ was quite complicated, requiring `SelectMany`, `GroupJoin` and `DefaultIfEmpty` operations [in a particular configuration](/dotnet/csharp/linq/standard-query-operators/join-operations#perform-left-outer-joins). + +.NET 10 adds first-class LINQ support for `LeftJoin` method, making those queries much simpler to write. EF Core recognizes the new method, so it can be used in EF LINQ queries instead of the old construct: + +```C# +var query = context.Students + .LeftJoin( + context.Departments, + student => student.DepartmentID, + department => department.ID, + (student, department) => new + { + student.FirstName, + student.LastName, + Department = department.Name ?? "[NONE]" + }); +``` + +See [#12793](https://github.com/dotnet/efcore/issues/12793) for more details. + ### Other query improvements * Translation for DateOnly.ToDateTime(timeOnly) ([#35194](https://github.com/dotnet/efcore/pull/35194), contributed by [@mseada94](https://github.com/mseada94)). -* Optimization for multiple consecutive `LIMIT`s ([#35384](https://github.com/dotnet/efcore/pull/35384)), contributed by [@ranma42](https://github.com/ranma42)). -* Optimization for use of `Count` operation on `ICollection` ([#35381](https://github.com/dotnet/efcore/pull/35381)), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). +* Optimization for multiple consecutive `LIMIT`s ([#35384](https://github.com/dotnet/efcore/pull/35384), contributed by [@ranma42](https://github.com/ranma42)). +* Optimization for use of `Count` operation on `ICollection` ([#35381](https://github.com/dotnet/efcore/pull/35381), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). +* Optimization for `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)). +* Translation for date/time functions using `DatePart.Microsecond` and `DatePart.Nanosecond` arguments ([#34861](https://github.com/dotnet/efcore/pull/34861)). +* Simplifying parameter names (e.g. from `@__city_0` to `city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)). ## ExecuteUpdateAsync now accepts a regular, non-expression lambda @@ -76,3 +103,9 @@ await context.Blogs.ExecuteUpdateAsync(s => ``` Thanks to [@aradalvand](https://github.com/aradalvand) for proposing and pushing for this change (in [#32018](https://github.com/dotnet/efcore/issues/32018)). + + + +## Other improvements + +* Make SQL Server scaffolding compatible with Azure Data Explorer ([#34832](https://github.com/dotnet/efcore/pull/34832), contributed by [@barnuri](https://github.com/barnuri)). From 4d75546a231f75257ede940f72986b63f1818d6f Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Mon, 24 Feb 2025 11:16:28 +0100 Subject: [PATCH 114/224] removing mention of daily builds, point to preview releases instead (#4955) * removing mention of daily builds, point to preview releases instead --- entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index f02a5b006d..bb549da8cf 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -10,7 +10,7 @@ uid: core/what-is-new/ef-core-10.0/whatsnew EF Core 10 (EF10) is the next release after EF Core 9 and is scheduled for release in November 2025. -EF10 is available as [daily builds](https://github.com/dotnet/efcore/blob/main/docs/DailyBuilds.md) which contain all the latest EF10 features and API tweaks. The samples here make use of these daily builds. +EF10 is available as a preview. See [.NET 10 release notes](https://github.com/dotnet/core/release-notes/10.0) to get information about the latest preview. This article will be updated as new preview releases are made available. > [!TIP] > You can run and debug into the samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs). Each section below links to the source code specific to that section. From 4ed13cbe1d95324a705eb1a21f4af896bb4562f0 Mon Sep 17 00:00:00 2001 From: "Jamie R. Rytlewski" Date: Wed, 26 Feb 2025 19:52:58 -0500 Subject: [PATCH 115/224] Update DiscriminatorPropertyConfiguration.cs (#4952) --- .../FluentAPI/DiscriminatorPropertyConfiguration.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/core/Modeling/Inheritance/FluentAPI/DiscriminatorPropertyConfiguration.cs b/samples/core/Modeling/Inheritance/FluentAPI/DiscriminatorPropertyConfiguration.cs index 4c188560d0..b046c11ba5 100644 --- a/samples/core/Modeling/Inheritance/FluentAPI/DiscriminatorPropertyConfiguration.cs +++ b/samples/core/Modeling/Inheritance/FluentAPI/DiscriminatorPropertyConfiguration.cs @@ -10,7 +10,7 @@ public class MyContext : DbContext protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity() - .Property("Discriminator") + .Property("blog_type") .HasMaxLength(200); } #endregion @@ -25,4 +25,4 @@ public class Blog public class RssBlog : Blog { public string RssUrl { get; set; } -} \ No newline at end of file +} From d094fd74823257b3ec7b8d0d806485595fe5fcee Mon Sep 17 00:00:00 2001 From: Sander ten Brinke Date: Thu, 27 Feb 2025 23:13:24 +0100 Subject: [PATCH 116/224] Add SanderTenBrinke.EntityFrameworkCore.Extensions.SqlServer.DataMasking as an EF Core extension and the outdated fork its based on (#4949) --- entity-framework/core/extensions/index.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index 6f2f284f2b..1fdc81fef0 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -391,6 +391,12 @@ A standard for implementing REST APIs with specifications for discovery, filteri [GitHub repository](https://github.com/OData) | [NuGet](https://www.nuget.org/packages/Microsoft.OData.Core/) +### SanderTenBrinke.EntityFrameworkCore.Extensions.SqlServer.DataMasking + +This package focuses on adding data masking support for SQL Server to EF Core. For EF Core: 8-9. + +[GitHub repository](https://github.com/sander1095/EntityFrameworkCore.Extensions.SqlServer.DataMasking) | [NuGet](https://www.nuget.org/packages/SanderTenBrinke.EntityFrameworkCore.Extensions.SqlServer.DataMasking) + ## Extensions for unsupported EF Core versions ### nHydrate ORM for Entity Framework @@ -449,3 +455,11 @@ NCache Entity Framework Core Provider is a distributed second level cache provid Life cycle hooks (for SaveChanges). For EF Core: 2-3. [GitHub repository](https://github.com/JValck/Ramses) | [NuGet](https://www.nuget.org/packages/Ramses) + +### EntityFrameworkCore.Extensions + +An extension library for Dynamic Data Masking (SQL Server) and MigrationBuilder and ModelBuilder extensions. For EF Core: 5. + +An updated fork for the data masking feature can be found at [EntityFrameworkCore.Extensions.SqlServer.DataMasking](https://github.com/sander1095/EntityFrameworkCore.Extensions.SqlServer.DataMasking) + +[GitHub repository](https://github.com/nikitasavinov/EntityFrameworkCore.Extensions) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Extensions) From 9b1dccce1c2400f49c66e48266cd9ec11dd33cda Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 4 Mar 2025 11:43:17 +0100 Subject: [PATCH 117/224] Add async disposal to transactions in samples (#4960) Fixes #4959 --- samples/core/Saving/Transactions/ControllingTransaction.cs | 2 +- samples/core/Saving/Transactions/ExternalDbTransaction.cs | 2 +- samples/core/Saving/Transactions/ManagingSavepoints.cs | 2 +- samples/core/Saving/Transactions/SharingTransaction.cs | 2 +- .../Testing/BloggingWebApi/Controllers/BloggingController.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/core/Saving/Transactions/ControllingTransaction.cs b/samples/core/Saving/Transactions/ControllingTransaction.cs index e4b3ef5845..2e043bd9ac 100644 --- a/samples/core/Saving/Transactions/ControllingTransaction.cs +++ b/samples/core/Saving/Transactions/ControllingTransaction.cs @@ -17,7 +17,7 @@ public static async Task Run() #region Transaction using var context = new BloggingContext(); - using var transaction = await context.Database.BeginTransactionAsync(); + await using var transaction = await context.Database.BeginTransactionAsync(); try { diff --git a/samples/core/Saving/Transactions/ExternalDbTransaction.cs b/samples/core/Saving/Transactions/ExternalDbTransaction.cs index d7fa2d3bb6..0ea8f878e1 100644 --- a/samples/core/Saving/Transactions/ExternalDbTransaction.cs +++ b/samples/core/Saving/Transactions/ExternalDbTransaction.cs @@ -25,7 +25,7 @@ public static async Task Run() using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); - using var transaction = (SqlTransaction)await connection.BeginTransactionAsync(); + await using var transaction = (SqlTransaction)await connection.BeginTransactionAsync(); try { // Run raw ADO.NET command in the transaction diff --git a/samples/core/Saving/Transactions/ManagingSavepoints.cs b/samples/core/Saving/Transactions/ManagingSavepoints.cs index a8cc4a2d57..d0a5f05fac 100644 --- a/samples/core/Saving/Transactions/ManagingSavepoints.cs +++ b/samples/core/Saving/Transactions/ManagingSavepoints.cs @@ -16,7 +16,7 @@ public static async Task Run() #region Savepoints using var context = new BloggingContext(); - using var transaction = await context.Database.BeginTransactionAsync(); + await using var transaction = await context.Database.BeginTransactionAsync(); try { diff --git a/samples/core/Saving/Transactions/SharingTransaction.cs b/samples/core/Saving/Transactions/SharingTransaction.cs index 719c7a6163..ad7af12dad 100644 --- a/samples/core/Saving/Transactions/SharingTransaction.cs +++ b/samples/core/Saving/Transactions/SharingTransaction.cs @@ -30,7 +30,7 @@ public static async Task Run() .Options; using var context1 = new BloggingContext(options); - using var transaction = await context1.Database.BeginTransactionAsync(); + await using var transaction = await context1.Database.BeginTransactionAsync(); try { context1.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/dotnet" }); diff --git a/samples/core/Testing/BloggingWebApi/Controllers/BloggingController.cs b/samples/core/Testing/BloggingWebApi/Controllers/BloggingController.cs index a0f07a0321..fe4feee86f 100644 --- a/samples/core/Testing/BloggingWebApi/Controllers/BloggingController.cs +++ b/samples/core/Testing/BloggingWebApi/Controllers/BloggingController.cs @@ -46,7 +46,7 @@ public async Task AddBlog(string name, string url) public async Task UpdateBlogUrl(string name, string url) { // Note: it isn't usually necessary to start a transaction for updating. This is done here for illustration purposes only. - using var transaction = await _context.Database.BeginTransactionAsync(IsolationLevel.Serializable); + await using var transaction = await _context.Database.BeginTransactionAsync(IsolationLevel.Serializable); var blog = await _context.Blogs.FirstOrDefaultAsync(b => b.Name == name); if (blog is null) From e57dfff1c45a7c9dba4f0f27fc1a3dcba71a1164 Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Tue, 4 Mar 2025 02:45:49 -0800 Subject: [PATCH 118/224] update toc for ef 10 release (#4965) --- entity-framework/toc.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index daea6694e6..7d71eeba61 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -61,6 +61,12 @@ href: core/what-is-new/index.md - name: Release planning process href: core/what-is-new/release-planning.md + - name: EF Core 10.0 + items: + - name: "What's new?" + href: core/what-is-new/ef-core-10.0/whatsnew.md + - name: Breaking changes + href: core/what-is-new/ef-core-10.0/breaking-changes.md - name: EF Core 9.0 items: - name: "What's new?" From cf7a02f358293918335830c1325f2765975ac448 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 6 Mar 2025 11:41:52 +0100 Subject: [PATCH 119/224] Qualify note to SQL Server (#4969) --- entity-framework/core/managing-schemas/migrations/operations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/managing-schemas/migrations/operations.md b/entity-framework/core/managing-schemas/migrations/operations.md index 1278877bcc..0e3495517c 100644 --- a/entity-framework/core/managing-schemas/migrations/operations.md +++ b/entity-framework/core/managing-schemas/migrations/operations.md @@ -22,7 +22,7 @@ The easiest way to implement a custom operation is to define an extension method [!code-csharp[](../../../../samples/core/Schemas/Migrations/CustomOperationSql.cs#snippet_CustomOperationSql)] > [!TIP] -> Use the `EXEC` function when a statement must be the first or only one in a SQL batch. It might also be needed to work around parser errors in idempotent migration scripts that can occur when referenced columns don't currently exist on a table. +> On SQL Server, use the `EXEC` function when a statement must be the first or only one in a SQL batch. It might also be needed to work around parser errors in idempotent migration scripts that can occur when referenced columns don't currently exist on a table. If your migrations need to support multiple database providers, you can use the `MigrationBuilder.ActiveProvider` property. Here's an example supporting both Microsoft SQL Server and PostgreSQL. From f443e26a76ded0a16a5abf271abc00923bf014ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Fri, 7 Mar 2025 13:46:44 +0100 Subject: [PATCH 120/224] Update standups. (#4971) --- .../core/learn-more/community-standups.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/entity-framework/core/learn-more/community-standups.md b/entity-framework/core/learn-more/community-standups.md index c08368a83a..5bd9fb96aa 100644 --- a/entity-framework/core/learn-more/community-standups.md +++ b/entity-framework/core/learn-more/community-standups.md @@ -16,6 +16,7 @@ The .NET Data Community Standups are live-streamed monthly (roughly) on Wednesda | Date | Area | Title | |--------------|-----------------------|------------------------------------------------------------------------------------------| +| Mar 06, 2025 | Chroma | [Using Chroma vector database from .NET](#Mar06_2025) | | Jan 22, 2025 | Tips | [Context pooling, FromSql and compiled queries](#Jan22_2025) | | Nov 20, 2024 | Release | [EF Core 9: Release extravaganza](#Nov20_2024) | | Jun 26, 2024 | SQL schemas | [Improve your SQL schema and scripts with .NET based static code analysis](#June26_2024) | @@ -100,6 +101,17 @@ The .NET Data Community Standups are live-streamed monthly (roughly) on Wednesda ## 2025 + + +### March 6: [Using Chroma vector database from .NET](https://www.youtube.com/live/Nj0vYJ9HVGk?si=fZG7B4dl7YlR4Saj) + +Join Jiri as he talks about Chroma vector database and fresh new library for .NET that you can use to interact with Chroma. + +Featuring: + +- [Jiri Cincura](https://www.tabsoverspaces.com/) (Host) +- [Shay Rojansky](https://www.roji.org/) (Host) + ### January 22: [Context pooling, FromSql and compiled queries](https://www.youtube.com/live/lAP2nlA6ijw?si=jq7XhqVwmLi_Yt7c) From 0a4ef68fae5fe46e207ea576c565da90250c6aa0 Mon Sep 17 00:00:00 2001 From: Ivan Stoychev Date: Mon, 10 Mar 2025 21:46:44 +0200 Subject: [PATCH 121/224] Update concurrency.md (#4972) --- entity-framework/core/saving/concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/saving/concurrency.md b/entity-framework/core/saving/concurrency.md index f125be729c..213e6eb9b8 100644 --- a/entity-framework/core/saving/concurrency.md +++ b/entity-framework/core/saving/concurrency.md @@ -53,7 +53,7 @@ Note that in addition to the `PersonId` in the WHERE clause, EF Core has added a In the normal ("optimistic") case, no concurrent update occurs and the UPDATE completes successfully, modifying the row; the database reports to EF Core that one row was affected by the UPDATE, as expected. However, if a concurrent update occurred, the UPDATE fails to find any matching rows and reports that zero were affected. As a result, EF Core's throws a , which the application must catch and handle appropriately. Techniques for doing this are detailed below, under [Resolving concurrency conflicts](#resolving-concurrency-conflicts). -While the above examples discussed *updates* to existing entities. EF also throws when attempting to *delete* a row that has been concurrently modified. However, this exception is never thrown when adding entities; while the database may indeed raise a unique constraint violation if rows with the same key are being inserted, this results in a provider-specific exception being thrown, and not . +While the above examples discussed *updates* to existing entities. EF also throws when attempting to *delete* a row that has been concurrently modified. However, this exception is generally never thrown when adding entities; while the database may indeed raise a unique constraint violation if rows with the same key are being inserted, this results in a provider-specific exception being thrown, and not . ## Native database-generated concurrency tokens From 25628f7eea0d414215ba8fa8290995f94dd1ad6f Mon Sep 17 00:00:00 2001 From: Shady Nagy Date: Thu, 13 Mar 2025 02:40:56 +0200 Subject: [PATCH 122/224] Add EntityFrameworkCore.AuditInterceptor to EF Core extensions list (#4961) This commit adds EntityFrameworkCore.AuditInterceptor to the list of available EF Core extensions. EntityFrameworkCore.AuditInterceptor is a library that provides seamless auditing capabilities for Entity Framework Core applications. It automatically tracks entity changes, recording who made the changes and when they occurred through a simple implementation of the IAuditable interface. --- entity-framework/core/extensions/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index 1fdc81fef0..26d11c5377 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -463,3 +463,9 @@ An extension library for Dynamic Data Masking (SQL Server) and MigrationBuilder An updated fork for the data masking feature can be found at [EntityFrameworkCore.Extensions.SqlServer.DataMasking](https://github.com/sander1095/EntityFrameworkCore.Extensions.SqlServer.DataMasking) [GitHub repository](https://github.com/nikitasavinov/EntityFrameworkCore.Extensions) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Extensions) + +### EntityFrameworkCore.AuditInterceptor + +A library that provides seamless auditing capabilities for Entity Framework Core. It automatically tracks entity changes including who made the changes and when they were made. The library integrates with .NET Dependency Injection and supports various auditing scenarios through a simple configuration process. For EF Core: 6-8. + +[GitHub repository](https://github.com/ShadyNagy/EntityFrameworkCore.AuditInterceptor) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.AuditInterceptor) From d2b73a8fb7b5ef17a4cb7396820ee5c9bffb9a19 Mon Sep 17 00:00:00 2001 From: Shady Nagy Date: Thu, 13 Mar 2025 22:27:28 +0200 Subject: [PATCH 123/224] Move EntityFrameworkCore.AuditInterceptor to Extensions section (#4978) --- entity-framework/core/extensions/index.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index 26d11c5377..e0377729f8 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -357,6 +357,12 @@ Persisted computed properties in EF Core that update automatically on save chang [GitHub repository](https://github.com/lucaslorentz/auto-compute) | [NuGet](https://www.nuget.org/packages/LLL.AutoCompute.EFCore) +### EntityFrameworkCore.AuditInterceptor + +A library that provides seamless auditing capabilities for Entity Framework Core. It automatically tracks entity changes including who made the changes and when they were made. The library integrates with .NET Dependency Injection and supports various auditing scenarios through a simple configuration process. For EF Core: 6-8. + +[GitHub repository](https://github.com/ShadyNagy/EntityFrameworkCore.AuditInterceptor) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.AuditInterceptor) + ## API Integrations These packages are designed to integrate directly with EF Core to expose various APIs. @@ -463,9 +469,3 @@ An extension library for Dynamic Data Masking (SQL Server) and MigrationBuilder An updated fork for the data masking feature can be found at [EntityFrameworkCore.Extensions.SqlServer.DataMasking](https://github.com/sander1095/EntityFrameworkCore.Extensions.SqlServer.DataMasking) [GitHub repository](https://github.com/nikitasavinov/EntityFrameworkCore.Extensions) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Extensions) - -### EntityFrameworkCore.AuditInterceptor - -A library that provides seamless auditing capabilities for Entity Framework Core. It automatically tracks entity changes including who made the changes and when they were made. The library integrates with .NET Dependency Injection and supports various auditing scenarios through a simple configuration process. For EF Core: 6-8. - -[GitHub repository](https://github.com/ShadyNagy/EntityFrameworkCore.AuditInterceptor) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.AuditInterceptor) From 87e50d40fc5a4c6746af2125622e209627ac3707 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 13 Mar 2025 21:32:13 +0100 Subject: [PATCH 124/224] Tweak tab headings around NRTs in properties page (#4968) Closes #4967 --- entity-framework/core/modeling/entity-properties.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/entity-framework/core/modeling/entity-properties.md b/entity-framework/core/modeling/entity-properties.md index 74c2b74d14..e6b17f6ddf 100644 --- a/entity-framework/core/modeling/entity-properties.md +++ b/entity-framework/core/modeling/entity-properties.md @@ -132,14 +132,14 @@ C# 8 introduced a new feature called [nullable reference types (NRT)](/dotnet/cs The following example shows an entity type with required and optional properties, with the nullable reference feature disabled and enabled: -#### [Without NRT (default)](#tab/without-nrt) - -[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/CustomerWithoutNullableReferenceTypes.cs?name=Customer&highlight=5,8)] - #### [With NRT](#tab/with-nrt) [!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/Customer.cs?name=Customer&highlight=4-6)] +#### [Without NRT](#tab/without-nrt) + +[!code-csharp[Main](../../../samples/core/Miscellaneous/NullableReferenceTypes/CustomerWithoutNullableReferenceTypes.cs?name=Customer&highlight=5,8)] + *** Using nullable reference types is recommended since it flows the nullability expressed in C# code to EF Core's model and to the database, and obviates the use of the Fluent API or Data Annotations to express the same concept twice. From bd8b05483d07d7974889141ce26e9146f4e8e734 Mon Sep 17 00:00:00 2001 From: Lazaro Gonzalez Date: Tue, 18 Mar 2025 09:11:08 -0400 Subject: [PATCH 125/224] EF Scaffolding many to many join Entity (#4979) --- .../managing-schemas/scaffolding/templates.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/entity-framework/core/managing-schemas/scaffolding/templates.md b/entity-framework/core/managing-schemas/scaffolding/templates.md index f0c13e8667..227c4197ef 100644 --- a/entity-framework/core/managing-schemas/scaffolding/templates.md +++ b/entity-framework/core/managing-schemas/scaffolding/templates.md @@ -178,6 +178,24 @@ For large models, the OnModelCreating method of the DbContext class can become u To scaffold these classes, you can use a third template called `EntityTypeConfiguration.t4`. Like the `EntityType.t4` template, it gets used for each entity type in the model and uses the `EntityType` template parameter. +### Generate Join Table in Many to Many Relationships + +By default, the scaffolding process does not generate an entity for join tables in simple many-to-many relationships. However, there are cases where explicitly generating the join table as an entity might be necessary (e.g., when finer control over the generated SQL query is required). + +The scaffolding behavior for each entity is controlled by the EntityType.t4 template file. Within this file, there is a condition that short-circuits entity generation for simple many-to-many join tables. To override this behavior and generate the join entity, you can comment out this condition in the 'EntityType.t4' file. + +```T4 +<# + // Comment this condition + if (EntityType.IsSimpleManyToManyJoinEntityType()) + { + // Don't scaffold these + return ""; + } + . . . +#> +``` + ### Scaffolding other types of files The primary purpose of reverse engineering in EF Core is to scaffold a DbContext and entity types. However, there's nothing in the tools that require you to actually scaffold code. For example, you could instead scaffold an entity relationship diagram using [Mermaid](https://mermaid-js.github.io/). From 2c0886d8e05e27392078e6cdb563d7fd6f0185a6 Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Tue, 18 Mar 2025 10:51:59 -0700 Subject: [PATCH 126/224] update whats new for preview2 (#4964) --- .../core/what-is-new/ef-core-10.0/whatsnew.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index bb549da8cf..1ea382ef97 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -26,7 +26,7 @@ EF10 requires the .NET 10 SDK to build and requires the .NET 10 runtime to run. -### Support for the .NET 10 LeftJoin operator +### Support for the .NET 10 `LeftJoin` and `RightJoin` operators `LEFT JOIN` is a common and useful operation when working with EF Core. In previous versions, implementing `LEFT JOIN` in LINQ was quite complicated, requiring `SelectMany`, `GroupJoin` and `DefaultIfEmpty` operations [in a particular configuration](/dotnet/csharp/linq/standard-query-operators/join-operations#perform-left-outer-joins). @@ -46,7 +46,10 @@ var query = context.Students }); ``` -See [#12793](https://github.com/dotnet/efcore/issues/12793) for more details. +> [!NOTE] +> EF 10 also supports the analogous `RightJoin` operator, which keeps all the data from the second collection and only the matching data from the first collection. EF 10 translates this to `RIGHT JOIN` operation in the database. + +See [#12793](https://github.com/dotnet/efcore/issues/12793) and [#35367](https://github.com/dotnet/efcore/issues/35367) for more details. @@ -109,3 +112,4 @@ Thanks to [@aradalvand](https://github.com/aradalvand) for proposing and pushing ## Other improvements * Make SQL Server scaffolding compatible with Azure Data Explorer ([#34832](https://github.com/dotnet/efcore/pull/34832), contributed by [@barnuri](https://github.com/barnuri)). +* Associate the DatabaseRoot with the scoped options instance and not the singleton options ([#34477](https://github.com/dotnet/efcore/pull/34477), contributed by [@koenigst](https://github.com/koenigst)). From cc5809c81634b534cd2484d67ee3fcc5bcba90da Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Tue, 18 Mar 2025 16:26:37 -0700 Subject: [PATCH 127/224] We started pointing to Preview builds, but didn't remove the tip about dailies - fixing this now. (#4984) --- entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 1ea382ef97..edbcb5c748 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -17,9 +17,6 @@ EF10 is available as a preview. See [.NET 10 release notes](https://github.com/d EF10 requires the .NET 10 SDK to build and requires the .NET 10 runtime to run. EF10 will not run on earlier .NET versions, and will not run on .NET Framework. -> [!TIP] -> The _What's New_ docs are updated for each preview. All the samples are set up to use the [EF10 daily builds](https://github.com/dotnet/efcore/blob/main/docs/DailyBuilds.md), which usually have several additional weeks of completed work compared to the latest preview. We strongly encourage use of the daily builds when testing new features so that you're not doing your testing against stale bits. - ## LINQ and SQL translation From 1d1cb814681bff6e7018568f980a9576cc5e92ad Mon Sep 17 00:00:00 2001 From: Samson Amaugo Date: Thu, 20 Mar 2025 10:30:31 +0100 Subject: [PATCH 128/224] nit: fixes statement error (#4985) --- entity-framework/core/modeling/relationships/many-to-many.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/modeling/relationships/many-to-many.md b/entity-framework/core/modeling/relationships/many-to-many.md index 4dda440966..3082666b6c 100644 --- a/entity-framework/core/modeling/relationships/many-to-many.md +++ b/entity-framework/core/modeling/relationships/many-to-many.md @@ -1006,7 +1006,7 @@ CREATE TABLE "PersonPerson" ( ## Symmetrical self-referencing many-to-many -Sometimes a many-to-many relationship is naturally symmetrical. That is, if entity A is related to entity B, then entity B is also related to entity A. This is naturally modeled using a single navigation. For example, imagine the case where is person A is friends with person B, then person B is friends with person A: +Sometimes a many-to-many relationship is naturally symmetrical. That is, if entity A is related to entity B, then entity B is also related to entity A. This is naturally modeled using a single navigation. For example, imagine the case where person A is friends with person B, and person B is friends with person A: > [!TIP] -> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Saving/Disconnected/) on GitHub. +> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Saving/Disconnected/) on GitHub. > [!TIP] > EF Core can only track one instance of any entity with a given primary key value. The best way to avoid this being an issue is to use a short-lived context for each unit-of-work such that the context starts empty, has entities attached to it, saves those entities, and then the context is disposed and discarded. diff --git a/entity-framework/core/saving/related-data.md b/entity-framework/core/saving/related-data.md index 5b5c3cfcee..7964fd9006 100644 --- a/entity-framework/core/saving/related-data.md +++ b/entity-framework/core/saving/related-data.md @@ -10,7 +10,7 @@ uid: core/saving/related-data In addition to isolated entities, you can also make use of the relationships defined in your model. > [!TIP] -> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Saving/RelatedData/) on GitHub. +> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Saving/RelatedData/) on GitHub. ## Adding a graph of new entities diff --git a/entity-framework/core/saving/transactions.md b/entity-framework/core/saving/transactions.md index 6788e93d87..6091da0723 100644 --- a/entity-framework/core/saving/transactions.md +++ b/entity-framework/core/saving/transactions.md @@ -10,7 +10,7 @@ uid: core/saving/transactions Transactions allow several database operations to be processed in an atomic manner. If the transaction is committed, all of the operations are successfully applied to the database. If the transaction is rolled back, none of the operations are applied to the database. > [!TIP] -> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Saving/Transactions/) on GitHub. +> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Saving/Transactions/) on GitHub. ## Default transaction behavior diff --git a/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md index c9b6574e1a..3ff9c8b6cd 100644 --- a/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md @@ -11,7 +11,7 @@ uid: core/what-is-new/ef-core-6.0/whatsnew EF Core 6.0 has [shipped to NuGet](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/). This page contains an overview of interesting changes introduced in this release. > [!TIP] -> You can run and debug into the samples shown below by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore6). +> You can run and debug into the samples shown below by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore6). ## SQL Server temporal tables @@ -682,7 +682,7 @@ If supporting any of these features is critical to your success, then please vot ### Benchmarks > [!TIP] -> You can try compiling a large model and running a benchmark on it by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/CompiledModels). +> You can try compiling a large model and running a benchmark on it by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/CompiledModels). The model in the GitHub repo referenced above contains 449 entity types, 6390 properties, and 720 relationships. This is a moderately large model. Using [BenchmarkDotNet](https://www.nuget.org/packages/BenchmarkDotNet) to measure, the average time to first query is 1.02 seconds on a reasonably powerful laptop. Using compiled models brings this down to 117 milliseconds on the same hardware. An 8x to 10x improvement like this stays relatively constant as the model size increases. @@ -712,7 +712,7 @@ After these improvements, the gap between the popular "micro-ORM" [Dapper](https EF Core 6.0 contains many improvements to the Azure Cosmos DB database provider. > [!TIP] -> You can run and debug into all the the Cosmos-specific samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore6.Cosmos). +> You can run and debug into all the the Cosmos-specific samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore6.Cosmos). ### Default to implicit ownership @@ -2622,7 +2622,7 @@ modelBuilder --> [!code-csharp[WithDifferentTable](../../../../samples/core/Miscellaneous/NewInEFCore6/OptionalDependentsSample.cs?name=WithDifferentTable)] -See the [OptionalDependentsSample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore6) in GitHub for more examples of optional dependents, including cases with nested optional dependents. +See the [OptionalDependentsSample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore6) in GitHub for more examples of optional dependents, including cases with nested optional dependents. ## New mapping attributes @@ -3568,7 +3568,7 @@ The EF Core codebase now uses [C# nullable reference types (NRTs)](/dotnet/cshar ## Microsoft.Data.Sqlite 6.0 > [!TIP] -> You can run and debug into all the samples shown below by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore6). +> You can run and debug into all the samples shown below by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore6). ### Connection Pooling diff --git a/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md index 1a8a775baf..99f6a091a7 100644 --- a/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md @@ -30,7 +30,7 @@ And a second aggregate type for post metadata: [!code-csharp[PostMetadataAggregate](../../../../samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs?name=PostMetadataAggregate)] > [!TIP] -> The sample model can be found in [BlogsContext.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs). +> The sample model can be found in [BlogsContext.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs). ## JSON Columns @@ -96,7 +96,7 @@ The aggregate type is configured in `OnModelCreating` using `OwnsOne`: [!code-csharp[TableSharingAggregate](../../../../samples/core/Miscellaneous/NewInEFCore7/JsonColumnsSample.cs?name=TableSharingAggregate)] > [!TIP] -> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/JsonColumnsSample.cs). +> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/JsonColumnsSample.cs). By default, relational database providers map aggregate types like this to the same table as the owning entity type. That is, each property of the `ContactDetails` and `Address` classes is mapped to a column in the `Authors` table. @@ -549,7 +549,7 @@ All of this means that the `ExecuteUpdate` and `ExecuteDelete` methods complemen ### Basic `ExecuteDelete` examples > [!TIP] -> The code shown here comes from [ExecuteDeleteSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ExecuteDeleteSample.cs). +> The code shown here comes from [ExecuteDeleteSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ExecuteDeleteSample.cs). Calling `ExecuteDelete` or `ExecuteDeleteAsync` on a `DbSet` immediately deletes all entities of that `DbSet` from the database. For example, to delete all `Tag` entities: @@ -602,7 +602,7 @@ WHERE NOT EXISTS ( ### Basic `ExecuteUpdate` examples > [!TIP] -> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ExecuteUpdateSample.cs). +> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ExecuteUpdateSample.cs). `ExecuteUpdate` and `ExecuteUpdateAsync` behave in a very similar way to the `ExecuteDelete` methods. The main difference is that an update requires knowing _which_ properties to update, and _how_ to update them. This is achieved using one or more calls to `SetProperty`. For example, to update the `Name` of every blog: @@ -790,7 +790,7 @@ Some examples of these improvements are shown below. > See [Announcing Entity Framework Core 7 Preview 6: Performance Edition](https://devblogs.microsoft.com/dotnet/announcing-ef-core-7-preview6-performance-optimizations/) on the .NET Blog for an in-depth discussion of these changes. > [!TIP] -> The code shown here comes from [SaveChangesPerformanceSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/SaveChangesPerformanceSample.cs). +> The code shown here comes from [SaveChangesPerformanceSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/SaveChangesPerformanceSample.cs). ### Unneeded transactions are eliminated @@ -1020,7 +1020,7 @@ In addition, different database systems require different SQL for many of these By default, EF Core maps an inheritance hierarchy of .NET types to a single database table. This is known as the [table-per-hierarchy (TPH)](xref:core/modeling/inheritance#table-per-hierarchy-and-discriminator-configuration) mapping strategy. EF Core 5.0 introduced the [table-per-type (TPT)](xref:core/modeling/inheritance#table-per-type-configuration) strategy, which supports mapping each .NET type to a different database table. EF7 introduces the table-per-concrete-type (TPC) strategy. TPC also maps .NET types to different tables, but in a way that addresses some common performance issues with the TPT strategy. > [!TIP] -> The code shown here comes from [TpcInheritanceSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/TpcInheritanceSample.cs). +> The code shown here comes from [TpcInheritanceSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/TpcInheritanceSample.cs). > [!TIP] > The EF Team demonstrated and talked in depth about TPC mapping in an episode of the .NET Data Community Standup. As with [all Community Standup episodes](https://aka.ms/efstandups), you can [watch the TPC episode now on YouTube](https://youtu.be/HaL6DKW1mrg). @@ -1486,7 +1486,7 @@ protected override void ConfigureConventions(ModelConfigurationBuilder configura > To find all built-in model building conventions, look for every class that implements the interface. > [!TIP] -> The code shown here comes from [ModelBuildingConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingConventionsSample.cs). +> The code shown here comes from [ModelBuildingConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingConventionsSample.cs). ### Removing an existing convention @@ -2324,7 +2324,7 @@ The following sections show some examples of using these new interception capabi ### Simple actions on entity creation > [!TIP] -> The code shown here comes from [SimpleMaterializationSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/SimpleMaterializationSample.cs). +> The code shown here comes from [SimpleMaterializationSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/SimpleMaterializationSample.cs). The new supports interception before and after an entity instance is created, and before and after properties of that instance are initialized. The interceptor can change or replace the entity instance at each point. This allows: @@ -2418,7 +2418,7 @@ Customer 'Alice' was retrieved at '9/22/2022 5:25:54 PM' ### Injecting services into entities > [!TIP] -> The code shown here comes from [InjectLoggerSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/InjectLoggerSample.cs). +> The code shown here comes from [InjectLoggerSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/InjectLoggerSample.cs). EF Core already has built-in support for injecting some special services into context instances; for example, see [Lazy loading without proxies](xref:core/querying/related-data/lazy#lazy-loading-without-proxies), which works by injecting the `ILazyLoader` service. @@ -2503,7 +2503,7 @@ info: CustomersLogger[1] ### LINQ expression tree interception > [!TIP] -> The code shown here comes from [QueryInterceptionSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/QueryInterceptionSample.cs). +> The code shown here comes from [QueryInterceptionSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/QueryInterceptionSample.cs). EF Core makes use of [.NET LINQ queries](xref:core/querying/how-query-works). This typically involves using the C#, VB, or F# compiler to build an expression tree which is then translated by EF Core into the appropriate SQL. For example, consider a method that returns a page of customers: @@ -2649,7 +2649,7 @@ In this case the `ThenBy` is simply added to the query. Yes, it may need to be d ### Optimistic concurrency interception > [!TIP] -> The code shown here comes from [OptimisticConcurrencyInterceptionSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/OptimisticConcurrencyInterceptionSample.cs). +> The code shown here comes from [OptimisticConcurrencyInterceptionSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/OptimisticConcurrencyInterceptionSample.cs). EF Core supports the [optimistic concurrency pattern](xref:core/saving/concurrency) by checking that the number of rows actually affected by an update or delete is the same as the number of rows expected to be affected. This is often coupled with a concurrency token; that is, a column value that will only match its expected value if the row has not been updated since the expected value was read. @@ -2694,7 +2694,7 @@ There are several things worth noting about this interceptor: ### Lazy initialization of a connection string > [!TIP] -> The code shown here comes from [LazyConnectionStringSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/LazyConnectionStringSample.cs). +> The code shown here comes from [LazyConnectionStringSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/LazyConnectionStringSample.cs). Connection strings are often static assets read from a configuration file. These can easily be passed to `UseSqlServer` or similar when configuring a `DbContext`. However, sometimes the connection string can change for each context instance. For example, each tenant in a multi-tenant system may have a different connection string. @@ -2783,7 +2783,7 @@ Finally, the interceptor uses this service to obtain the connection string async ### Logging SQL Server query statistics > [!TIP] -> The code shown here comes from [QueryStatisticsLoggerSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/QueryStatisticsLoggerSample.cs). +> The code shown here comes from [QueryStatisticsLoggerSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/QueryStatisticsLoggerSample.cs). Finally, let's create two interceptors that work together to send SQL Server query statistics to the application log. To generate the statistics, we need an to do two things. @@ -2870,7 +2870,7 @@ EF7 contains many improvements in the translation of LINQ queries. ### GroupBy as final operator > [!TIP] -> The code shown here comes from [GroupByFinalOperatorSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs). +> The code shown here comes from [GroupByFinalOperatorSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs). EF7 supports using `GroupBy` as the final operator in a query. For example, this LINQ query: @@ -2893,7 +2893,7 @@ ORDER BY [b].[Price] ### GroupJoin as final operator > [!TIP] -> The code shown here comes from [GroupJoinFinalOperatorSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs). +> The code shown here comes from [GroupJoinFinalOperatorSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs). EF7 supports using `GroupJoin` as the final operator in a query. For example, this LINQ query: @@ -2919,7 +2919,7 @@ ORDER BY [c].[Id] ### GroupBy entity type > [!TIP] -> The code shown here comes from [GroupByEntityTypeSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs). +> The code shown here comes from [GroupByEntityTypeSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs). EF7 supports grouping by an entity type. For example, this LINQ query: @@ -2961,7 +2961,7 @@ FROM [Authors] AS [a] ### Subqueries don't reference ungrouped columns from outer query > [!TIP] -> The code shown here comes from [UngroupedColumnsQuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/UngroupedColumnsQuerySample.cs). +> The code shown here comes from [UngroupedColumnsQuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/UngroupedColumnsQuerySample.cs). In EF Core 6.0, a `GROUP BY` clause would reference columns in the outer query, which fails with some databases and is inefficient in others. For example, consider the following query: @@ -3005,7 +3005,7 @@ GROUP BY [t].[Key] ### Read-only collections can be used for `Contains` > [!TIP] -> The code shown here comes from [ReadOnlySetQuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ReadOnlySetQuerySample.cs). +> The code shown here comes from [ReadOnlySetQuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ReadOnlySetQuerySample.cs). EF7 supports using `Contains` when the items to search for are contained in an `IReadOnlySet` or `IReadOnlyCollection`, or `IReadOnlyList`. For example, this LINQ query: @@ -3040,7 +3040,7 @@ EF7 introduces better extensibility for providers to translate aggregate functio #### String aggregate functions > [!TIP] -> The code shown here comes from [StringAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/StringAggregateFunctionsSample.cs). +> The code shown here comes from [StringAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/StringAggregateFunctionsSample.cs). Queries using and are now translated when appropriate. For example: @@ -3109,7 +3109,7 @@ ORDER BY [t].[Name] #### Spatial aggregate functions > [!TIP] -> The code shown here comes from [SpatialAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/SpatialAggregateFunctionsSample.cs). +> The code shown here comes from [SpatialAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/SpatialAggregateFunctionsSample.cs). It is now possible for [database providers that support for NetTopologySuite](xref:core/modeling/spatial) to translate the following spatial aggregate functions: @@ -3147,7 +3147,7 @@ GROUP BY [c].[Owner] #### Statistical aggregate functions > [!TIP] -> The code shown here comes from [StatisticalAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/StatisticalAggregateFunctionsSample.cs). +> The code shown here comes from [StatisticalAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/StatisticalAggregateFunctionsSample.cs). SQL Server translations have been implemented for the following statistical functions: @@ -3190,7 +3190,7 @@ GROUP BY [u].[Id] ### Translation of `string.IndexOf` > [!TIP] -> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). +> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). EF7 now translates in LINQ queries. For example: @@ -3212,7 +3212,7 @@ WHERE (CAST(CHARINDEX(N'Entity', [p].[Content]) AS int) - 1) > 0 ### Translation of `GetType` for entity types > [!TIP] -> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). +> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). EF7 now translates in LINQ queries. For example: @@ -3248,7 +3248,7 @@ And will return both `Post` and `FeaturedPost` entities. ### Support for `AT TIME ZONE` > [!TIP] -> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). +> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). EF7 introduces new functions for and . These functions translate to `AT TIME ZONE` clauses in the generated SQL. For example: @@ -3276,7 +3276,7 @@ FROM [Posts] AS [p] ### Filtered Include on hidden navigations > [!TIP] -> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). +> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). The [Include methods](xref:core/querying/related-data/eager) can now be used with . This allows [filtering and ordering](xref:core/querying/related-data/eager#filtered-include) even for private navigation properties, or private navigations represented by fields. For example: @@ -3315,7 +3315,7 @@ ORDER BY [b].[Id], [t].[Title] ### Cosmos translation for `Regex.IsMatch` > [!TIP] -> The code shown here comes from [CosmosQueriesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/CosmosQueriesSample.cs). +> The code shown here comes from [CosmosQueriesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/CosmosQueriesSample.cs). EF7 supports using in LINQ queries against Azure Cosmos DB. For example: @@ -3339,7 +3339,7 @@ WHERE ((c["Discriminator"] = "Triangle") AND RegexMatch(c["Name"], "[a-z]t[a-z]" EF7 contains a variety of small improvements to and related classes. > [!TIP] -> The code for samples in this section comes from [DbContextApiSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/DbContextApiSample.cs). +> The code for samples in this section comes from [DbContextApiSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/DbContextApiSample.cs). ### Suppressor for uninitialized DbSet properties @@ -3553,7 +3553,7 @@ Notice: EF7 contains a variety of small improvements in model building. > [!TIP] -> The code for samples in this section comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs). +> The code for samples in this section comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs). ### Indexes can be ascending or descending @@ -4067,7 +4067,7 @@ If these types are mapped to the same table, then in EF7 that table can be made EF7 includes two significant improvements to the automatic generation of values for key properties. > [!TIP] -> The code for samples in this section comes from [ValueGenerationSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ValueGenerationSample.cs). +> The code for samples in this section comes from [ValueGenerationSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ValueGenerationSample.cs). ### Value generation for DDD guarded types @@ -4331,4 +4331,4 @@ public partial class MainForm : Form } ``` -See [Getting Started with Windows Forms](xref:core/get-started/winforms) for a complete walkthrough and [downloadable WinForms sample application](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/WinForms). +See [Getting Started with Windows Forms](xref:core/get-started/winforms) for a complete walkthrough and [downloadable WinForms sample application](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/WinForms). diff --git a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md index 7305ee98a0..ddde4a3f15 100644 --- a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md @@ -665,7 +665,7 @@ The first option has advantages in many situations--we'll take a quick look at i Starting with Preview 4, EF8 now includes built-in support for the second option, using JSON as the serialization format. JSON works well for this since modern relational databases include built-in mechanisms for querying and manipulating JSON, such that the JSON column can, effectively, be treated as a table when needed, without the overhead of actually creating that table. These same mechanisms allow JSON to be passed in parameters and then used in similar way to table-valued parameters in queries--more about this later. > [!TIP] -> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs). +> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs). ### Primitive collection properties @@ -1017,7 +1017,7 @@ In all the examples above, column for primitive collection contains JSON. Howeve [!code-csharp[Pub](../../../../samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs?name=Pub)] > [!TIP] -> The code shown here comes from [PrimitiveCollectionsInJsonSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs). +> The code shown here comes from [PrimitiveCollectionsInJsonSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs). We can now run a variation of our final query that, this time, extracts data from the JSON document, including queries into the primitive collections contained in the document: @@ -1120,7 +1120,7 @@ CREATE TABLE [Beer] ( EF8 includes improvements to the [JSON column mapping support introduced in EF7](xref:core/what-is-new/ef-core-7.0/whatsnew#json-columns). > [!TIP] -> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs). +> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs). ### Translate element access into JSON arrays @@ -1241,7 +1241,7 @@ EF7 introduced support for mapping to JSON columns when using Azure SQL/SQL Serv The existing [documentation from What's New in EF7](xref:core/what-is-new/ef-core-7.0/whatsnew#json-columns) provides detailed information on JSON mapping, queries, and updates. This documentation now also applies to SQLite. > [!TIP] -> The code shown in the EF7 documentation has been updated to also run on SQLite can can be found in [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs). +> The code shown in the EF7 documentation has been updated to also run on SQLite can can be found in [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs). #### Queries into JSON columns @@ -1347,7 +1347,7 @@ The `HierarchyId` type can be used for properties of an entity type. For example [!code-csharp[Halfling](../../../../samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs?name=Halfling)] > [!TIP] -> The code shown here and in the examples below comes from [HierarchyIdSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs). +> The code shown here and in the examples below comes from [HierarchyIdSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs). > [!TIP] > If desired, `HierarchyId` is suitable for use as a key property type. @@ -1661,7 +1661,7 @@ Following the update, querying for the descendents of "Mungo" returns "Bungo", " EF7 introduced [raw SQL queries returning scalar types](xref:core/querying/sql-queries#querying-scalar-(non-entity)-types). This is enhanced in EF8 to include raw SQL queries returning any mappable CLR type, without including that type in the EF model. > [!TIP] -> The code shown here comes from [RawSqlSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/RawSqlSample.cs). +> The code shown here comes from [RawSqlSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/RawSqlSample.cs). Queries using unmapped types are executed using or . The former uses string interpolation to parameterize the query, which helps ensure that all non-constant values are parameterized. For example, consider the following database table: @@ -1850,7 +1850,7 @@ The returned `IQueryable` can be composed upon when it is the result of a view o EF8 adds support for [lazy-loading of navigations](xref:core/querying/related-data/lazy) on entities that are not being tracked by the `DbContext`. This means a no-tracking query can be followed by lazy-loading of navigations on the entities returned by the no-tracking query. > [!TIP] -> The code for the lazy-loading examples shown below comes from [LazyLoadingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/LazyLoadingSample.cs). +> The code for the lazy-loading examples shown below comes from [LazyLoadingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/LazyLoadingSample.cs). For example, consider a no-tracking query for blogs: @@ -1943,7 +1943,7 @@ EF8 contains new public APIs so that applications can now use these data structu [!code-csharp[LookupByPrimaryKey](../../../../samples/core/Miscellaneous/NewInEFCore8/LookupByKeySample.cs?name=LookupByPrimaryKey)] > [!TIP] -> The code shown here comes from [LookupByKeySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/LookupByKeySample.cs). +> The code shown here comes from [LookupByKeySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/LookupByKeySample.cs). The [`FindEntry`](https://github.com/dotnet/efcore/blob/81886272a761df8fafe4970b895b1e1fe35effb8/src/EFCore/ChangeTracking/LocalView.cs#L543) method returns either the for the tracked entity, or `null` if no entity with the given key is being tracked. Like all methods on `LocalView`, the database is never queried, even if the entity is not found. The returned entry contains the entity itself, as well as tracking information. For example: @@ -2082,7 +2082,7 @@ public class OpeningHours [!code-csharp[BritishSchools](../../../../samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs?name=BritishSchools)] > [!TIP] -> The code shown here comes from [DateOnlyTimeOnlySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs). +> The code shown here comes from [DateOnlyTimeOnlySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs). > [!NOTE] > This model represents only British schools and stores times as local (GMT) times. Handling different timezones would complicate this code significantly. Note that using `DateTimeOffset` would not help here, since opening and closing times have different offsets depending whether daylight saving time is active or not. @@ -2283,7 +2283,7 @@ b.Property(e => e.LeaseDate).HasDefaultValueSql("getutcdate()"); ``` > [!TIP] -> The code shown below comes from [DefaultConstraintSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs). +> The code shown below comes from [DefaultConstraintSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs). In order for EF to make use of this, it must determine when and when not to send a value for the column. By default, EF uses the CLR default as a sentinel for this. That is, when the value of `Status` or `LeaseDate` in the examples above are the CLR defaults for these types, then EF _interprets that to mean that the property has not been set_, and so does not send a value to the database. This works well for reference types--for example, if the `string` property `Status` is `null`, then EF doesn't send `null` to the database, but rather does not include any value so that the database default (`"Hidden"`) is used. Likewise, for the `DateTime` property `LeaseDate`, EF will not insert the CLR default value of `1/1/0001 12:00:00 AM`, but will instead omit this value so that database default is used. 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 1369efacc5..ba314af688 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 @@ -75,7 +75,7 @@ To learn more about querying with partition keys and point reads, [see the query ### Hierarchical partition keys > [!TIP] -> The code shown here comes from [HierarchicalPartitionKeysSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs). +> The code shown here comes from [HierarchicalPartitionKeysSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs). Azure Cosmos DB originally supported a single partition key, but has since expanded partitioning capabilities to also support [subpartitioning through the specification of up to three levels of hierarchy in the partition key](/azure/cosmos-db/hierarchical-partition-keys). EF Core 9 brings full support for hierarchical partition keys, allowing you take advantage of the better performance and cost savings associated with this feature. @@ -342,7 +342,7 @@ We'd like to call out Andrea Canciani ([@ranma42](https://github.com/ranma42)) f #### GroupBy > [!TIP] -> The code shown here comes from [ComplexTypesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs). +> The code shown here comes from [ComplexTypesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs). EF9 supports grouping by a complex type instance. For example: @@ -365,7 +365,7 @@ GROUP BY [s].[StoreAddress_City], [s].[StoreAddress_Country], [s].[StoreAddress_ #### ExecuteUpdate > [!TIP] -> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs). +> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs). Similarly, in EF9 `ExecuteUpdate` has also been improved to accept complex type properties. However, each member of the complex type must be specified explicitly. For example: @@ -506,7 +506,7 @@ FROM ( ### Translations involving GREATEST/LEAST > [!TIP] -> The code shown here comes from [LeastGreatestSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/LeastGreatestSample.cs). +> The code shown here comes from [LeastGreatestSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/LeastGreatestSample.cs). Several new translations have been introduced that use the `GREATEST` and `LEAST` SQL functions. @@ -584,7 +584,7 @@ FROM [Pubs] AS [p] ### Force or prevent query parameterization > [!TIP] -> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). +> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). Except in some special cases, EF Core parameterizes variables used in a LINQ query, but includes constants in the generated SQL. For example, consider the following query method: @@ -710,7 +710,7 @@ Moreover, EF9 introduces `TranslateParameterizedCollectionsToConstants` [context ### Inlined uncorrelated subqueries > [!TIP] -> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). +> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). In EF8, an IQueryable referenced in another query may be executed as a separate database roundtrip. For example, consider the following LINQ query: @@ -824,7 +824,7 @@ var topRatedPostsAverageRatingByLanguage = await context.Blogs. ### Queries using Count != 0 are optimized > [!TIP] -> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). +> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). In EF8, the following LINQ query was translated to use the SQL `COUNT` function: @@ -1121,7 +1121,7 @@ More information can be found [here](/ef/core/modeling/data-seeding#use-seeding- ### 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. +> The code shown here comes from the [NewInEFCore9.CompiledModels](https://github.com/dotnet/EntityFramework.Docs/tree/live/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: @@ -1221,7 +1221,7 @@ For more information see [MSBuild integration](xref:core/cli/msbuild). ### Read-only primitive collections > [!TIP] -> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs). +> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs). EF8 introduced support for [mapping arrays and mutable lists of primitive types](xref:core/what-is-new/ef-core-8.0/whatsnew#primitive-collections). This has been expanded in EF9 to include read-only collections/lists. Specifically, EF9 supports collections typed as `IReadOnlyList`, `IReadOnlyCollection`, or `ReadOnlyCollection`. For example, in the following code, `DaysVisited` will be mapped by convention as a primitive collection of dates: @@ -1281,7 +1281,7 @@ INNER JOIN "Pubs" AS "p" ON "w"."ClosestPubId" = "p"."Id" ### Specify fill-factor for keys and indexes > [!TIP] -> The code shown here comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs). +> The code shown here comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs). EF9 supports specification of the [SQL Server fill-factor](/sql/relational-databases/indexes/specify-fill-factor-for-an-index) when using EF Core Migrations to create keys and indexes. From the SQL Server docs, "When an index is created or rebuilt, the fill-factor value determines the percentage of space on each leaf-level page to be filled with data, reserving the remainder on each page as free space for future growth." @@ -1328,7 +1328,7 @@ This enhancement was contributed by [@deano-hunter](https://github.com/deano-hun ### Make existing model building conventions more extensible > [!TIP] -> The code shown here comes from [CustomConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/CustomConventionsSample.cs). +> The code shown here comes from [CustomConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/CustomConventionsSample.cs). Public model building conventions for applications were [introduced in EF7](xref:core/modeling/bulk-configuration#Conventions). In EF9, we have made it easier to extend some of the existing conventions. For example, [the code to map properties by attribute in EF7](xref:core/what-is-new/ef-core-7.0/whatsnew#model-building-conventions) is this: @@ -1451,7 +1451,7 @@ As an aside, some people think this pattern is an abomination because it couples ## SQL Server HierarchyId > [!TIP] -> The code shown here comes from [HierarchyIdSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/HierarchyIdSample.cs). +> The code shown here comes from [HierarchyIdSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/HierarchyIdSample.cs). From 42c9fd15a6a52d2d3d0dfe04bb0a1300bdb9d0ac Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 10 Jun 2025 21:55:58 +0200 Subject: [PATCH 162/224] What's new updates for 10.0-preview.5 (#5034) --- entity-framework/core/modeling/generated-properties.md | 5 ++--- .../core/what-is-new/ef-core-10.0/whatsnew.md | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/entity-framework/core/modeling/generated-properties.md b/entity-framework/core/modeling/generated-properties.md index 05babfd5dc..e66635a33a 100644 --- a/entity-framework/core/modeling/generated-properties.md +++ b/entity-framework/core/modeling/generated-properties.md @@ -22,7 +22,7 @@ You can also specify a SQL fragment that is used to calculate the default value: [!code-csharp[Main](../../../samples/core/Modeling/GeneratedProperties/FluentAPI/DefaultValueSql.cs?name=DefaultValueSql&highlight=3)] -Starting with EF 10, for SQL Server you can explicitly specify the name for default value constraints, giving you more control over your database schema. +Starting with EF 10, for SQL Server you can explicitly specify the name for default value constraints, giving you more control over your database schema. [!code-csharp[Main](../../../samples/core/Modeling/GeneratedProperties/FluentAPI/DefaultValue.cs?name=DefaultValueNamed&highlight=3)] @@ -33,8 +33,7 @@ You can also call `UseNamedDefaultConstraints` to enable automatic naming of all ```C# protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder - .UseNamedDefaultConstraints(); + modelBuilder.UseNamedDefaultConstraints(); } ``` diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 66582ece20..b95d083a92 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -139,6 +139,7 @@ See [#12793](https://github.com/dotnet/efcore/issues/12793) and [#35367](https:/ - Translate `COALESCE` as `ISNULL` on SQL Server, for most cases ([#34171](https://github.com/dotnet/efcore/pull/34171), contributed by [@ranma42](https://github.com/ranma42)). - Support some string functions taking `char` as arguments ([#34999](https://github.com/dotnet/efcore/pull/34999), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). - Support `MAX`/`MIN`/`ORDER BY` using `decimal` on SQLite ([#35606](https://github.com/dotnet/efcore/pull/35606), contributed by [@ranma42](https://github.com/ranma42)). +- Support projecting different navigations (but same type) via conditional operator ([#34589](https://github.com/dotnet/efcore/issues/34589), contributed by [@ranma42](https://github.com/ranma42)). ## ExecuteUpdateAsync now accepts a regular, non-expression lambda @@ -187,11 +188,11 @@ Thanks to [@aradalvand](https://github.com/aradalvand) for proposing and pushing -## Custom Default Constraint Names +## Custom default constraint names -In previous versions of EF Core, when you specified a default value for a property, EF Core would always let the database automatically generate a constraint name. Now, you can explicitly specify the name for default value constraints for SQL Server, giving you more control over your database schema. +In previous versions of EF Core, when you specified a default value for a property, EF Core would always let the database automatically generate a constraint name. Now, you can explicitly specify the name for default value constraints for SQL Server, giving you more control over your database schema. -You can now specify a constraint name when defining default values in your model configuration: +You can now specify a constraint name when defining default values in your model configuration: ```C# protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -212,8 +213,7 @@ You can also call `UseNamedDefaultConstraints` to enable automatic naming of all ```C# protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder - .UseNamedDefaultConstraints(); + modelBuilder.UseNamedDefaultConstraints(); } ``` From 7af2cec0e462454c446a2c2ebe2397562d61d90b Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 10 Jun 2025 13:12:16 -0700 Subject: [PATCH 163/224] Update build-samples image (#5036) --- .github/workflows/build-samples.yml | 25 ++++++------------- .../GeneratedProperties.csproj | 4 +-- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build-samples.yml b/.github/workflows/build-samples.yml index ee0f154c42..50bfd5fd7d 100644 --- a/.github/workflows/build-samples.yml +++ b/.github/workflows/build-samples.yml @@ -2,13 +2,13 @@ name: Build Samples on: push: - branches: [main] + branches: [live] paths: - "samples/core/**" - "samples/end2end/**" - ".github/workflows/build-samples.yml" pull_request: - branches: [main] + branches: [live] paths: - "samples/core/**" - "samples/end2end/**" @@ -16,27 +16,16 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - name: Setup .NET Core 3.1 SDK - uses: actions/setup-dotnet@v1 + - name: Setup .NET 10.0 SDK + uses: actions/setup-dotnet@v4 with: - dotnet-version: 3.1.x - - - name: Setup .NET 6.0 SDK - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 6.0.x - include-prerelease: true - - - name: Setup .NET 8.0 SDK - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 8.0.x + dotnet-version: 10.0.x include-prerelease: true - name: Build samples diff --git a/samples/core/Modeling/GeneratedProperties/GeneratedProperties.csproj b/samples/core/Modeling/GeneratedProperties/GeneratedProperties.csproj index 4f9926d3d5..65a94c2408 100644 --- a/samples/core/Modeling/GeneratedProperties/GeneratedProperties.csproj +++ b/samples/core/Modeling/GeneratedProperties/GeneratedProperties.csproj @@ -2,13 +2,13 @@ Exe - net8.0 + net10.0 EFModeling.GeneratedProperties EFModeling.GeneratedProperties - + From b27072128f4e05994f8ba0cd1092c97aea5430a6 Mon Sep 17 00:00:00 2001 From: Taylor Southwick Date: Fri, 13 Jun 2025 14:28:36 -0700 Subject: [PATCH 164/224] Highlight that migrating from EF6->EF Core requires being off .NET Framework (#5051) It also removes a comment around ApiPort that is no longer valid since that tool has been deprecated and is unavailable. Co-authored-by: Shay Rojansky --- entity-framework/efcore-and-ef6/porting/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/entity-framework/efcore-and-ef6/porting/index.md b/entity-framework/efcore-and-ef6/porting/index.md index 303b97f09a..434766a0f9 100644 --- a/entity-framework/efcore-and-ef6/porting/index.md +++ b/entity-framework/efcore-and-ef6/porting/index.md @@ -13,8 +13,9 @@ Entity Framework Core, or EF Core for short, is a total rewrite of Entity Framew > [!IMPORTANT] > Before you start the porting process it is important to validate that EF Core meets the data access requirements for your application. You can find everything you need in the [EF Core documentation](xref:core/index). -> [!IMPORTANT] -> There is a known issue ([microsoft/dotnet-apiport #993](https://github.com/microsoft/dotnet-apiport/issues/993)) with the [portability analyzer](/dotnet/standard/analyzers/portability-analyzer) that erroneously reports EF Core as incompatible with .NET 5 and .NET 6. These warnings can be safely ignored as EF Core is 100% compatible with .NET 5 and .NET 6 target frameworks. +> [!WARNING] +> EF Core only supports modern .NET, and does not support .NET Framework. +> As such, if your project is still targeting .NET Framework, you will have to migrate to modern .NET before you can start your migration from EF6 to EF Core. Note that EF6 supports modern .NET, so you can migrate to modern .NET first while keeping EF6, and then tackle the migration from EF6 to EF Core. ## Reasons to upgrade From 2a99d6206d2014ef8182ee46ce5089853b4ac96d Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sat, 14 Jun 2025 02:35:29 +0200 Subject: [PATCH 165/224] Remove older "new feature" notes (#5048) --- .../core/logging-events-diagnostics/metrics.md | 2 +- entity-framework/core/miscellaneous/async.md | 2 +- .../core/miscellaneous/nullable-reference-types.md | 2 +- entity-framework/core/modeling/bulk-configuration.md | 3 --- entity-framework/core/modeling/entity-properties.md | 2 +- entity-framework/core/modeling/indexes.md | 3 --- entity-framework/core/modeling/inheritance.md | 3 --- entity-framework/core/modeling/keys.md | 3 --- .../core/modeling/relationships/many-to-many.md | 3 --- entity-framework/core/providers/sql-server/columns.md | 2 +- entity-framework/core/querying/sql-queries.md | 7 ------- .../core/saving/execute-insert-update-delete.md | 3 --- entity-framework/core/saving/index.md | 3 --- 13 files changed, 5 insertions(+), 33 deletions(-) diff --git a/entity-framework/core/logging-events-diagnostics/metrics.md b/entity-framework/core/logging-events-diagnostics/metrics.md index 63df417f76..8ff310efbf 100644 --- a/entity-framework/core/logging-events-diagnostics/metrics.md +++ b/entity-framework/core/logging-events-diagnostics/metrics.md @@ -19,7 +19,7 @@ Entity Framework Core (EF Core) exposes continuous numeric metrics which can pro EF Core reports metrics via the standard API. `Microsoft.EntityFrameworkCore` is the name of the meter. It's recommended to read [.NET documentation on metrics](/dotnet/core/diagnostics/metrics). > [!NOTE] -> This feature is being introduced in EF Core 9.0 (in preview). [See event counters below](#event-counters-legacy) for older versions of EF Core. +> This feature was introduced in EF Core 9.0. [See event counters below](#event-counters-legacy) for older versions of EF Core. ### Metrics and their meaning diff --git a/entity-framework/core/miscellaneous/async.md b/entity-framework/core/miscellaneous/async.md index 75d01c4742..7360e38ec8 100644 --- a/entity-framework/core/miscellaneous/async.md +++ b/entity-framework/core/miscellaneous/async.md @@ -53,4 +53,4 @@ await foreach (var blog in blogs) ``` > [!NOTE] -> LINQ operators over were introduced in .NET 10. When using an older version of .NET, reference the [`System.Linq.Async` package](https://www.nuget.org/packages/System.Linq.Async). +> LINQ operators over are being introduced in .NET 10. When using an older version of .NET, reference the [`System.Linq.Async` package](https://www.nuget.org/packages/System.Linq.Async). diff --git a/entity-framework/core/miscellaneous/nullable-reference-types.md b/entity-framework/core/miscellaneous/nullable-reference-types.md index 361b84fdb9..5c000b5f22 100644 --- a/entity-framework/core/miscellaneous/nullable-reference-types.md +++ b/entity-framework/core/miscellaneous/nullable-reference-types.md @@ -7,7 +7,7 @@ uid: core/miscellaneous/nullable-reference-types --- # Working with Nullable Reference Types -C# 8 introduced a new feature called [nullable reference types (NRT)](/dotnet/csharp/tutorials/nullable-reference-types), allowing reference types to be annotated, indicating whether it is valid for them to contain `null` or not. If you are new to this feature, it is recommended that you make yourself familiar with it by reading the C# docs. Nullable reference types are enabled by default in new project templates, but remain disabled in existing projects unless explicitly opted into. +C# [nullable reference types (NRT)](/dotnet/csharp/tutorials/nullable-reference-types) allow reference types to be annotated, indicating whether it is valid for them to contain `null` or not. If you are new to this feature, it is recommended that you make yourself familiar with it by reading the C# docs. Nullable reference types are enabled by default in new project templates, but remain disabled in existing projects unless explicitly opted into. This page introduces EF Core's support for nullable reference types, and describes best practices for working with them. diff --git a/entity-framework/core/modeling/bulk-configuration.md b/entity-framework/core/modeling/bulk-configuration.md index 7bce6cfc7b..f553cd7bf7 100644 --- a/entity-framework/core/modeling/bulk-configuration.md +++ b/entity-framework/core/modeling/bulk-configuration.md @@ -75,9 +75,6 @@ Generally, EF is able to translate queries with constants of a type that is not ## Conventions -> [!NOTE] -> Custom model building conventions were introduced in EF Core 7.0. - EF Core model building conventions are classes that contain logic that is triggered based on changes being made to the model as it is being built. This keeps the model up-to-date as explicit configuration is made, mapping attributes are applied, and other conventions run. To participate in this, every convention implements one or more interfaces which determine when the corresponding method will be triggered. For example, a convention that implements will be triggered whenever a new entity type is added to the model. Likewise, a convention that implements both and will be triggered whenever either a key or a foreign key is added to the model. Model building conventions are a powerful way to control the model configuration, but can be complex and hard to get right. In many cases, the [pre-convention model configuration](#pre-convention-configuration) can be used instead to easily specify common configuration for properties and types. diff --git a/entity-framework/core/modeling/entity-properties.md b/entity-framework/core/modeling/entity-properties.md index e6b17f6ddf..3f378076b7 100644 --- a/entity-framework/core/modeling/entity-properties.md +++ b/entity-framework/core/modeling/entity-properties.md @@ -125,7 +125,7 @@ A property is considered optional if it is valid for it to contain `null`. If `n By convention, a property whose .NET type can contain null will be configured as optional, whereas properties whose .NET type cannot contain null will be configured as required. For example, all properties with .NET value types (`int`, `decimal`, `bool`, etc.) are configured as required, and all properties with nullable .NET value types (`int?`, `decimal?`, `bool?`, etc.) are configured as optional. -C# 8 introduced a new feature called [nullable reference types (NRT)](/dotnet/csharp/tutorials/nullable-reference-types), which allows reference types to be annotated, indicating whether it is valid for them to contain null or not. This feature is enabled by default in new project templates, but remains disabled in existing projects unless explicitly opted into. Nullable reference types affect EF Core's behavior in the following way: +C# [nullable reference types (NRT)](/dotnet/csharp/tutorials/nullable-reference-types) allow reference types to be annotated, indicating whether it is valid for them to contain null or not. This feature is enabled by default in new project templates, but remains disabled in existing projects unless explicitly opted into. Nullable reference types affect EF Core's behavior in the following way: * If nullable reference types are disabled, all properties with .NET reference types are configured as optional by convention (for example, `string`). * If nullable reference types are enabled, properties will be configured based on the C# nullability of their .NET type: `string?` will be configured as optional, but `string` will be configured as required. diff --git a/entity-framework/core/modeling/indexes.md b/entity-framework/core/modeling/indexes.md index 5bb71104bd..003ca0c9cb 100644 --- a/entity-framework/core/modeling/indexes.md +++ b/entity-framework/core/modeling/indexes.md @@ -58,9 +58,6 @@ Attempting to insert more than one entity with the same values for the index's c ## Index sort order -> [!NOTE] -> This feature is being introduced in EF Core 7.0. - In most databases, each column covered by an index can be either ascending or descending. For indexes covering only one column, this typically does not matter: the database can traverse the index in reverse order as needed. However, for composite indexes, the ordering can be crucial for good performance, and can mean the difference between an index getting used by a query or not. In general, the index columns' sort orders should correspond to those specified in the `ORDER BY` clause of your query. The index sort order is ascending by default. You can make all columns have descending order as follows: diff --git a/entity-framework/core/modeling/inheritance.md b/entity-framework/core/modeling/inheritance.md index 67a4161df7..0fa7c0ff02 100644 --- a/entity-framework/core/modeling/inheritance.md +++ b/entity-framework/core/modeling/inheritance.md @@ -102,9 +102,6 @@ If you are employing bulk configuration you can retrieve the column name for a s ## Table-per-concrete-type configuration -> [!NOTE] -> The table-per-concrete-type (TPC) feature was introduced in EF Core 7.0. - In the TPC mapping pattern, all the types are mapped to individual tables. Each table contains columns for all properties on the corresponding entity type. This addresses some common performance issues with the TPT strategy. > [!TIP] diff --git a/entity-framework/core/modeling/keys.md b/entity-framework/core/modeling/keys.md index 2589255fba..7094a44fed 100644 --- a/entity-framework/core/modeling/keys.md +++ b/entity-framework/core/modeling/keys.md @@ -34,9 +34,6 @@ You can also configure multiple properties to be the key of an entity - this is ### [Data Annotations](#tab/data-annotations) -> [!NOTE] -> The `[PrimaryKey]` attribute was introduced in EF Core 7.0. Use the Fluent API in older versions. - -#### [.NET Core CLI](#tab/dotnet-core-cli) +#### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef database update @@ -140,10 +140,10 @@ Sometimes you may want to reference types from another DbContext. This can lead ### Next steps -The above was only a brief introduction to migrations. Please consult the other documentation pages to learn more about [managing migrations](xref:core/managing-schemas/migrations/managing), [applying them](xref:core/managing-schemas/migrations/applying), and other aspects. The [.NET Core CLI tool reference](xref:core/cli/index) also contains useful information on the different commands +The above was only a brief introduction to migrations. Please consult the other documentation pages to learn more about [managing migrations](xref:core/managing-schemas/migrations/managing), [applying them](xref:core/managing-schemas/migrations/applying), and other aspects. The [.NET CLI tool reference](xref:core/cli/index) also contains useful information on the different commands ## Additional resources -* [Entity Framework Core tools reference - .NET Core CLI](xref:core/cli/dotnet) : Includes commands to update, drop, add, remove, and more. +* [Entity Framework Core tools reference - .NET CLI](xref:core/cli/dotnet) : Includes commands to update, drop, add, remove, and more. * [Entity Framework Core tools reference - Package Manager Console in Visual Studio](xref:core/cli/powershell) : Includes commands to update, drop, add, remove, and more. * [.NET Data Community Standup session](https://www.youtube.com/watch?v=mSsGERmrhnE&list=PLdo4fOcmZ0oX-DBuRG4u58ZTAJgBAeQ-t&index=20) going over new migration features in EF Core 5.0. diff --git a/entity-framework/core/managing-schemas/migrations/managing.md b/entity-framework/core/managing-schemas/migrations/managing.md index 0d576e97a9..23d3da2a5f 100644 --- a/entity-framework/core/managing-schemas/migrations/managing.md +++ b/entity-framework/core/managing-schemas/migrations/managing.md @@ -10,13 +10,13 @@ uid: core/managing-schemas/migrations/managing As your model changes, migrations are added and removed as part of normal development, and the migration files are checked into your project's source control. To manage migrations, you must first install the [EF Core command-line tools](xref:core/cli/index). > [!TIP] -> If the `DbContext` is in a different assembly than the startup project, you can explicitly specify the target and startup projects in either the [Package Manager Console tools](xref:core/cli/powershell#target-and-startup-project) or the [.NET Core CLI tools](xref:core/cli/dotnet#target-project-and-startup-project). +> If the `DbContext` is in a different assembly than the startup project, you can explicitly specify the target and startup projects in either the [Package Manager Console tools](xref:core/cli/powershell#target-and-startup-project) or the [.NET CLI tools](xref:core/cli/dotnet#target-project-and-startup-project). ## Add a migration After your model has been changed, you can add a migration for that change: -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef migrations add AddBlogCreatedTimestamp @@ -44,7 +44,7 @@ The timestamp in the filename helps keep them ordered chronologically so you can You are free to move Migrations files and change their namespace manually. New migrations are created as siblings of the last migration. Alternatively, you can specify the directory at generation time as follows: -#### [.NET Core CLI](#tab/dotnet-core-cli) +#### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef migrations add InitialCreate --output-dir Your/Directory @@ -170,7 +170,7 @@ In most cases, EF Core will automatically wrap each migration in its own transac Sometimes you add a migration and realize you need to make additional changes to your EF Core model before applying it. To remove the last migration, use this command. -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef migrations remove @@ -193,7 +193,7 @@ After removing the migration, you can make the additional model changes and add You can list all existing migrations as follows: -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef migrations list @@ -242,5 +242,5 @@ VALUES (N'', N''); ## Additional resources -* [Entity Framework Core tools reference - .NET Core CLI](xref:core/cli/dotnet) : Includes commands to update, drop, add, remove, and more. +* [Entity Framework Core tools reference - .NET CLI](xref:core/cli/dotnet) : Includes commands to update, drop, add, remove, and more. * [Entity Framework Core tools reference - Package Manager Console in Visual Studio](xref:core/cli/powershell) : Includes commands to update, drop, add, remove, and more. diff --git a/entity-framework/core/managing-schemas/migrations/projects.md b/entity-framework/core/managing-schemas/migrations/projects.md index 2f8fcc7b83..4ea010ee6d 100644 --- a/entity-framework/core/managing-schemas/migrations/projects.md +++ b/entity-framework/core/managing-schemas/migrations/projects.md @@ -46,7 +46,7 @@ You may want to store your migrations in a different project than the one contai If you did everything correctly, you should be able to add new migrations to the project. -## [.NET Core CLI](#tab/dotnet-core-cli) +## [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef migrations add NewMigration --project WebApplication1.Migrations diff --git a/entity-framework/core/managing-schemas/migrations/providers.md b/entity-framework/core/managing-schemas/migrations/providers.md index c3640088ca..df3af9cf2c 100644 --- a/entity-framework/core/managing-schemas/migrations/providers.md +++ b/entity-framework/core/managing-schemas/migrations/providers.md @@ -23,7 +23,7 @@ class SqliteBlogContext : BlogContext Specify the context type when adding new migrations. -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef migrations add InitialCreate --context BlogContext --output-dir Migrations/SqlServerMigrations @@ -58,7 +58,7 @@ Here's one pattern that works well when using a [Generic Host](/dotnet/core/exte Since the default host builder reads configuration from command-line arguments, you can specify the provider when running the tools. -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef migrations add MyMigration --project ../SqlServerMigrations -- --provider SqlServer diff --git a/entity-framework/core/managing-schemas/scaffolding/index.md b/entity-framework/core/managing-schemas/scaffolding/index.md index 04ef575ecb..56f11947b5 100644 --- a/entity-framework/core/managing-schemas/scaffolding/index.md +++ b/entity-framework/core/managing-schemas/scaffolding/index.md @@ -201,7 +201,7 @@ public partial class post ### Use mapping attributes (aka Data Annotations) -Entity types are configured using the [`ModelBuilder` API in `OnModelCreating`](xref:core/modeling/index#use-fluent-api-to-configure-a-model) by default. Specify `-DataAnnotations` (PMC) or `--data-annotations` (.NET Core CLI) to instead use [mapping attributes](xref:core/modeling/index#use-data-annotations-to-configure-a-model) when possible. +Entity types are configured using the [`ModelBuilder` API in `OnModelCreating`](xref:core/modeling/index#use-fluent-api-to-configure-a-model) by default. Specify `-DataAnnotations` (PMC) or `--data-annotations` (.NET CLI) to instead use [mapping attributes](xref:core/modeling/index#use-data-annotations-to-configure-a-model) when possible. For example, using the Fluent API will scaffold this: @@ -224,7 +224,7 @@ public string Title { get; set; } ### DbContext name -The scaffolded `DbContext` class name will be the name of the database suffixed with _Context_ by default. To specify a different one, use `-Context` in PMC and `--context` in the .NET Core CLI. +The scaffolded `DbContext` class name will be the name of the database suffixed with _Context_ by default. To specify a different one, use `-Context` in PMC and `--context` in the .NET CLI. ### Target directories and namespaces diff --git a/entity-framework/core/managing-schemas/scaffolding/templates.md b/entity-framework/core/managing-schemas/scaffolding/templates.md index 227c4197ef..c7499a0e00 100644 --- a/entity-framework/core/managing-schemas/scaffolding/templates.md +++ b/entity-framework/core/managing-schemas/scaffolding/templates.md @@ -120,7 +120,7 @@ var usings = new List Test the changes by using the reverse engineering commands. The templates inside your project are used automatically by the commands. -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer diff --git a/entity-framework/core/miscellaneous/connection-strings.md b/entity-framework/core/miscellaneous/connection-strings.md index 37f6ffa289..8340bc4df1 100644 --- a/entity-framework/core/miscellaneous/connection-strings.md +++ b/entity-framework/core/miscellaneous/connection-strings.md @@ -37,7 +37,7 @@ dotnet user-secrets set ConnectionStrings:YourDatabaseAlias "Data Source=(locald Then, in scaffolding, use a connection string that consists of `Name=`. -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet ef dbcontext scaffold Name=ConnectionStrings:YourDatabaseAlias Microsoft.EntityFrameworkCore.SqlServer diff --git a/entity-framework/core/miscellaneous/platforms.md b/entity-framework/core/miscellaneous/platforms.md index 19bfafdcb0..43a590cc1f 100644 --- a/entity-framework/core/miscellaneous/platforms.md +++ b/entity-framework/core/miscellaneous/platforms.md @@ -13,7 +13,7 @@ We want EF Core to be available to developers on all modern .NET implementations Several older .NET implementations are no longer supported. See the sections below for more guidance. | EF Core | .NET & .NET Core | .NET Standard | .NET Framework | -|-------------------|------------------|---------------|----------------| +|------------------ | ---------------- | ------------- | -------------- | | **9.0** | 8.0 | | | | **8.0** | 8.0 | | | | ~~**7.0**~~ (EOL) | 6.0 | | | diff --git a/entity-framework/core/providers/cosmos/index.md b/entity-framework/core/providers/cosmos/index.md index 8c8edd4640..fd560934af 100644 --- a/entity-framework/core/providers/cosmos/index.md +++ b/entity-framework/core/providers/cosmos/index.md @@ -21,7 +21,7 @@ It is strongly recommended to familiarize yourself with the [Azure Cosmos DB doc Install the [Microsoft.EntityFrameworkCore.Cosmos NuGet package](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Cosmos/). -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet add package Microsoft.EntityFrameworkCore.Cosmos diff --git a/entity-framework/core/providers/in-memory/index.md b/entity-framework/core/providers/in-memory/index.md index b2dcd67d32..645798c692 100644 --- a/entity-framework/core/providers/in-memory/index.md +++ b/entity-framework/core/providers/in-memory/index.md @@ -19,7 +19,7 @@ This database provider allows Entity Framework Core to be used with an in-memory Install the [Microsoft.EntityFrameworkCore.InMemory NuGet package](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.InMemory/). -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet add package Microsoft.EntityFrameworkCore.InMemory diff --git a/entity-framework/core/providers/index.md b/entity-framework/core/providers/index.md index bdbf2735ad..ab4f846b38 100644 --- a/entity-framework/core/providers/index.md +++ b/entity-framework/core/providers/index.md @@ -67,7 +67,7 @@ Entity Framework Core can access many different databases through plug-in librar Most database providers for EF Core are distributed as NuGet packages, and can be installed as follows: -## [.NET Core CLI](#tab/dotnet-core-cli) +## [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet add package provider_package_name diff --git a/entity-framework/core/providers/sql-server/hierarchyid.md b/entity-framework/core/providers/sql-server/hierarchyid.md index 8e30175303..a306e2d003 100644 --- a/entity-framework/core/providers/sql-server/hierarchyid.md +++ b/entity-framework/core/providers/sql-server/hierarchyid.md @@ -31,7 +31,7 @@ At the next level, a new [Microsoft.EntityFrameworkCore.SqlServer.Abstractions]( Use of `HierarchyId` for EF Core functionality such as queries and updates requires the [Microsoft.EntityFrameworkCore.SqlServer.HierarchyId](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer.HierarchyId) package. This package brings in `Microsoft.EntityFrameworkCore.SqlServer.Abstractions` and `Microsoft.SqlServer.Types` as transitive dependencies, and so is often the only package needed. -### [.NET Core CLI](#tab/netcore-cli) +### [.NET CLI](#tab/netcore-cli) ```dotnetcli dotnet add package Microsoft.EntityFrameworkCore.SqlServer.HierarchyId diff --git a/entity-framework/core/providers/sql-server/index.md b/entity-framework/core/providers/sql-server/index.md index 8e7f08d04d..b73f82281d 100644 --- a/entity-framework/core/providers/sql-server/index.md +++ b/entity-framework/core/providers/sql-server/index.md @@ -13,7 +13,7 @@ This database provider allows Entity Framework Core to be used with Microsoft SQ Install the [Microsoft.EntityFrameworkCore.SqlServer NuGet package](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer/). -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet add package Microsoft.EntityFrameworkCore.SqlServer diff --git a/entity-framework/core/providers/sqlite/index.md b/entity-framework/core/providers/sqlite/index.md index 0d30b325b3..756a6e4a0e 100644 --- a/entity-framework/core/providers/sqlite/index.md +++ b/entity-framework/core/providers/sqlite/index.md @@ -13,7 +13,7 @@ This database provider allows Entity Framework Core to be used with SQLite. The Install the [Microsoft.EntityFrameworkCore.Sqlite NuGet package](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite/). -### [.NET Core CLI](#tab/dotnet-core-cli) +### [.NET CLI](#tab/dotnet-core-cli) ```dotnetcli dotnet add package Microsoft.EntityFrameworkCore.Sqlite diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 36486d1499..a42ef09869 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -152,7 +152,7 @@ See [#12793](https://github.com/dotnet/efcore/issues/12793) and [#35367](https:/ - Optimize use of `Count` operation on `ICollection` ([#35381](https://github.com/dotnet/efcore/pull/35381), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). - Optimize `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)). - Translate date/time functions using `DatePart.Microsecond` and `DatePart.Nanosecond` arguments ([#34861](https://github.com/dotnet/efcore/pull/34861)). -- Simplify parameter names (e.g. from `@__city_0` to `city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)). +- Simplify parameter names (e.g. from `@__city_0` to `@city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)). - Translate `COALESCE` as `ISNULL` on SQL Server, for most cases ([#34171](https://github.com/dotnet/efcore/pull/34171), contributed by [@ranma42](https://github.com/ranma42)). - Support some string functions taking `char` as arguments ([#34999](https://github.com/dotnet/efcore/pull/34999), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). - Support `MAX`/`MIN`/`ORDER BY` using `decimal` on SQLite ([#35606](https://github.com/dotnet/efcore/pull/35606), contributed by [@ranma42](https://github.com/ranma42)). diff --git a/entity-framework/core/what-is-new/ef-core-3.x/index.md b/entity-framework/core/what-is-new/ef-core-3.x/index.md index ea7d0e2086..0adda59be7 100644 --- a/entity-framework/core/what-is-new/ef-core-3.x/index.md +++ b/entity-framework/core/what-is-new/ef-core-3.x/index.md @@ -188,7 +188,7 @@ public class OrderDetails This isn't really an EF Core 3.x feature, but we think it is important to many of our current customers. -We understand that many existing applications use previous versions of EF, and that porting them to EF Core only to take advantage of .NET Core can require a significant effort. +We understand that many existing applications use previous versions of EF, and that porting them to EF Core only to take advantage of .NET can require a significant effort. For that reason, we decided to port the newest version of EF 6 to run on .NET Core 3.x. For more details, see [what's new in EF 6](xref:ef6/what-is-new/index). diff --git a/entity-framework/core/what-is-new/ef-core-6.0/plan.md b/entity-framework/core/what-is-new/ef-core-6.0/plan.md index ff759c7ae5..4e792f5e57 100644 --- a/entity-framework/core/what-is-new/ef-core-6.0/plan.md +++ b/entity-framework/core/what-is-new/ef-core-6.0/plan.md @@ -312,7 +312,7 @@ Status: In-progress T-shirt size: Ongoing -[Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/) is a fully-featured ADO.NET database provider for SQL Server. It supports a broad range of SQL Server features on both .NET Core and .NET Framework. However, it is also a large and old codebase with many complex interactions between its behaviors. This makes it difficult to investigate the potential gains the could be made using newer .NET Core features. Therefore, we are starting an experiment in collaboration with the community to determine what potential there is for a highly performing SQL Server driver for .NET. +[Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/) is a fully-featured ADO.NET database provider for SQL Server. It supports a broad range of SQL Server features on both .NET and .NET Framework. However, it is also a large and old codebase with many complex interactions between its behaviors. This makes it difficult to investigate the potential gains the could be made using newer .NET features. Therefore, we are starting an experiment in collaboration with the community to determine what potential there is for a highly performing SQL Server driver for .NET. > [!IMPORTANT] > Investment in Microsoft.Data.SqlClient is not changing. It will continue to be the recommended way to connect to SQL Server and SQL Azure, both with and without EF Core. It will continue to support new SQL Server features as they are introduced. diff --git a/entity-framework/core/what-is-new/ef-core-7.0/plan.md b/entity-framework/core/what-is-new/ef-core-7.0/plan.md index a08da6463f..c884ce1487 100644 --- a/entity-framework/core/what-is-new/ef-core-7.0/plan.md +++ b/entity-framework/core/what-is-new/ef-core-7.0/plan.md @@ -168,7 +168,7 @@ Tracked in the [.NET Data Lab repo](https://github.com/dotnet/datalab/) Value proposition: Fast, fully managed access to SQL Server and Azure SQL for modern .NET applications. -[Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/) is a fully-featured ADO.NET database provider for SQL Server. It supports a broad range of SQL Server features on both .NET Core and .NET Framework. However, it is also a large and old codebase with many complex interactions between its behaviors. This makes it difficult to investigate the potential gains that could be made using newer .NET Core features. +[Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient/) is a fully-featured ADO.NET database provider for SQL Server. It supports a broad range of SQL Server features on both .NET and .NET Framework. However, it is also a large and old codebase with many complex interactions between its behaviors. This makes it difficult to investigate the potential gains that could be made using newer .NET features. We began a project last year, colloquially known as "Woodstar", to investigate the potential for a highly performing SQL Server driver for .NET. We plan to make significant further investment into this project in the EF7 timeframe. diff --git a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md index ddde4a3f15..1d5795b1a5 100644 --- a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md @@ -1306,7 +1306,7 @@ The database is then able to run queries against this data using its hierarchica ### Support in .NET and EF Core -Official support for the SQL Server `hierarchyid` type has only recently come to modern .NET platforms (i.e. ".NET Core"). This support is in the form of the [Microsoft.SqlServer.Types](https://www.nuget.org/packages/Microsoft.SqlServer.Types) NuGet package, which brings in low-level SQL Server-specific types. In this case, the low-level type is called `SqlHierarchyId`. +Official support for the SQL Server `hierarchyid` type has only recently come to modern .NET platforms. This support is in the form of the [Microsoft.SqlServer.Types](https://www.nuget.org/packages/Microsoft.SqlServer.Types) NuGet package, which brings in low-level SQL Server-specific types. In this case, the low-level type is called `SqlHierarchyId`. At the next level, a new [Microsoft.EntityFrameworkCore.SqlServer.Abstractions](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer.Abstractions) package has been introduced, which includes a higher-level `HierarchyId` type intended for use in entity types. diff --git a/entity-framework/core/what-is-new/index.md b/entity-framework/core/what-is-new/index.md index 79d21de8f0..a3aedef25d 100644 --- a/entity-framework/core/what-is-new/index.md +++ b/entity-framework/core/what-is-new/index.md @@ -39,7 +39,7 @@ Entity Framework Core releases and support are aligned with .NET releases and su ## Release planning and schedules -EF Core releases align with the [.NET Core shipping schedule](https://github.com/dotnet/core/blob/main/roadmap.md). +EF Core releases align with the [.NET shipping schedule](https://github.com/dotnet/core/blob/main/roadmap.md). Patch releases usually ship monthly, but have a long lead time. diff --git a/entity-framework/ef6/fundamentals/databinding/wpf.md b/entity-framework/ef6/fundamentals/databinding/wpf.md index 00f7adfee3..755c2025e2 100644 --- a/entity-framework/ef6/fundamentals/databinding/wpf.md +++ b/entity-framework/ef6/fundamentals/databinding/wpf.md @@ -10,7 +10,7 @@ uid: ef6/fundamentals/databinding/wpf > [!IMPORTANT] > **This document is valid for WPF on the .NET Framework only** > -> This document describes databinding for WPF on the .NET Framework. For new .NET Core projects, we recommend you use [EF Core](xref:core/index) instead of Entity Framework 6. The documentation for databinding in EF Core is here: [Getting Started with WPF](xref:core/get-started/wpf). +> This document describes databinding for WPF on the .NET Framework. For new .NET projects, we recommend you use [EF Core](xref:core/index) instead of Entity Framework 6. The documentation for databinding in EF Core is here: [Getting Started with WPF](xref:core/get-started/wpf). This step-by-step walkthrough shows how to bind POCO types to WPF controls in a “master-detail" form. The application uses the Entity Framework APIs to populate objects with data from the database, track changes, and persist data to the database. diff --git a/entity-framework/ef6/what-is-new/index.md b/entity-framework/ef6/what-is-new/index.md index 7c089f652f..2f8ce7a64c 100644 --- a/entity-framework/ef6/what-is-new/index.md +++ b/entity-framework/ef6/what-is-new/index.md @@ -37,7 +37,7 @@ The EF 6.3.0 runtime was released to NuGet in September 2019. The main goal of t ### EF designer support -There's currently no support for using the EF designer directly on .NET Core or .NET Standard projects or on an SDK-style .NET Framework project. +There's currently no support for using the EF designer directly on .NET or .NET Standard projects or on an SDK-style .NET Framework project. You can work around this limitation by adding the EDMX file and the generated classes for the entities and the DbContext as linked files to a .NET Core 3.0 or .NET Standard 2.1 project in the same solution. @@ -52,7 +52,7 @@ The linked files will look like this in the project file: ``` -Note that the EDMX file is linked with the EntityDeploy build action. This is a special MSBuild task (now included in the EF 6.3 package) that takes care of adding the EF model into the target assembly as embedded resources (or copying it as files in the output folder, depending on the Metadata Artifact Processing setting in the EDMX). For more details on how to get this set up, see our [EDMX .NET Core sample](https://aka.ms/EdmxDotNetCoreSample). +Note that the EDMX file is linked with the EntityDeploy build action. This is a special MSBuild task (now included in the EF 6.3 package) that takes care of adding the EF model into the target assembly as embedded resources (or copying it as files in the output folder, depending on the Metadata Artifact Processing setting in the EDMX). For more details on how to get this set up, see our [EDMX .NET sample](https://aka.ms/EdmxDotNetCoreSample). Warning: make sure the old style (i.e. non-SDK-style) .NET Framework project defining the "real" .edmx file comes _before_ the project defining the link inside the .sln file. Otherwise, when you open the .edmx file in the designer, you see the error message "The Entity Framework is not available in the target framework currently specified for the project. You can change the target framework of the project or edit the model in the XmlEditor". From b707e72c325dff1802d46d5164cd620c381eb323 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 25 Jul 2025 22:06:20 +0200 Subject: [PATCH 174/224] Remove note on sync method usage in change tracking section (#5060) The code shown is now async --- entity-framework/core/change-tracking/explicit-tracking.md | 3 --- entity-framework/core/change-tracking/index.md | 3 --- 2 files changed, 6 deletions(-) diff --git a/entity-framework/core/change-tracking/explicit-tracking.md b/entity-framework/core/change-tracking/explicit-tracking.md index 223eaa3e7c..372b3be840 100644 --- a/entity-framework/core/change-tracking/explicit-tracking.md +++ b/entity-framework/core/change-tracking/explicit-tracking.md @@ -18,9 +18,6 @@ Entity Framework Core (EF Core) change tracking works best when the same [!TIP] > You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/ChangeTrackingInEFCore). -> [!TIP] -> For simplicity, this document uses and references synchronous methods such as rather than their async equivalents such as . Calling and awaiting the async method can be substituted unless otherwise noted. - ## Introduction Entities can be explicitly "attached" to a such that the context then tracks those entities. This is primarily useful when: diff --git a/entity-framework/core/change-tracking/index.md b/entity-framework/core/change-tracking/index.md index d804cd3048..8393957ca8 100644 --- a/entity-framework/core/change-tracking/index.md +++ b/entity-framework/core/change-tracking/index.md @@ -15,9 +15,6 @@ This document presents an overview of Entity Framework Core (EF Core) change tra > [!TIP] > You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/ChangeTrackingInEFCore). -> [!TIP] -> For simplicity, this document uses and references synchronous methods such as rather than their async equivalents such as . Calling and awaiting the async method can be substituted unless otherwise noted. - ## How to track entities Entity instances become tracked when they are: From 11449dcb67f098f3a07a894116c52361cbbed820 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 25 Jul 2025 22:08:32 +0200 Subject: [PATCH 175/224] Improvements and tweaks to the SQL Server docs (#5064) --- .openpublishing.redirection.json | 7 +- .../sql-server/azure-sql-database.md | 32 ------ .../core/providers/sql-server/index.md | 103 +++++++++++++++--- .../core/providers/sql-server/misc.md | 26 +++++ entity-framework/toc.yml | 10 +- 5 files changed, 125 insertions(+), 53 deletions(-) delete mode 100644 entity-framework/core/providers/sql-server/azure-sql-database.md diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 333cacf1be..175082dbbf 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -489,6 +489,11 @@ "source_path": "entity-framework/core/providers/cosmos/functions.md", "redirect_url": "/ef/core/providers/cosmos/querying", "redirect_document_id": false - } + }, + { + "source_path": "entity-framework/core/providers/sql-server/azure-sql-database.md", + "redirect_url": "/ef/core/providers/sql-server/misc", + "redirect_document_id": false + } ] } diff --git a/entity-framework/core/providers/sql-server/azure-sql-database.md b/entity-framework/core/providers/sql-server/azure-sql-database.md deleted file mode 100644 index aeb9548403..0000000000 --- a/entity-framework/core/providers/sql-server/azure-sql-database.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: Microsoft SQL Server Database Provider - Azure SQL Database Options - EF Core -description: How to specify the service tier and performance level for Azure SQL Database with the SQL Server Entity Framework Core Database Provider -author: AndriySvyryd -ms.date: 11/05/2019 -uid: core/providers/sql-server/azure-sql-database ---- -# Specifying Azure SQL Database Options - -> [!NOTE] -> You should [use `UseAzureSql` method](xref:core/providers/sql-server/index#usage) instead of `UseSqlServer` when connecting to Azure SQL. - -Azure SQL Database provides [a variety of pricing options](https://azure.microsoft.com/pricing/details/sql-database/single/) that are usually configured through the Azure Portal. However if you are managing the schema using [EF Core migrations](xref:core/managing-schemas/migrations/index) you can specify the desired options in the model itself. - -You can specify the service tier of the database (EDITION) using [HasServiceTier](/dotnet/api/Microsoft.EntityFrameworkCore.SqlServerModelBuilderExtensions.HasServiceTier): - -[!code-csharp[HasServiceTier](../../../../samples/core/SqlServer/AzureDatabase/AzureSqlContext.cs?name=HasServiceTier)] - -You can specify the maximum size of the database using [HasDatabaseMaxSize](/dotnet/api/Microsoft.EntityFrameworkCore.SqlServerModelBuilderExtensions.HasDatabaseMaxSize): - -[!code-csharp[HasDatabaseMaxSize](../../../../samples/core/SqlServer/AzureDatabase/AzureSqlContext.cs?name=HasDatabaseMaxSize)] - -You can specify the performance level of the database (SERVICE_OBJECTIVE) using [HasPerformanceLevel](/dotnet/api/Microsoft.EntityFrameworkCore.SqlServerModelBuilderExtensions.HasPerformanceLevel): - -[!code-csharp[HasPerformanceLevel](../../../../samples/core/SqlServer/AzureDatabase/AzureSqlContext.cs?name=HasPerformanceLevel)] - -Use [HasPerformanceLevelSql](/dotnet/api/Microsoft.EntityFrameworkCore.SqlServerModelBuilderExtensions.HasPerformanceLevelSql) to configure the elastic pool, since the value is not a string literal: - -[!code-csharp[HasPerformanceLevel](../../../../samples/core/SqlServer/AzureDatabase/AzureSqlContext.cs?name=HasPerformanceLevelSql)] - -> [!TIP] -> You can find all the supported values in the [ALTER DATABASE documentation](/sql/t-sql/statements/alter-database-transact-sql?view=azuresqldb-current&preserve-view=true). diff --git a/entity-framework/core/providers/sql-server/index.md b/entity-framework/core/providers/sql-server/index.md index b73f82281d..81121d9544 100644 --- a/entity-framework/core/providers/sql-server/index.md +++ b/entity-framework/core/providers/sql-server/index.md @@ -27,28 +27,103 @@ Install-Package Microsoft.EntityFrameworkCore.SqlServer *** -> [!NOTE] -> The provider references Microsoft.Data.SqlClient (not System.Data.SqlClient). If your project takes a direct dependency on SqlClient, make sure it references the Microsoft.Data.SqlClient package. +## Usage and configuration + +Once your project references the nuget package, configure EF for SQL Server as follows: + +### [SQL Server (on-premises)](#tab/sqlserver) + +```c# +public class MyContext : DbContext +{ + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseSqlServer(""); + } +} +``` + +When using EF with dependency injection (e.g. ASP.NET), use the following: + +```c# +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddDbContext(options => + options.UseSqlServer(builder.Configuration.GetConnectionString("MyContext"))); +``` -> [!TIP] -> The Microsoft.Data.SqlClient package ships more frequently than the EF Core provider. If you would like to take advantage of new features and bug fixes, you can add a direct package reference to the latest version of Microsoft.Data.SqlClient. +### [Azure SQL](#tab/azure-sql) -> [!WARNING] -> The async implementation of [Microsoft.Data.SqlClient](https://github.com/dotnet/SqlClient) unfortunately has some known issues (e.g. [#593](https://github.com/dotnet/SqlClient/issues/593), [#601](https://github.com/dotnet/SqlClient/issues/601), and others). If you're seeing unexpected performance problems, try using sync command execution instead, especially when dealing with large text or binary values. +```c# +public class MyContext : DbContext +{ + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseAzureSql(""); + } +} +``` -## Usage +When using EF with dependency injection (e.g. ASP.NET), use the following: -Starting with EF 9, it's recommended to use `UseAzureSql` and `UseAzureSynapse` to specify that you're connecting to Azure SQL or Azure Synapse Analytics specifically, and `UseSqlServer` to specify that you're connecting to on-premises SQL Server; doing so allows the provider to optimize for and properly support these platforms. It's also recommended to use `UseCompatibilityLevel` method to specify the compatibility level so that the generated SQL is compatible and/or uses the latest possible features. +```c# +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddDbContext(options => + options.UseSqlServer(builder.Configuration.GetConnectionString("MyContext"))); +``` > [!NOTE] -> UseAzureSql and UseAzureSynapse methods were introduced in EF Core 9.0. +> was introduced in EF Core 9.0. When using an older version, use instead. + +### [Azure Synapse Analytics](#tab/azure-synapse) + +```c# +public class MyContext : DbContext +{ + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseAzureSynapse(""); + } +} +``` + +When using EF with dependency injection (e.g. ASP.NET), use the following: + +```c# +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddDbContext(options => + options.UseSqlServer(builder.Configuration.GetConnectionString("MyContext"))); +``` + +> [!NOTE] +> was introduced in EF Core 9.0. When using an older version, use instead. + +*** + +## Compatibility level + +You can optionally configure EF with the compatibility level of your database; higher compatibility levels allow for newer features, and configuring EF accordingly makes it use those features. If you do not explicitly configure a compatibility level, a reasonable default will be chosen that may not take advantage of the newest features. As a result, it's recommended to explicitly configure the compatibility level you'd like to have. + +Note that this only covers EF's own configuration of the compatibility level - affecting e.g. the SQL it generates - but does not affect the compatibility level configured in your actual database. Databases hosted on newer versions of SQL Server may still be configured with lower compatibility levels, causing them to not support the latest features - so you may need to change the compatibility level in your database as well. For more information on compatibility levels, [see the documentation](/sql/relational-databases/databases/view-or-change-the-compatibility-level-of-a-database). + +To configure EF with a compatibility level, use `UseCompatibilityLevel()` as follows: + +```c# +optionsBuilder.UseSqlServer("", o => o.UseCompatibilityLevel()); +``` + +## Connection resiliency + +EF includes functionality for automatically retrying failed database commands; for more information, [see the documentation](xref:core/miscellaneous/connection-resiliency). When using and , connection resiliency is automatically set up with the appropriate settings specific for those databases. Otherwise, when using , configure the provider with as shown in the connection resiliency documentation. + +In some cases, may be called in code that you cannot control. Starting with EF 9, to enable connection resiliency in such scenarios, call `ConfigureSqlEngine(c => c.EnableRetryOnFailureByDefault())` beforehand (this is not necessary with and ). -### EnableRetryOnFailureByDefault +## Notes and caveats -EF 9 introduced `EnableRetryOnFailureByDefault` method that configures the context to default [execution strategy](xref:core/miscellaneous/connection-resiliency) unless it is configured explicitly (i.e. when using DI). To use it, simply call `ConfigureSqlEngine(c => c.EnableRetryOnFailureByDefault())` and later you can use `UseSqlServer` as usual. It is not necessary to call `EnableRetryOnFailureByDefault` when using `UseAzureSql` or `UseAzureSynapse`, as they already enable the default execution strategy. +* The Microsoft.Data.SqlClient package ships more frequently than the EF Core provider. If you would like to take advantage of new features and bug fixes, you can add a direct package reference to the latest version of Microsoft.Data.SqlClient. +* The EF SQL Server provider uses Microsoft.Data.SqlClient, and not the older System.Data.Client; if your project takes a direct dependency on SqlClient, make sure it references the Microsoft.Data.SqlClient package. For more information on the differences between Microsoft.Data.SqlClient and System.Data.SqlClient, [see this blog post](https://devblogs.microsoft.com/dotnet/introducing-the-new-microsoftdatasqlclient). -## Supported Database Engines +## Supported database engines -* Microsoft SQL Server (2012 onwards) -* Azure SQL +* Microsoft SQL Server (2019 onwards) +* Azure SQL Database * Azure Synapse Analytics diff --git a/entity-framework/core/providers/sql-server/misc.md b/entity-framework/core/providers/sql-server/misc.md index dd4ce74700..2206fe39ef 100644 --- a/entity-framework/core/providers/sql-server/misc.md +++ b/entity-framework/core/providers/sql-server/misc.md @@ -7,6 +7,32 @@ uid: core/providers/sql-server/misc --- # Miscellaneous notes for SQL Server +## Azure SQL database options + +> [!NOTE] +> You should [use `UseAzureSql` method](xref:core/providers/sql-server/index#usage) instead of `UseSqlServer` when connecting to Azure SQL. + +Azure SQL Database provides [a variety of pricing options](https://azure.microsoft.com/pricing/details/sql-database/single/) that are usually configured through the Azure Portal. However, if you are managing the schema using [EF Core migrations](xref:core/managing-schemas/migrations/index), you can configure the desired options with EF, and they will get applied when EF creates the database. + +You can specify the service tier of the database (EDITION) using [HasServiceTier](/dotnet/api/Microsoft.EntityFrameworkCore.SqlServerModelBuilderExtensions.HasServiceTier): + +[!code-csharp[HasServiceTier](../../../../samples/core/SqlServer/AzureDatabase/AzureSqlContext.cs?name=HasServiceTier)] + +You can specify the maximum size of the database using [HasDatabaseMaxSize](/dotnet/api/Microsoft.EntityFrameworkCore.SqlServerModelBuilderExtensions.HasDatabaseMaxSize): + +[!code-csharp[HasDatabaseMaxSize](../../../../samples/core/SqlServer/AzureDatabase/AzureSqlContext.cs?name=HasDatabaseMaxSize)] + +You can specify the performance level of the database (SERVICE_OBJECTIVE) using [HasPerformanceLevel](/dotnet/api/Microsoft.EntityFrameworkCore.SqlServerModelBuilderExtensions.HasPerformanceLevel): + +[!code-csharp[HasPerformanceLevel](../../../../samples/core/SqlServer/AzureDatabase/AzureSqlContext.cs?name=HasPerformanceLevel)] + +Use [HasPerformanceLevelSql](/dotnet/api/Microsoft.EntityFrameworkCore.SqlServerModelBuilderExtensions.HasPerformanceLevelSql) to configure the elastic pool, since the value is not a string literal: + +[!code-csharp[HasPerformanceLevel](../../../../samples/core/SqlServer/AzureDatabase/AzureSqlContext.cs?name=HasPerformanceLevelSql)] + +> [!TIP] +> You can find all the supported values in the [ALTER DATABASE documentation](/sql/t-sql/statements/alter-database-transact-sql?view=azuresqldb-current&preserve-view=true). + ## SaveChanges, database triggers and unsupported computed columns Starting with EF Core 7.0, EF Core saves changes to the database with significantly optimized SQL; unfortunately, this technique is not supported on SQL Server if the target table has database triggers, or certain kinds of computed columns. For more information on this SQL Server limitation, see the documentation on the [OUTPUT clause](/sql/t-sql/queries/output-clause-transact-sql#remarks). diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index 7a33c4d7e1..cf5ff332ef 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -394,16 +394,16 @@ items: - name: Overview href: core/providers/sql-server/index.md - - name: Temporal tables - href: core/providers/sql-server/temporal-tables.md - - name: Value generation - href: core/providers/sql-server/value-generation.md - name: Function mappings href: core/providers/sql-server/functions.md - name: Columns href: core/providers/sql-server/columns.md - name: Indexes href: core/providers/sql-server/indexes.md + - name: Value generation + href: core/providers/sql-server/value-generation.md + - name: Temporal tables + href: core/providers/sql-server/temporal-tables.md - name: Memory-optimized tables href: core/providers/sql-server/memory-optimized-tables.md - name: Hierarchical data @@ -411,8 +411,6 @@ - name: Spatial data displayName: GIS href: core/providers/sql-server/spatial.md - - name: Specify Azure SQL Database options - href: core/providers/sql-server/azure-sql-database.md - name: Miscellaneous href: core/providers/sql-server/misc.md - name: SQLite From 1e6c840c09e7850f0b5b61f31049fc2b3dc2deaf Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Wed, 6 Aug 2025 11:40:38 +0200 Subject: [PATCH 176/224] Document Cosmos vector search/FTS being introduced in 10 (#5075) Fixes #5074 --- .../core/providers/cosmos/full-text-search.md | 9 ++++++--- entity-framework/core/providers/cosmos/vector-search.md | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/entity-framework/core/providers/cosmos/full-text-search.md b/entity-framework/core/providers/cosmos/full-text-search.md index 99f191689a..541a20888b 100644 --- a/entity-framework/core/providers/cosmos/full-text-search.md +++ b/entity-framework/core/providers/cosmos/full-text-search.md @@ -1,11 +1,14 @@ --- -title: Full Text Search - Azure Cosmos DB Provider - EF Core -description: Full text search with the Azure Cosmos DB EF Core Provider +title: Full-Text Search - Azure Cosmos DB Provider - EF Core +description: Full-text search with the Azure Cosmos DB EF Core Provider author: maumar ms.date: 04/19/2025 uid: core/providers/cosmos/full-text-search --- -# Full text search +# Full-text search + +> [!NOTE] +> Full-text search support for Cosmos was introduced in EF 10. Azure Cosmos DB now offers support for [full-text search](/azure/cosmos-db/gen-ai/full-text-search). It enables efficient and effective text searches using advanced techniques like stemming, as well as evaluating the relevance of documents to a given search query. It can be used in combination with vector search (i.e. hybrid search) to improve the accuracy of responses in some AI scenarios. EF Core allows for modeling the database with full-text search enabled properties and using full-text search functions inside queries targeting Azure Cosmos DB. diff --git a/entity-framework/core/providers/cosmos/vector-search.md b/entity-framework/core/providers/cosmos/vector-search.md index a12aa9d5f4..8fdc7924ef 100644 --- a/entity-framework/core/providers/cosmos/vector-search.md +++ b/entity-framework/core/providers/cosmos/vector-search.md @@ -7,6 +7,9 @@ uid: core/providers/cosmos/vector-search --- # Vector search +> [!NOTE] +> The below describes the vector search support in EF 10. EF 9 includes similar experimental support with slightly different method naming. + Azure Cosmos DB now offers support for vector similarity search. Vector search is a fundamental part of some application types, including AI, semantic search and others. Azure Cosmos DB allows you to store vectors directly in your documents alongside the rest of your data, meaning you can perform all of your queries against a single database. This can considerably simplify your architecture and remove the need for an additional, dedicated vector database solution in your stack. To learn more about Azure Cosmos DB vector search, [see the documentation](/azure/cosmos-db/nosql/vector-search). Vector property can be configured inside `OnModelCreating`: From b14e18d2fd79a8d4e8969fa7d226c80d1b294a88 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Sun, 17 Aug 2025 17:48:12 +0200 Subject: [PATCH 177/224] What's new docs for 10.0.0-preview.7 (#5070) (#5071) --- .../core/what-is-new/ef-core-10.0/whatsnew.md | 78 +++++++++++++++++-- entity-framework/toc.yml | 16 ++-- 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index a42ef09869..6d3d4dbb2c 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -115,7 +115,66 @@ In EF 10 we improved this experience - EF will now materialize a default value f ## LINQ and SQL translation - + + +### Improved translation for parameterized collection + +A notoriously difficult problem with relational databases is queries that involve *parameterized collections*: + +```c# +int[] ids = [1, 2, 3]; +var blogs = await context.Blogs.Where(b => ids.Contains(b.Id)).ToListAsync(); +``` + +In the above query, `ids` is a parameterized collection: the same query can be executed many times, with `ids` containing different values each time. + +Since relational databases don't typically support sending a collection directly as a parameter, EF version up to 8.0 simply inlined the collection contents into the SQL as constants: + +```sql +SELECT [b].[Id], [b].[Name] +FROM [Blogs] AS [b] +WHERE [b].[Id] IN (1, 2, 3) +``` + +While this works, it has the unfortunate consequence of generating different SQLs for different collections, causing database plan cache misses and bloat, and creating various performance problems (see [#13617](https://github.com/dotnet/efcore/issues/13617), which was the most highly-voted issue in the repo at the time). As a result, EF 8.0 leveraged the introduction of extensive JSON support and changed the translation of parameterized collections to use JSON arrays ([release notes](xref:core/what-is-new/ef-core-8.0/whatsnew#queries-with-primitive-collections +)): + +```sql +@__ids_0='[1,2,3]' + +SELECT [b].[Id], [b].[Name] +FROM [Blogs] AS [b] +WHERE [b].[Id] IN ( + SELECT [i].[value] + FROM OPENJSON(@__ids_0) WITH ([value] int '$') AS [i] +) +``` + +Here, the collection is encoded as a string containing a JSON array, sent as a single parameter and then unpacked using the SQL Server [`OPENJSON`](/sql/t-sql/functions/openjson-transact-sql) function (other databases use similar mechanisms). Since the collection is now parameterized, the SQL stays the same and a single query plan no matter what values the collection contains. Unfortunately, while elegant, this translation also deprives the database query planner of important information on the cardinality (or length) of the collection, and can cause a plan to be chosen that works well for a small - or large - number of elements. As a result, EF Core 9.0 introduced the ability to control which translation strategy to use ([release notes](xref:core/what-is-new/ef-core-9.0/whatsnew#parameterized-primitive-collections)). + +EF 10.0 introduces a new default translation mode for parameterized collections, where each value in the collection is translated into its own scalar parameter: + +```sql +SELECT [b].[Id], [b].[Name] +FROM [Blogs] AS [b] +WHERE [b].[Id] IN (@ids1, @ids2, @ids3) +``` + +This allows the collection values to change without resulting in different SQLs - solving the plan cache problem - but at the same time provides the query planner with information on the collection cardinality. Since different cardinalities still cause different SQLs to be generated, the final version of EF 10 will include a "bucketization" feature, where e.g. 10 parameters are sent even when the user only specifies 8, to reduce the SQL variations and optimize the query cache. + +Unfortunately, parameterized collections are a case where EF simply cannot always make the right choice: selecting between multiple parameters (the new default), a single JSON array parameter or multiple inlined constants can require knowledge about the data in your database, and different choices may work better for different queries. As a result, EF exposes full control to the user to control the translation strategy, both at the global configuration level: + +```c# +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder + .UseSqlServer("", o => o.UseParameterizedCollectionMode(ParameterTranslationMode.Constant)); +``` + +... and at the per-query level: + +```c# +var blogs = await context.Blogs.Where(b => EF.Constant(ids).Contains(b.Id)).ToListAsync(); +``` ### Support for the .NET 10 `LeftJoin` and `RightJoin` operators @@ -140,24 +199,33 @@ var query = context.Students > [!NOTE] > EF 10 also supports the analogous `RightJoin` operator, which keeps all the data from the second collection and only the matching data from the first collection. EF 10 translates this to `RIGHT JOIN` operation in the database. +Unfortunately, C# query syntax (`from x select x.Id`) doesn't yet support expressing left/right join operations in this way. + See [#12793](https://github.com/dotnet/efcore/issues/12793) and [#35367](https://github.com/dotnet/efcore/issues/35367) for more details. ### Other query improvements +#### New translations + - Translate [DateOnly.ToDateTime()](/dotnet/api/system.dateonly.todatetime) ([#35194](https://github.com/dotnet/efcore/pull/35194), contributed by [@mseada94](https://github.com/mseada94)). - Translate [DateOnly.DayNumber](/dotnet/api/system.dateonly.daynumber) and `DayNumber` subtraction for SQL Server and SQLite ([#36183](https://github.com/dotnet/efcore/issues/36183)). -- Optimize multiple consecutive `LIMIT`s ([#35384](https://github.com/dotnet/efcore/pull/35384), contributed by [@ranma42](https://github.com/ranma42)). -- Optimize use of `Count` operation on `ICollection` ([#35381](https://github.com/dotnet/efcore/pull/35381), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). -- Optimize `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)). - Translate date/time functions using `DatePart.Microsecond` and `DatePart.Nanosecond` arguments ([#34861](https://github.com/dotnet/efcore/pull/34861)). -- Simplify parameter names (e.g. from `@__city_0` to `@city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)). - Translate `COALESCE` as `ISNULL` on SQL Server, for most cases ([#34171](https://github.com/dotnet/efcore/pull/34171), contributed by [@ranma42](https://github.com/ranma42)). - Support some string functions taking `char` as arguments ([#34999](https://github.com/dotnet/efcore/pull/34999), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). - Support `MAX`/`MIN`/`ORDER BY` using `decimal` on SQLite ([#35606](https://github.com/dotnet/efcore/pull/35606), contributed by [@ranma42](https://github.com/ranma42)). - Support projecting different navigations (but same type) via conditional operator ([#34589](https://github.com/dotnet/efcore/issues/34589), contributed by [@ranma42](https://github.com/ranma42)). +#### Bug fixes and optimizations + +- Fix Microsoft.Data.Sqlite behavior around `DateTime`, `DateTimeOffset` and UTC, [see breaking change notes](xref:core/what-is-new/ef-core-10.0/breaking-changes#DateTimeOffset-read) ([#36195](https://github.com/dotnet/efcore/issues/36195)). +- Fix translation of `DefaultIfEmpty` in various scenarios ([#19095](https://github.com/dotnet/efcore/issues/19095), [#33343](https://github.com/dotnet/efcore/issues/33343), [#36208](https://github.com/dotnet/efcore/issues/36208)). +- Optimize multiple consecutive `LIMIT`s ([#35384](https://github.com/dotnet/efcore/pull/35384), contributed by [@ranma42](https://github.com/ranma42)). +- Optimize use of `Count` operation on `ICollection` ([#35381](https://github.com/dotnet/efcore/pull/35381), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). +- Optimize `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)). +- Simplify parameter names (e.g. from `@__city_0` to `@city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)). + ## ExecuteUpdateAsync now accepts a regular, non-expression lambda The can be used to express arbitrary update operations in the database. In previous versions, the changes to be performed on the database rows were provided via an expression tree parameter; this made it quite difficult to build those changes dynamically. For example, let's assume we want to update a Blog's Views, but conditionally also its Name. Since the setters argument was an expression tree, code such as the following needed to be written: diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index cf5ff332ef..6f11095fbb 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -75,38 +75,38 @@ href: core/what-is-new/ef-core-9.0/breaking-changes.md - name: EF Core 8.0 items: - - name: High-level plan - href: core/what-is-new/ef-core-8.0/plan.md - name: "What's new?" href: core/what-is-new/ef-core-8.0/whatsnew.md - name: Breaking changes href: core/what-is-new/ef-core-8.0/breaking-changes.md + - name: High-level plan + href: core/what-is-new/ef-core-8.0/plan.md - name: Out of support items: - name: EF Core 7.0 items: - - name: High-level plan - href: core/what-is-new/ef-core-7.0/plan.md - name: "What's new?" href: core/what-is-new/ef-core-7.0/whatsnew.md - name: Breaking changes href: core/what-is-new/ef-core-7.0/breaking-changes.md + - name: High-level plan + href: core/what-is-new/ef-core-7.0/plan.md - name: EF Core 6.0 items: - - name: High-level plan - href: core/what-is-new/ef-core-6.0/plan.md - name: "What's new?" href: core/what-is-new/ef-core-6.0/whatsnew.md - name: Breaking changes href: core/what-is-new/ef-core-6.0/breaking-changes.md + - name: High-level plan + href: core/what-is-new/ef-core-6.0/plan.md - name: EF Core 5.0 items: - - name: High-level plan - href: core/what-is-new/ef-core-5.0/plan.md - name: "What's new?" href: core/what-is-new/ef-core-5.0/whatsnew.md - name: Breaking changes href: core/what-is-new/ef-core-5.0/breaking-changes.md + - name: High-level plan + href: core/what-is-new/ef-core-5.0/plan.md - name: EF Core 3.1 items: - name: New features From faa6184d4fc1d2042134560a90f064f5df107ddc Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 18 Aug 2025 20:37:59 +0200 Subject: [PATCH 178/224] Fix grammar problem (#5078) Fixes #5077 --- entity-framework/core/miscellaneous/connection-resiliency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/miscellaneous/connection-resiliency.md b/entity-framework/core/miscellaneous/connection-resiliency.md index 31cf6420b3..79072409ed 100644 --- a/entity-framework/core/miscellaneous/connection-resiliency.md +++ b/entity-framework/core/miscellaneous/connection-resiliency.md @@ -49,7 +49,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) An execution strategy that automatically retries on failures needs to be able to play back each operation in a retry block that fails. When retries are enabled, each operation you perform via EF Core becomes its own retriable operation. That is, each query and each call to `SaveChangesAsync()` will be retried as a unit if a transient failure occurs. -However, if your code initiates a transaction using `BeginTransactionAsync()` you are defining your own group of operations that need to be treated as a unit, and everything inside the transaction would need to be played back shall a failure occur. You will receive an exception like the following if you attempt to do this when using an execution strategy: +However, if your code initiates a transaction using `BeginTransactionAsync()` you are defining your own group of operations that need to be treated as a unit, and everything inside the transaction would need to be played back if a failure occurs. You will receive an exception like the following if you attempt to do this when using an execution strategy: > InvalidOperationException: The configured execution strategy 'SqlServerRetryingExecutionStrategy' does not support user-initiated transactions. Use the execution strategy returned by 'DbContext.Database.CreateExecutionStrategy()' to execute all the operations in the transaction as a retriable unit. From 232a10fb45c10fb32dc5aa2b9226e71417d86217 Mon Sep 17 00:00:00 2001 From: Wade Pickett Date: Wed, 20 Aug 2025 22:19:16 -0700 Subject: [PATCH 179/224] Update docfx.json with ms.update-cycle meta data (#5087) --- entity-framework/docfx.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/entity-framework/docfx.json b/entity-framework/docfx.json index d8f2d19b14..510e3bf55a 100644 --- a/entity-framework/docfx.json +++ b/entity-framework/docfx.json @@ -95,7 +95,10 @@ "ef6/**/**.md": "https://github.com/dotnet/ef6/issues/new" }, "ms.technology": { - } + }, + "ms.update-cycle": { + "**/**.{md,yml}": "3650-days" + } }, "dest": "_site", "template": [ From d253400be14515c766e581cb4d9eea884ebd45c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Thu, 21 Aug 2025 23:25:21 +0200 Subject: [PATCH 180/224] Add standup (#5089) --- .../core/learn-more/community-standups.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/entity-framework/core/learn-more/community-standups.md b/entity-framework/core/learn-more/community-standups.md index dcb85065c6..eebf16e727 100644 --- a/entity-framework/core/learn-more/community-standups.md +++ b/entity-framework/core/learn-more/community-standups.md @@ -16,7 +16,8 @@ The .NET Data Community Standups are live-streamed monthly (roughly) on Wednesda | Date | Area | Title | |--------------|-----------------------|------------------------------------------------------------------------------------------| -| Jul 17, 2025 | Couchbase | [Couchbase has an EF Core provider](#Jul17_2025) | +| Aug 21, 2025 | ORMs | [Learning about jOOQ with Lukas Eder](#Aug21_2025) | +| Jul 17, 2025 | Couchbase | [Couchbase has an EF Core provider](#Jul17_2025) | | Jun 19, 2025 | Vector databases | [Microsoft.Extensions.VectorData - Access Vector databases in AI apps](#Jun19_2025) | | May 14, 2025 | Azure SQL | [Azure SQL vector search with Davide Mauri](#May14_2025) | | Apr 24, 2025 | EF Core | [Jiri and Shay talk about EF Core testing and Maurycy corrects them](#Apr24_2025) | @@ -106,6 +107,22 @@ The .NET Data Community Standups are live-streamed monthly (roughly) on Wednesda ## 2025 + + +### Aug 21: [Learning about jOOQ with Lukas Eder](https://www.youtube.com/live/EbFqlYPvAE4?si=O2ifWoBfxNSS5zL9) + +Join us for another community standup where we welcome Lukas Eder, author of jOOQ, to show us what it can do, and what inspiration we can get for EF from it. + +Featuring: + +- [Lukas Eder](https://blog.jooq.org/author/lukaseder/) (Special guest) +- [Jiri Cincura](https://www.tabsoverspaces.com/) (Host) +- [Shay Rojansky](https://www.roji.org/) (Host) + +Links: + +- [jOOQ](https://www.jooq.org/) + ### Jul 17: [Couchbase has an EF Core provider](https://www.youtube.com/live/0UDFJvMg5Wc?si=lnIptXlNblaplGOC) From 8978e59dbc12191da0bd222402227d0f159b8433 Mon Sep 17 00:00:00 2001 From: Wade Pickett Date: Fri, 22 Aug 2025 09:41:33 -0700 Subject: [PATCH 181/224] Update managed-identities-test-non-production.md (#5090) Replacing ms.author invalid value so it will stop popping up as a warning in reporting. Author is no longer at Microsoft and ms.author requires a valid entry. --- .../core/includes/managed-identities-test-non-production.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/includes/managed-identities-test-non-production.md b/entity-framework/core/includes/managed-identities-test-non-production.md index 1a7c06c5d3..dedfb45f35 100644 --- a/entity-framework/core/includes/managed-identities-test-non-production.md +++ b/entity-framework/core/includes/managed-identities-test-non-production.md @@ -1,7 +1,7 @@ --- description: A local database that doesn't require the user to be authenticated author: rick-anderson -ms.author: riande +ms.author: wpickett ms.date: 10/23/2024 ms.topic: include title: an include file From f2228893721bd465c0a017d22695f6c7cac8f961 Mon Sep 17 00:00:00 2001 From: Manuel Henke Date: Sat, 6 Sep 2025 00:22:19 +0200 Subject: [PATCH 182/224] Typo in ef-core-8.0 whats new (#5095) --- entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md index 1d5795b1a5..3a78d2a361 100644 --- a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md @@ -2357,7 +2357,7 @@ modelBuilder.Entity() With this configuration, EF will exclude sending the value to the database when it is set to `Level.Beginner`, and instead `Level.Intermediate` is assigned by the database. This isn't what was intended! -The problem would not have occurred if the the enum been defined with the "unknown" or "unspecified" value being the database default: +The problem would not have occurred if the enum been defined with the "unknown" or "unspecified" value being the database default: ```csharp public enum Level From e12eb440d754ad29c8ebac586b51e8a4431d75ee Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 18 Aug 2025 08:58:21 +0200 Subject: [PATCH 183/224] Document SQL Server vector search and JSON data type (#5082) Closes #5081 Closes #4818 --- .../core/providers/sql-server/columns.md | 25 +-- .../core/providers/sql-server/functions.md | 63 +++--- .../providers/sql-server/vector-search.md | 80 ++++++++ .../core/providers/sqlite/functions.md | 38 ++-- .../core/what-is-new/ef-core-10.0/whatsnew.md | 182 +++++++++++++----- entity-framework/toc.yml | 2 + 6 files changed, 273 insertions(+), 117 deletions(-) create mode 100644 entity-framework/core/providers/sql-server/vector-search.md diff --git a/entity-framework/core/providers/sql-server/columns.md b/entity-framework/core/providers/sql-server/columns.md index 728b382d7a..b04949855c 100644 --- a/entity-framework/core/providers/sql-server/columns.md +++ b/entity-framework/core/providers/sql-server/columns.md @@ -11,11 +11,7 @@ This page details column configuration options that are specific to the SQL Serv ## Unicode and UTF-8 -SQL Server 2019 introduced [introduced UTF-8](/sql/relational-databases/collations/collation-and-unicode-support#utf8) support, which allows storing UTF-8 data in `char` and `varchar` columns by configuring them with special UTF-8 collations. - -### [EF Core 7.0](#tab/ef-core-7) - -EF Core 7.0 includes first-class support for UTF-8 columns. To configure them, simply configure the column's type to `char` or `varchar`, specify a UTF-8 collation (ending with `_UTF8`), and specify that the column should be Unicode: +SQL Server 2019 introduced [introduced UTF-8](/sql/relational-databases/collations/collation-and-unicode-support#utf8) support, which allows storing UTF-8 data in `char` and `varchar` columns by configuring them with special UTF-8 collations. You can use UTF-8 columns with EF simply by configuring the column's type to `char` or `varchar`, specify a UTF-8 collation (ending with `_UTF8`), and specifying that the column should be Unicode: ```c# protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -28,25 +24,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } ``` -#### [Older versions](#tab/older-versions) - -In EF Core versions prior to 7.0, UTF-8 columns do not work out-of-the-box with EF Core's SQL Server provider. To map a string property to a `varchar(x)` column, the Fluent or Data Annotation API is typically used to disable Unicode ([see these docs](xref:core/modeling/entity-properties#unicode)). While this causes the correct column type to be created in the database, it also makes EF Core send database parameters in a way which is incompatible with UTF-8 data: `DbType.AnsiString` is used (signifying non-Unicode data), but `DbType.String` is needed to properly send Unicode data. - -As a result, you'll have to configure the EF property as a regular `nvarchar` column, ensuring that parameters are sent with the correct `DbType`: - -```c# -protected override void OnModelCreating(ModelBuilder modelBuilder) -{ - modelBuilder.Entity() - .Property(b => b.Name) - .UseCollation("LATIN1_GENERAL_100_CI_AS_SC_UTF8"); -} -``` - -Once you've created the migration for the column, edit it and manually change the column's type from `nvarchar` to `varchar`. - -*** - ## Sparse columns Sparse columns are ordinary columns that have an optimized storage for null values, reducing the space requirements for null values at the cost of more overhead to retrieve non-null values. diff --git a/entity-framework/core/providers/sql-server/functions.md b/entity-framework/core/providers/sql-server/functions.md index fb8c77c998..0bd0543b58 100644 --- a/entity-framework/core/providers/sql-server/functions.md +++ b/entity-framework/core/providers/sql-server/functions.md @@ -13,25 +13,25 @@ This page shows which .NET members are translated into which SQL functions when .NET | SQL | Added in ----------------------------------------------------------------------- | -------------------------------- | -------- -EF.Functions.StandardDeviationSample(group.Select(x => x.Property)) | STDEV(Property) | EF Core 7.0 -EF.Functions.StandardDeviationPopulation(group.Select(x => x.Property)) | STDEVP(Property) | EF Core 7.0 -EF.Functions.VarianceSample(group.Select(x => x.Property)) | VAR(Property) | EF Core 7.0 -EF.Functions.VariancePopulation(group.Select(x => x.Property)) | VARP(Property) | EF Core 7.0 +EF.Functions.StandardDeviationSample(group.Select(x => x.Property)) | STDEV(Property) +EF.Functions.StandardDeviationPopulation(group.Select(x => x.Property)) | STDEVP(Property) +EF.Functions.VarianceSample(group.Select(x => x.Property)) | VAR(Property) +EF.Functions.VariancePopulation(group.Select(x => x.Property)) | VARP(Property) group.Average(x => x.Property) | AVG(Property) group.Count() | COUNT(*) group.LongCount() | COUNT_BIG(*) group.Max(x => x.Property) | MAX(Property) group.Min(x => x.Property) | MIN(Property) group.Sum(x => x.Property) | SUM(Property) -string.Concat(group.Select(x => x.Property)) | STRING_AGG(Property, N'') | EF Core 7.0 -string.Join(separator, group.Select(x => x.Property)) | STRING_AGG(Property, @separator) | EF Core 7.0 +string.Concat(group.Select(x => x.Property)) | STRING_AGG(Property, N'') +string.Join(separator, group.Select(x => x.Property)) | STRING_AGG(Property, @separator) ## Binary functions .NET | SQL | Added in ---------------------------- | ----------------------------- | -------- bytes.Contains(value) | CHARINDEX(@value, @bytes) > 0 -bytes.ElementAt(i) | SUBSTRING(@bytes, @i + 1, 1) | EF Core 8.0 +bytes.ElementAt(i) | SUBSTRING(@bytes, @i + 1, 1) bytes.First() | SUBSTRING(@bytes, 1, 1) bytes.Length | DATALENGTH(@bytes) bytes.SequenceEqual(second) | @bytes = @second @@ -53,7 +53,7 @@ Convert.ToInt16(value) | CONVERT(smallint, @value) Convert.ToInt32(value) | CONVERT(int, @value) Convert.ToInt64(value) | CONVERT(bigint, @value) Convert.ToString(value) | CONVERT(nvarchar(max), @value) -dateOnly.ToString() | CONVERT(varchar(100), @dateOnly) | EF Core 8.0 +dateOnly.ToString() | CONVERT(varchar(100), @dateOnly) dateTime.ToString() | CONVERT(varchar(100), @dateTime) dateTimeOffset.ToString() | CONVERT(varchar(100), @dateTimeOffset) decimalValue.ToString() | CONVERT(varchar(100), @decimalValue) @@ -64,7 +64,7 @@ intValue.ToString() | CONVERT(varchar(11), @intValue) longValue.ToString() | CONVERT(varchar(20), @longValue) sbyteValue.ToString() | CONVERT(varchar(4), @sbyteValue) shortValue.ToString() | CONVERT(varchar(6), @shortValue) -timeOnly.ToString() | CONVERT(varchar(100), @timeOnly) | EF Core 8.0 +timeOnly.ToString() | CONVERT(varchar(100), @timeOnly) timeSpan.ToString() | CONVERT(varchar(100), @timeSpan) uintValue.ToString() | CONVERT(varchar(10), @uintValue) ulongValue.ToString() | CONVERT(varchar(19), @ulongValue) @@ -116,19 +116,19 @@ dateTimeOffset.Month | DATEPART(month, @d dateTimeOffset.Nanosecond | DATEPART(nanosecond, @dateTimeOffset) % 1000 | EF Core 10.0 dateTimeOffset.Second | DATEPART(second, @dateTimeOffset) dateTimeOffset.TimeOfDay | CONVERT(time, @dateTimeOffset) -dateTimeOffset.ToUnixTimeSeconds() | DATEDIFF_BIG(second, '1970-01-01T00:00:00.0000000+00:00', @dateTimeOffset) | EF Core 8.0 -dateTimeOffset.ToUnixTimeMilliseconds() | DATEDIFF_BIG(millisecond, '1970-01-01T00:00:00.0000000+00:00', @dateTimeOffset) | EF Core 8.0 +dateTimeOffset.ToUnixTimeSeconds() | DATEDIFF_BIG(second, '1970-01-01T00:00:00.0000000+00:00', @dateTimeOffset) +dateTimeOffset.ToUnixTimeMilliseconds() | DATEDIFF_BIG(millisecond, '1970-01-01T00:00:00.0000000+00:00', @dateTimeOffset) dateTimeOffset.Year | DATEPART(year, @dateTimeOffset) -DateOnly.FromDateTime(dateTime) | CONVERT(date, @dateTime) | EF Core 8.0 -dateOnly.AddDays(value) | DATEADD(day, @value, @dateOnly) | EF Core 8.0 -dateOnly.AddMonths(months) | DATEADD(month, @months, @dateOnly) | EF Core 8.0 -dateOnly.AddYears(value) | DATEADD(year, @value, @dateOnly) | EF Core 8.0 -dateOnly.Day | DATEPART(day, @dateOnly) | EF Core 8.0 -dateOnly.DayOfYear | DATEPART(dayofyear, @dateOnly) | EF Core 8.0 -dateOnly.Month | DATEPART(month, @dateOnly) | EF Core 8.0 -dateOnly.Year | DATEPART(year, @dateOnly) | EF Core 8.0 +DateOnly.FromDateTime(dateTime) | CONVERT(date, @dateTime) +dateOnly.AddDays(value) | DATEADD(day, @value, @dateOnly) +dateOnly.AddMonths(months) | DATEADD(month, @months, @dateOnly) +dateOnly.AddYears(value) | DATEADD(year, @value, @dateOnly) +dateOnly.Day | DATEPART(day, @dateOnly) +dateOnly.DayOfYear | DATEPART(dayofyear, @dateOnly) +dateOnly.Month | DATEPART(month, @dateOnly) +dateOnly.Year | DATEPART(year, @dateOnly) dateOnly.DayNumber | DATEDIFF(day, '0001-01-01', @dateOnly) | EF Core 10.0 -EF.Functions.AtTimeZone(dateTime, timeZone) | @dateTime AT TIME ZONE @timeZone | EF Core 7.0 +EF.Functions.AtTimeZone(dateTime, timeZone) | @dateTime AT TIME ZONE @timeZone EF.Functions.DateDiffDay(start, end) | DATEDIFF(day, @start, @end) EF.Functions.DateDiffHour(start, end) | DATEDIFF(hour, @start, @end) EF.Functions.DateDiffMicrosecond(start, end) | DATEDIFF(microsecond, @start, @end) @@ -146,15 +146,15 @@ EF.Functions.DateTimeOffsetFromParts(year, month, day, ...) | DATETIMEOFFSETFROM EF.Functions.IsDate(expression) | ISDATE(@expression) EF.Functions.SmallDateTimeFromParts(year, month, day, ...) | SMALLDATETIMEFROMPARTS(@year, @month, @day, ...) EF.Functions.TimeFromParts(hour, minute, second, ...) | TIMEFROMPARTS(@hour, @minute, @second, ...) -timeOnly.AddHours(value) | DATEADD(hour, @value, @timeOnly) | EF Core 8.0 -timeOnly.AddMinutes(value) | DATEADD(minute, @value, @timeOnly) | EF Core 8.0 -timeOnly.Hour | DATEPART(hour, @timeOnly) | EF Core 8.0 -timeOnly.IsBetween(start, end) | @timeOnly >= @start AND @timeOnly < @end | EF Core 8.0 +timeOnly.AddHours(value) | DATEADD(hour, @value, @timeOnly) +timeOnly.AddMinutes(value) | DATEADD(minute, @value, @timeOnly) +timeOnly.Hour | DATEPART(hour, @timeOnly) +timeOnly.IsBetween(start, end) | @timeOnly >= @start AND @timeOnly < @end timeOnly.Microsecond | DATEPART(microsecond, @timeOnly) % 1000 | EF Core 10.0 -timeOnly.Millisecond | DATEPART(millisecond, @timeOnly) | EF Core 8.0 -timeOnly.Minute | DATEPART(minute, @timeOnly) | EF Core 8.0 +timeOnly.Millisecond | DATEPART(millisecond, @timeOnly) +timeOnly.Minute | DATEPART(minute, @timeOnly) timeOnly.Nanosecond | DATEPART(nanosecond, @timeOnly) % 1000 | EF Core 10.0 -timeOnly.Second | DATEPART(second, @timeOnly) | EF Core 8.0 +timeOnly.Second | DATEPART(second, @timeOnly) timeSpan.Hours | DATEPART(hour, @timeSpan) timeSpan.Microsecond | DATEPART(microsecond, @timeSpan) % 1000 | EF Core 10.0 timeSpan.Milliseconds | DATEPART(millisecond, @timeSpan) @@ -166,8 +166,8 @@ timeSpan.Seconds | DATEPART(second, @ .NET | SQL | Added in -------------------------- | -------------------- | -------- -double.DegreesToRadians(x) | RADIANS(@x) | EF Core 8.0 -double.RadiansToDegrees(x) | DEGREES(@x) | EF Core 8.0 +double.DegreesToRadians(x) | RADIANS(@x) +double.RadiansToDegrees(x) | DEGREES(@x) EF.Functions.Random() | RAND() Math.Abs(value) | ABS(@value) Math.Acos(d) | ACOS(@d) @@ -219,7 +219,7 @@ stringValue.Contains(value) | @strin stringValue.EndsWith(value) | @stringValue LIKE N'%' + @value stringValue.FirstOrDefault() | SUBSTRING(@stringValue, 1, 1) stringValue.IndexOf(value) | CHARINDEX(@value, @stringValue) - 1 -stringValue.IndexOf(value, startIndex) | CHARINDEX(@value, @stringValue, @startIndex) - 1 | EF Core 7.0 +stringValue.IndexOf(value, startIndex) | CHARINDEX(@value, @stringValue, @startIndex) - 1 stringValue.LastOrDefault() | SUBSTRING(@stringValue, LEN(@stringValue), 1) stringValue.Length | LEN(@stringValue) stringValue.Replace(@oldValue, @newValue) | REPLACE(@stringValue, @oldValue, @newValue) @@ -242,9 +242,10 @@ nullable.GetValueOrDefault() | COALESCE(@nullable, 0) nullable.GetValueOrDefault(defaultValue) | COALESCE(@nullable, @defaultValue) > [!NOTE] -> Some SQL has been simplified for illustration purposes. The actual SQL is more complex to handle a wider range of values. +> Some SQL translations have been simplified for illustration purposes. The actual SQL is more complex to handle a wider range of values. ## See also +* [Vector Search Function Mappings](xref:core/providers/sql-server/vector-search) * [Spatial Function Mappings](xref:core/providers/sql-server/spatial#spatial-function-mappings) * [HierarchyId Function Mappings](xref:core/providers/sql-server/hierarchyid#function-mappings) diff --git a/entity-framework/core/providers/sql-server/vector-search.md b/entity-framework/core/providers/sql-server/vector-search.md new file mode 100644 index 0000000000..2cfae980d1 --- /dev/null +++ b/entity-framework/core/providers/sql-server/vector-search.md @@ -0,0 +1,80 @@ +--- +title: Microsoft SQL Server Database Provider - Vector Search - EF Core +description: Using vectors and embeddings to perform similarity search with the Entity Framework Core Microsoft SQL Server database provider +author: roji +ms.date: 08/17/2025 +uid: core/providers/sql-server/vector-search +--- +# Vector search in the SQL Server EF Core Provider + +## Vector search + +> [!NOTE] +> Vector support was introduced in EF Core 10.0, and is only supported with SQL Server 2025 and above. + +The SQL Server vector data type allows storing *embeddings*, which are representation of meaning that can be efficiently searched over for similarity, powering AI workloads such as semantic search and retrieval-augmented generation (RAG). + +To use the `vector` data type, simply add a .NET property of type `SqlVector` to your entity type, specifying the dimensions as follows: + +### [Data Annotations](#tab/data-annotations) + +```c# +public class Blog +{ + // ... + + [Column(TypeName = "vector(1536)")] + public SqlVector Embedding { get; set; } +} +``` + +### [Fluent API](#tab/fluent-api) + +```c# +public class Blog +{ + // ... + + public SqlVector Embedding { get; set; } +} + +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity() + .Property(b => b.Embedding) + .HasColumnType("vector(1536)"); +} +``` + +*** + +Once your property is added and the corresponding column created in the database, you can start inserting embeddings. Embedding generation is done outside of the database, usually via a service, and the details for doing this are out of scope for this documentation. However, [the .NET Microsoft.Extensions.AI libraries](/dotnet/ai/microsoft-extensions-ai) contains [`IEmbeddingGenerator`](/dotnet/ai/microsoft-extensions-ai#create-embeddings), which is an abstraction over embedding generators that has implementations for the major providers. + +Once you've chosen your embedding generator and set it up, use it to generate embeddings and insert them as follows + +```c# +IEmbeddingGenerator> embeddingGenerator = /* Set up your preferred embedding generator */; + +var embedding = await embeddingGenerator.GenerateVectorAsync("Some text to be vectorized"); +context.Blogs.Add(new Blog +{ + Name = "Some blog", + Embedding = new SqlVector(embedding) +}); +await context.SaveChangesAsync(); +``` + +Finally, use the [`EF.Functions.VectorDistance()`](/sql/t-sql/functions/vector-distance-transact-sql) function to perform similarity search for a given user query: + +```c# +var sqlVector = new SqlVector(await embeddingGenerator.GenerateVectorAsync("Some user query to be vectorized")); +var topSimilarBlogs = context.Blogs + .OrderBy(b => EF.Functions.VectorDistance("cosine", b.Embedding, sqlVector)) + .Take(3) + .ToListAsync(); +``` + +> [!NOTE] +> The built-in support in EF 10 replaces the previous [EFCore.SqlServer.VectorSearch](https://github.com/efcore/EFCore.SqlServer.VectorSearch) extension, which allowed performing vector search before the `vector` data type was introduced. As part of upgrading to EF 10, remove the extension from your projects. +> +> The [`VECTOR_SEARCH()`](/sql/t-sql/functions/vector-search-transact-sql) function (in preview) for approximate search with DiskANN is currently unsupported. diff --git a/entity-framework/core/providers/sqlite/functions.md b/entity-framework/core/providers/sqlite/functions.md index 0a656c6ab8..bcc0c1e3a4 100644 --- a/entity-framework/core/providers/sqlite/functions.md +++ b/entity-framework/core/providers/sqlite/functions.md @@ -21,8 +21,8 @@ group.Max(x => x.Property) | MAX(Property) group.Min(x => x.Property) | MIN(Property) group.Sum(x => x.Property) | SUM(Property) group.Sum(x => x.DecimalProperty) | ef_sum(DecimalProperty) | EF Core 9.0 -string.Concat(group.Select(x => x.Property)) | group_concat(Property, '') | EF Core 7.0 -string.Join(separator, group.Select(x => x.Property)) | group_concat(Property, @separator) | EF Core 7.0 +string.Concat(group.Select(x => x.Property)) | group_concat(Property, '') +string.Join(separator, group.Select(x => x.Property)) | group_concat(Property, @separator) ## Binary functions @@ -34,8 +34,8 @@ bytes.SequenceEqual(second) | @bytes = @second EF.Functions.Hex(bytes) | hex(@bytes) EF.Functions.Substr(bytes, startIndex) | substr(@bytes, @startIndex) EF.Functions.Substr(bytes, startIndex, length) | substr(@bytes, @startIndex, @length) -EF.Functions.Unhex(value) | unhex(@value) | EF Core 8.0 -EF.Functions.Unhex(value, ignoreChars) | unhex(@value, @ignoreChars) | EF Core 8.0 +EF.Functions.Unhex(value) | unhex(@value) +EF.Functions.Unhex(value, ignoreChars) | unhex(@value, @ignoreChars) ## Conversion functions @@ -69,7 +69,7 @@ dateOnly.AddYears(value) | date(@dateOnly, @value \|\| ' years') dateOnly.Day | strftime('%d', @dateOnly) dateOnly.DayOfWeek | strftime('%w', @dateOnly) dateOnly.DayOfYear | strftime('%j', @dateOnly) -DateOnly.FromDateTime(dateTime) | date(@dateTime) | EF Core 8.0 +DateOnly.FromDateTime(dateTime) | date(@dateTime) dateOnly.Month | strftime('%m', @dateOnly) dateOnly.Year | strftime('%Y', @dateOnly) dateOnly.DayNumber | CAST(julianday(@dateOnly) - julianday('0001-01-01') AS INTEGER) | EF Core 10.0 @@ -114,23 +114,23 @@ decimalValue < d | ef_compare(@decimalValue, @d) < 0 decimalValue <= d | ef_compare(@decimalValue, @d) <= 0 decimalValue > d | ef_compare(@decimalValue, @d) > 0 decimalValue >= d | ef_compare(@decimalValue, @d) >= 0 -double.DegreesToRadians(degrees) | radians(@degrees) | EF Core 8.0 -double.RadiansToDegrees(radians) | degrees(@dradians) | EF Core 8.0 +double.DegreesToRadians(degrees) | radians(@degrees) +double.RadiansToDegrees(radians) | degrees(@dradians) doubleValue % d | mod(@doubleValue, @d) EF.Functions.Random() | abs(random() / 9223372036854780000.0) Math.Abs(value) | abs(@value) -Math.Acos(value) | acos(@value) | EF Core 8.0 -Math.Acosh(d) | acosh(@d) | EF Core 8.0 -Math.Asin(d) | asin(@d) | EF Core 8.0 -Math.Asinh(d) | asinh(@d) | EF Core 8.0 -Math.Atan(d) | atan(@d) | EF Core 8.0 -Math.Atan2(y, x) | atan2(@y, @x) | EF Core 8.0 -Math.Atanh(d) | atanh(@d) | EF Core 8.0 -Math.Ceiling(d) | ceiling(@d) | EF Core 8.0 -Math.Cos(d) | cos(@d) | EF Core 8.0 -Math.Cosh(value) | cosh(@value) | EF Core 8.0 -Math.Exp(d) | exp(@d) | EF Core 8.0 -Math.Floor(d) | floor(@d) | EF Core 8.0 +Math.Acos(value) | acos(@value) +Math.Acosh(d) | acosh(@d) +Math.Asin(d) | asin(@d) +Math.Asinh(d) | asinh(@d) +Math.Atan(d) | atan(@d) +Math.Atan2(y, x) | atan2(@y, @x) +Math.Atanh(d) | atanh(@d) +Math.Ceiling(d) | ceiling(@d) +Math.Cos(d) | cos(@d) +Math.Cosh(value) | cosh(@value) +Math.Exp(d) | exp(@d) +Math.Floor(d) | floor(@d) Math.Log(d) | ln(@d) | EF Core 8.0 Math.Log(a, newBase) | log(@newBase, @a) | EF Core 8.0 Math.Log2(x) | log2(@x) | EF Core 8.0 diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 6d3d4dbb2c..96d278934f 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -19,21 +19,131 @@ EF10 requires the .NET 10 SDK to build and requires the .NET 10 runtime to run. -## Named query filters +## Azure SQL and SQL Server -EF's [global query filters](xref:core/querying/filters) feature has long enabled users to configuring filters to entity types which apply to all queries by default. This has simplified implementing common patterns and scenarios such as soft deletion, multitenancy and others. However, up to now EF has only supported a single query filter per entity type, making it difficult to have multiple filters and selectively disabling only some of them in specific queries. +### Vector search support -EF 10 introduces *named query filters*, which allow attaching names to query filter and managing each one separately: +EF 10 brings full support for the recently-introduced [vector data type](/sql/t-sql/data-types/vector-data-type) and its supporting [`VECTOR_DISTANCE()`](/sql/t-sql/functions/vector-distance-transact-sql) function, available on Azure SQL Database and on SQL Server 2025. The vector data type allows storing *embeddings*, which are representation of meaning that can be efficiently searched over for similarity, powering AI workloads such as semantic search and retrieval-augmented generation (RAG). -[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#FilterConfiguration)] +To use the `vector` data type, simply add a .NET property of type `SqlVector` to your entity type: -This notably allows disabling only certain filters in a specific LINQ query: +```c# +public class Blog +{ + // ... -[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#DisableSoftDeletionFilter)] + [Column(TypeName = "vector(1536)")] + public SqlVector Embedding { get; set; } +} +``` -For more information on named query filters, see the [documentation](xref:core/querying/filters). +Then, insert embedding data by populating the Embedding property and calling `SaveChangesAsync()` as usual: -This feature was contributed by [@bittola](https://github.com/bittola). +```c# +IEmbeddingGenerator> embeddingGenerator = /* Set up your preferred embedding generator */; + +var embedding = await embeddingGenerator.GenerateVectorAsync("Some text to be vectorized"); +context.Blogs.Add(new Blog +{ + Name = "Some blog", + Embedding = new SqlVector(embedding) +}); +await context.SaveChangesAsync(); +``` + +Finally, use the [`EF.Functions.VectorDistance()`](/sql/t-sql/functions/vector-distance-transact-sql) function in your LINQ queries to perform similarity search for a given user query: + +```c# +var sqlVector = /* some user query which we should search for similarity */; +var topSimilarBlogs = context.Blogs + .OrderBy(b => EF.Functions.VectorDistance("cosine", b.Embedding, sqlVector)) + .Take(3) + .ToListAsync(); +``` + +For more information on vector search, [see the documentation](xref:core/providers/sql-server/vector-search). + +### JSON type support + +EF 10 also fully supports the new [json data type](/sql/t-sql/data-types/json-data-type), also available on Azure SQL Database and on SQL Server 2025. While SQL Server has included JSON functionality for several versions, the data itself was stored in plain textual columns in the database; the new data type provides significant efficiency improvements and a safer way to store and interact with JSON. + +With EF 10, if you've configured EF with `UseAzureSql()` or with a compatibility level of 170 or higher (SQL Server 2025), EF automatically defaults to using the new JSON data type. For example, the following entity type has a primitive collection (Tags, an array of strings) and Details (mapped as a complex type): + +```c# +public class Blog +{ + public int Id { get; set; } + + public string[] Tags { get; set; } + public required BlogDetails Details { get; set; } +} + +public class BlogDetails +{ + public string? Description { get; set; } + public int Viewers { get; set; } +} + +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity().ComplexProperty(b => b.Details, b => b.ToJson()); +} +``` + +EF 10 creates the following table for the above: + +```sql +CREATE TABLE [Blogs] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(max) NOT NULL, + [Tags] json NOT NULL, + [Details] json NOT NULL, + CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]) +); +``` + +LINQ querying is fully supported as well. For example, the following filters for blogs with more than 3 viewers: + +```c# +var highlyViewedBlogs = await context.Blogs.Where(b => b.Details.Viewers > 3).ToListAsync(); +``` + +This produces the following SQL, making use of the new `JSON_VALUE()` `RETURNING` clause: + +```sql +SELECT [b].[Id], [b].[Name], [b].[Tags], [b].[Details] +FROM [Blogs] AS [b] +WHERE JSON_VALUE([b].[Details], '$.Viewers' RETURNING int) > 3 +``` + +Note that if your EF application already uses JSON via `nvarchar` columns, these columns will be automatically changed to `json` with the first migration. You can opt out of this by manually setting the column type to `nvarchar(max)`, or configuring a compatibility level lower than 170. + + + +### Custom default constraint names + +EF 10 now allows you to specify a name for default constraints, rather than letting the database generate them: + +```c# +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity() + .Property(p => b.CreatedDate) + .HasDefaultValueSql("GETDATE()", "DF_Post_CreatedDate"); +} +``` + +You can also enable automatic naming by EF of all default constraints: + +```c# +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.UseNamedDefaultConstraints(); +} +``` + +> [!NOTE] +> If you have existing migrations, the next migration you add will rename every single default constraint in your model. ## Azure Cosmos DB for NoSQL @@ -77,7 +187,7 @@ var cosmosBlogs = await context.Blogs.Where(x => EF.Functions.FullTextContains(x The following full-text operations are currently supported: [`FullTextContains`](/azure/cosmos-db/nosql/query/fulltextcontains), [`FullTextContainsAll`](/azure/cosmos-db/nosql/query/fulltextcontainsall), [`FullTextContainsAny`](/azure/cosmos-db/nosql/query/fulltextcontainsany), [`FullTextScore`](/azure/cosmos-db/nosql/query/fulltextscore). -For more information on Cosmos full-text search, see the [docs](xref:core/providers/cosmos/full-text-search). +For more information on Cosmos full-text search, see the [documentation](xref:core/providers/cosmos/full-text-search). ### Hybrid search @@ -92,7 +202,7 @@ var hybrid = await context.Blogs.OrderBy(x => EF.Functions.Rrf( .ToListAsync(); ``` -For more information on Cosmos hybrid search, see the [docs](xref:core/providers/cosmos/full-text-search?#hybrid-search). +For more information on Cosmos hybrid search, [see the documentation](xref:core/providers/cosmos/full-text-search?#hybrid-search). ### Vector similarity search exits preview @@ -101,7 +211,7 @@ In EF9 we added experimental support for [vector similarity search](xref:core/wh - EF Core can now generate containers with vector properties defined on owned reference entities. Containers with vector properties defined on owned collections still have to be created by other means. However, they can be used in queries. - Model building APIs have been renamed. A vector property can now be configured using the `IsVectorProperty` method, and vector index can be configured using the `IsVectorIndex` method. -For more information on Cosmos vector search, see the [docs](xref:core/providers/cosmos/vector-search). +For more information on Cosmos vector search, [see the documentation](xref:core/providers/cosmos/vector-search). @@ -111,6 +221,24 @@ In previous versions of EF Core, evolving the model when using Azure Cosmos DB w In EF 10 we improved this experience - EF will now materialize a default value for a required property, if no data is present for it in the document, rather than throw. + + +## Named query filters + +EF's [global query filters](xref:core/querying/filters) feature has long enabled users to configuring filters to entity types which apply to all queries by default. This has simplified implementing common patterns and scenarios such as soft deletion, multitenancy and others. However, up to now EF has only supported a single query filter per entity type, making it difficult to have multiple filters and selectively disabling only some of them in specific queries. + +EF 10 introduces *named query filters*, which allow attaching names to query filter and managing each one separately: + +[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#FilterConfiguration)] + +This notably allows disabling only certain filters in a specific LINQ query: + +[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#DisableSoftDeletionFilter)] + +For more information on named query filters, [see the documentation](xref:core/querying/filters). + +This feature was contributed by [@bittola](https://github.com/bittola). + ## LINQ and SQL translation @@ -271,38 +399,6 @@ await context.Blogs.ExecuteUpdateAsync(s => Thanks to [@aradalvand](https://github.com/aradalvand) for proposing and pushing for this change (in [#32018](https://github.com/dotnet/efcore/issues/32018)). - - -## Custom default constraint names - -In previous versions of EF Core, when you specified a default value for a property, EF Core would always let the database automatically generate a constraint name. Now, you can explicitly specify the name for default value constraints for SQL Server, giving you more control over your database schema. - -You can now specify a constraint name when defining default values in your model configuration: - -```C# -protected override void OnModelCreating(ModelBuilder modelBuilder) -{ - modelBuilder.Entity() - .Property(b => b.IsActive) - .HasDefaultValue(true, "DF_Blog_IsActive"); - - modelBuilder.Entity() - .Property(p => b.CreatedDate) - .HasDefaultValueSql("GETDATE()", "DF_Post_CreatedDate"); -} - -``` - -You can also call `UseNamedDefaultConstraints` to enable automatic naming of all the default constraints. Note that if you have existing migrations then the next migration you add will rename every single default constraint in your model. - -```C# -protected override void OnModelCreating(ModelBuilder modelBuilder) -{ - modelBuilder.UseNamedDefaultConstraints(); -} - -``` - ## Other improvements diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index 6f11095fbb..981f1181ee 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -402,6 +402,8 @@ href: core/providers/sql-server/indexes.md - name: Value generation href: core/providers/sql-server/value-generation.md + - name: Vector search + href: core/providers/sql-server/vector-search.md - name: Temporal tables href: core/providers/sql-server/temporal-tables.md - name: Memory-optimized tables From f1e02687502a8c2daf841b22cb9e0c3e5a79de73 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 19 Aug 2025 23:44:33 +0200 Subject: [PATCH 184/224] Cosmos docs leftovers for 10 (#5086) --- .../core/providers/cosmos/full-text-search.md | 90 +++++++++---------- .../core/providers/cosmos/querying.md | 59 +++++++----- .../ef-core-10.0/breaking-changes.md | 4 +- 3 files changed, 78 insertions(+), 75 deletions(-) diff --git a/entity-framework/core/providers/cosmos/full-text-search.md b/entity-framework/core/providers/cosmos/full-text-search.md index 541a20888b..0140b7d07f 100644 --- a/entity-framework/core/providers/cosmos/full-text-search.md +++ b/entity-framework/core/providers/cosmos/full-text-search.md @@ -46,34 +46,34 @@ public class BloggingContext Full-text search operations are language specific, using American English (`en-US`) by default. You can customize the language for individual properties as part of `EnableFullTextSearch` call: ```c# - protected override void OnModelCreating(ModelBuilder modelBuilder) +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity(b => { - modelBuilder.Entity(b => - { - b.Property(x => x.Contents).EnableFullTextSearch(); - b.HasIndex(x => x.Contents).IsFullTextIndex(); - b.Property(x => x.ContentsGerman).EnableFullTextSearch("de-DE"); - b.HasIndex(x => x.ContentsGerman).IsFullTextIndex(); - }); - } + b.Property(x => x.Contents).EnableFullTextSearch(); + b.HasIndex(x => x.Contents).IsFullTextIndex(); + b.Property(x => x.ContentsGerman).EnableFullTextSearch("de-DE"); + b.HasIndex(x => x.ContentsGerman).IsFullTextIndex(); + }); +} ``` You can also set a default language for the container - unless overridden in the `EnableFullTextSearch` method, all full-text properties inside the container will use that language. ```c# - protected override void OnModelCreating(ModelBuilder modelBuilder) +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity(b => { - modelBuilder.Entity(b => - { - b.HasDefaultFullTextLanguage("de-DE"); - b.Property(x => x.ContentsEnglish).EnableFullTextSearch("en-US"); - b.HasIndex(x => x.ContentsEnglish).IsFullTextIndex(); - b.Property(x => x.ContentsGerman).EnableFullTextSearch(); - b.HasIndex(x => x.ContentsGerman).IsFullTextIndex(); - b.Property(x => x.TagsGerman).EnableFullTextSearch(); - b.HasIndex(x => x.TagsGerman).IsFullTextIndex(); - }); - } + b.HasDefaultFullTextLanguage("de-DE"); + b.Property(x => x.ContentsEnglish).EnableFullTextSearch("en-US"); + b.HasIndex(x => x.ContentsEnglish).IsFullTextIndex(); + b.Property(x => x.ContentsGerman).EnableFullTextSearch(); + b.HasIndex(x => x.ContentsGerman).IsFullTextIndex(); + b.Property(x => x.TagsGerman).EnableFullTextSearch(); + b.HasIndex(x => x.TagsGerman).IsFullTextIndex(); + }); +} ``` ## Querying @@ -94,41 +94,33 @@ var mostInteresting = await context.Blogs.OrderBy(x => EF.Functions.FullTextScor ## Hybrid search -Full-text search can be used with vector search in the same query (i.e. hybrid search), by combining results of `FullTextScore` and `VectorDistance` functions. It can be done using the [`RRF`](/azure/cosmos-db/nosql/query/rrf) (Reciprocal Rank Fusion) function, which EF Core also provides inside `EF.Functions`: +Full-text search can be used with [vector search](xref:core/providers/cosmos/vector-search) in the same query; this is sometimes known as "hybrid search", and involves combining the scoring results from multiple searches via the [RRF (Reciprocal Rank Fusion) function](/azure/cosmos-db/nosql/query/rrf). Once you have your vector and full-text search configuration properly set up, you can perform hybrid search as follows: ```c# -public class Blog -{ - ... - - public float[] Vector { get; set; } - public string Contents { get; set; } -} - -public class BloggingContext -{ - ... - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity(b => - { - b.Property(x => x.Contents).EnableFullTextSearch(); - b.HasIndex(x => x.Contents).IsFullTextIndex(); - - b.Property(x => x.Vector).IsVectorProperty(DistanceFunction.Cosine, dimensions: 1536); - b.HasIndex(x => x.Vector).IsVectorIndex(VectorIndexType.Flat); - }); - } -} - float[] myVector = /* generate vector data from text, image, etc. */ -var hybrid = await context.Blogs.OrderBy(x => EF.Functions.Rrf( +var hybrid = await context.Blogs + .OrderBy(x => EF.Functions.Rrf( EF.Functions.FullTextScore(x.Contents, "database"), EF.Functions.VectorDistance(x.Vector, myVector))) .Take(10) .ToListAsync(); ``` +The RRF function also allows assigning different weights to each search function, allowing e.g. the vector search to have great weight in the overall results: + +```c# +float[] myVector = /* generate vector data from text, image, etc. */ +var hybrid = await context.Blogs + .OrderBy(x => EF.Functions.Rrf( + new[] + { + EF.Functions.FullTextScore(x.Contents, "database"), + EF.Functions.VectorDistance(x.Vector, myVector) + }, + weights: new[] { 1, 2 })) + .Take(10) + .ToListAsync(); +``` + > [!TIP] -> You can combine more than two scoring functions inside `Rrf` call, as well as using only `FullTextScore`, or only `VectorDistance`. +> You can combine more than two scoring functions inside `Rrf` call, as well as using only `FullTextScore`, or only `VectorDistance` invocations. diff --git a/entity-framework/core/providers/cosmos/querying.md b/entity-framework/core/providers/cosmos/querying.md index 4d583614c5..089a75e315 100644 --- a/entity-framework/core/providers/cosmos/querying.md +++ b/entity-framework/core/providers/cosmos/querying.md @@ -223,19 +223,19 @@ This section shows which .NET methods and members are translated into which SQL ------------------------------------------ | --------------------------------------------------------------------------------- | -------- DateTime.UtcNow | [GetCurrentDateTime()](/azure/cosmos-db/nosql/query/getcurrentdatetime) DateTimeOffset.UtcNow | [GetCurrentDateTime()](/azure/cosmos-db/nosql/query/getcurrentdatetime) -dateTime.Year1 | [DateTimePart("yyyy", dateTime)](/azure/cosmos-db/nosql/query/datetimepart) | EF Core 9.0 -dateTimeOffset.Year1 | [DateTimePart("yyyy", dateTimeOffset)](/azure/cosmos-db/nosql/query/datetimepart) | EF Core 9.0 -dateTime.AddYears(years)1 | [DateTimeAdd("yyyy", dateTime)](/azure/cosmos-db/nosql/query/datetimeadd) | EF Core 9.0 -dateTimeOffset.AddYears(years)1 | [DateTimeAdd("yyyy", dateTimeOffset)](/azure/cosmos-db/nosql/query/datetimeadd) | EF Core 9.0 +dateTime.Year1 | [DateTimePart("yyyy", dateTime)](/azure/cosmos-db/nosql/query/datetimepart) | EF 9 +dateTimeOffset.Year1 | [DateTimePart("yyyy", dateTimeOffset)](/azure/cosmos-db/nosql/query/datetimepart) | EF 9 +dateTime.AddYears(years)1 | [DateTimeAdd("yyyy", dateTime)](/azure/cosmos-db/nosql/query/datetimeadd) | EF 9 +dateTimeOffset.AddYears(years)1 | [DateTimeAdd("yyyy", dateTimeOffset)](/azure/cosmos-db/nosql/query/datetimeadd) | EF 9 1 The other component members are translated as well (Month, Day...). ### Numeric functions -.NET | SQL | Added in --------------------------- | --------------------------------------------------- | -------- -double.DegreesToRadians(x) | [RADIANS(@x)](/azure/cosmos-db/nosql/query/radians) | EF Core 8.0 -double.RadiansToDegrees(x) | [DEGREES(@x)](/azure/cosmos-db/nosql/query/degrees) | EF Core 8.0 +.NET | SQL +-------------------------- | --------------------------------------------------- +double.DegreesToRadians(x) | [RADIANS(@x)](/azure/cosmos-db/nosql/query/radians) +double.RadiansToDegrees(x) | [DEGREES(@x)](/azure/cosmos-db/nosql/query/degrees) EF.Functions.Random() | [RAND()](/azure/cosmos-db/nosql/query/rand) Math.Abs(value) | [ABS(@value)](/azure/cosmos-db/nosql/query/abs) Math.Acos(d) | [ACOS(@d)](/azure/cosmos-db/nosql/query/acos) @@ -266,17 +266,17 @@ Math.Truncate(d) | [TRUNC(@d)](/azure/cosmos-db/nosql/query/trunc) .NET | SQL | Added in ----------------------------------------------------------------- | ---------------------------------------------------------------------------------- | -------- -Regex.IsMatch(input, pattern) | [RegexMatch(@pattern, @input)](/azure/cosmos-db/nosql/query/regexmatch) | EF Core 7.0 -Regex.IsMatch(input, pattern, options) | [RegexMatch(@input, @pattern, @options)](/azure/cosmos-db/nosql/query/regexmatch) | EF Core 7.0 +Regex.IsMatch(input, pattern) | [RegexMatch(@pattern, @input)](/azure/cosmos-db/nosql/query/regexmatch) +Regex.IsMatch(input, pattern, options) | [RegexMatch(@input, @pattern, @options)](/azure/cosmos-db/nosql/query/regexmatch) string.Concat(str0, str1) | @str0 + @str1 string.Equals(a, b, StringComparison.Ordinal) | [STRINGEQUALS(@a, @b)](/azure/cosmos-db/nosql/query/stringequals) string.Equals(a, b, StringComparison.OrdinalIgnoreCase) | [STRINGEQUALS(@a, @b, true)](/azure/cosmos-db/nosql/query/stringequals) stringValue.Contains(value) | [CONTAINS(@stringValue, @value)](/azure/cosmos-db/nosql/query/contains) -stringValue.Contains(value, StringComparison.Ordinal) | [CONTAINS(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/contains) | EF Core 9.0 -stringValue.Contains(value, StringComparison.OrdinalIgnoreCase) | [CONTAINS(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/contains) | EF Core 9.0 +stringValue.Contains(value, StringComparison.Ordinal) | [CONTAINS(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/contains) | EF 9 +stringValue.Contains(value, StringComparison.OrdinalIgnoreCase) | [CONTAINS(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/contains) | EF 9 stringValue.EndsWith(value) | [ENDSWITH(@stringValue, @value)](/azure/cosmos-db/nosql/query/endswith) -stringValue.EndsWith(value, StringComparison.Ordinal) | [ENDSWITH(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/endswith) | EF Core 9.0 -stringValue.EndsWith(value, StringComparison.OrdinalIgnoreCase) | [ENDSWITH(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/endswith) | EF Core 9.0 +stringValue.EndsWith(value, StringComparison.Ordinal) | [ENDSWITH(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/endswith) | EF 9 +stringValue.EndsWith(value, StringComparison.OrdinalIgnoreCase) | [ENDSWITH(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/endswith) | EF 9 stringValue.Equals(value, StringComparison.Ordinal) | [STRINGEQUALS(@stringValue, @value)](/azure/cosmos-db/nosql/query/stringequals) stringValue.Equals(value, StringComparison.OrdinalIgnoreCase) | [STRINGEQUALS(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/stringequals) stringValue.FirstOrDefault() | [LEFT(@stringValue, 1)](/azure/cosmos-db/nosql/query/left) @@ -286,8 +286,8 @@ stringValue.LastOrDefault() | [RIGHT(@stri stringValue.Length | [LENGTH(@stringValue)](/azure/cosmos-db/nosql/query/length) stringValue.Replace(oldValue, newValue) | [REPLACE(@stringValue, @oldValue, @newValue)](/azure/cosmos-db/nosql/query/replace) stringValue.StartsWith(value) | [STARTSWITH(@stringValue, @value)](/azure/cosmos-db/nosql/query/startswith) -stringValue.StartsWith(value, StringComparison.Ordinal) | [STARTSWITH(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/startswith) | EF Core 9.0 -stringValue.StartsWith(value, StringComparison.OrdinalIgnoreCase) | [STARTSWITH(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/startswith) | EF Core 9.0 +stringValue.StartsWith(value, StringComparison.Ordinal) | [STARTSWITH(@stringValue, @value, false)](/azure/cosmos-db/nosql/query/startswith) | EF 9 +stringValue.StartsWith(value, StringComparison.OrdinalIgnoreCase) | [STARTSWITH(@stringValue, @value, true)](/azure/cosmos-db/nosql/query/startswith) | EF 9 stringValue.Substring(startIndex) | [SUBSTRING(@stringValue, @startIndex, LENGTH(@stringValue))](/azure/cosmos-db/nosql/query/substring) stringValue.Substring(startIndex, length) | [SUBSTRING(@stringValue, @startIndex, @length)](/azure/cosmos-db/nosql/query/substring) stringValue.ToLower() | [LOWER(@stringValue)](/azure/cosmos-db/nosql/query/lower) @@ -296,17 +296,28 @@ stringValue.Trim() | [TRIM(@strin stringValue.TrimEnd() | [RTRIM(@stringValue)](/azure/cosmos-db/nosql/query/rtrim) stringValue.TrimStart() | [LTRIM(@stringValue)](/azure/cosmos-db/nosql/query/ltrim) +### Vector and full-text search + +.NET | SQL | Added in +--------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----- +EF.Functions.VectorDistance(vector1, vector2). | [VectorDistance(vector1, vector2)](/azure/cosmos-db/nosql/query/vectordistance) | EF 9 +EF.Functions.VectorDistance(vector1, vector2, bruteForce) | [VectorDistance(vector1, vector2, bruteForce)](/azure/cosmos-db/nosql/query/vectordistance) | EF 9 +EF.Functions.VectorDistance(vector1, vector2, bruteForce, distanceFunction) | [VectorDistance(vector1, vector2, bruteForce, distanceFunction)](/azure/cosmos-db/nosql/query/vectordistance) | EF 9 +EF.Functions.FullTextContains(property, keyword) | [FullTextContains(property, keyword)](/azure/cosmos-db/nosql/query/fulltextcontains) | EF 10 +EF.Functions.FullTextContainsAll(property, keyword1, keyword2) | [FullTextContainsAll(property, keyword1, keyword2)](/azure/cosmos-db/nosql/query/fulltextcontainsall) | EF 10 +EF.Functions.FullTextContainsAny(property, keyword1, keyword2) | [FullTextContainsAny(property, keyword1, keyword2)](/azure/cosmos-db/nosql/query/fulltextcontainsany) | EF 10 +EF.Functions.FullTextScore(property, keyword1, keyword2) | [FullTextScore(property, keyword1, keyword2)](/azure/cosmos-db/nosql/query/fulltextscore) | EF 10 +EF.Functions.Rrf(search1, search2) | [RRF(property, search1, search2)](/azure/cosmos-db/nosql/query/rrf). | EF 10 +EF.Functions.Rrf(new[] { search1, search2 }, weights) | [RRF(property, search1, search2, weights)](/azure/cosmos-db/nosql/query/rrf) | EF 10 + +For more information on vector search, see [the documentation](xref:core/providers/cosmos/vector-search). For more information on full-text search, see [the documentation](xref:core/providers/cosmos/full-text-search). + ### Miscellaneous functions -.NET | SQL | Notes +.NET | SQL | Added in --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----- collection.Contains(item) | @item IN @collection -EF.Functions.CoalesceUndefined(x, y)1 | [x ?? y](/azure/cosmos-db/nosql/query/ternary-coalesce-operators#coalesce-operator) | Added in EF Core 9.0 -EF.Functions.IsDefined(x) | [IS_DEFINED(x)](/azure/cosmos-db/nosql/query/is-defined) | Added in EF Core 9.0 -EF.Functions.VectorDistance(vector1, vector2)2 | [VectorDistance(vector1, vector2)](/azure/cosmos-db/nosql/query/vectordistance) | Added in EF Core 9.0, Experimental -EF.Functions.VectorDistance(vector1, vector2, bruteForce)2 | [VectorDistance(vector1, vector2, bruteForce)](/azure/cosmos-db/nosql/query/vectordistance) | Added in EF Core 9.0, Experimental -EF.Functions.VectorDistance(vector1, vector2, bruteForce, distanceFunction)2 | [VectorDistance(vector1, vector2, bruteForce, distanceFunction)](/azure/cosmos-db/nosql/query/vectordistance) | Added in EF Core 9.0, Experimental +EF.Functions.CoalesceUndefined(x, y)1 | [x ?? y](/azure/cosmos-db/nosql/query/ternary-coalesce-operators#coalesce-operator) | EF 9 +EF.Functions.IsDefined(x) | [IS_DEFINED(x)](/azure/cosmos-db/nosql/query/is-defined) | EF 9 1 Note that `EF.Functions.CoalesceUndefined` coalesces `undefined`, not `null`. To coalesce `null`, use the regular C# `??` operator. - -2 [See the documentation](xref:core/providers/cosmos/vector-search) for information on using vector search in Azure Cosmos DB, which is experimental. The APIs are subject to change. diff --git a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md index 51302797a3..7c41fe4dd5 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md @@ -95,9 +95,9 @@ await context.Blogs.ExecuteUpdateAsync(s => | **Breaking change** | **Impact** | |:----------------------------------------------------------------------------------------------------------|------------| -| [Using GetDateTimeOffset without an offset now assumes UTC](#DateTimeOffset-read) | High | +| [Using GetDateTimeOffset without an offset now assumes UTC](#DateTimeOffset-read) | High | | [Writing DateTimeOffset into REAL column now writes in UTC](#DateTimeOffset-write) | High | -| [Using GetDateTime with an offset now returns value in UTC](#DateTime-read) | High | +| [Using GetDateTime with an offset now returns value in UTC](#DateTime-read) | High | ### High-impact changes From 7e64f1f9e1d92e7e03b25af9797c7da98b217bf7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 22 Aug 2025 18:14:52 +0200 Subject: [PATCH 185/224] Breaking change note for SQL Server json data type (#5085) --- .../ef-core-10.0/breaking-changes.md | 92 ++++++++++++++++++- .../core/what-is-new/ef-core-10.0/whatsnew.md | 3 + 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md index 7c41fe4dd5..e217d81cf7 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md @@ -20,12 +20,98 @@ This page documents API and behavior changes that have the potential to break ex > [!NOTE] > If you are using Microsoft.Data.Sqlite, please see the [separate section below on Microsoft.Data.Sqlite breaking changes](#MDS-breaking-changes). -| **Breaking change** | **Impact** | -|:----------------------------------------------------------------------------------------------------------|------------| -| [ExecuteUpdateAsync now accepts a regular, non-expression lambda](#ExecuteUpdateAsync-lambda) | Low | +| **Breaking change** | **Impact** | +|:--------------------------------------------------------------------------------------------------------------- | -----------| +| [SQL Server json data type used by default on Azure SQL and compatibility level 170](#sqlserver-json-data-type) | Low | +| [ExecuteUpdateAsync now accepts a regular, non-expression lambda](#ExecuteUpdateAsync-lambda) | Low | ## Low-impact changes + + +### SQL Server json data type used by default on Azure SQL and compatibility level 170 + +[Tracking Issue #36372](https://github.com/dotnet/efcore/issues/36372) + +#### Old behavior + +Previously, when mapping primitive collections or owned types to JSON in the database, the SQL Server provider stored the JSON data in an `nvarchar(max)` column: + +```c# +public class Blog +{ + // ... + + // Primitive collection, mapped to nvarchar(max) JSON column + public string[] Tags { get; set; } + // Owned entity type mapped to nvarchar(max) JSON column + public List Posts { get; set; } +} + +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity().OwnsMany(b => b.Posts, b => b.ToJson()); +} +``` + +For the above, EF previously generated the following table: + +```sql +CREATE TABLE [Blogs] ( + ... + [Tags] nvarchar(max), + [Posts] nvarchar(max) +); +``` + +#### New behavior + +With EF 10, if you configure EF with ([see documentation](xref:core/providers/sql-server/index#usage-and-configuration)), or configure EF with a compatibility level of 170 or above ([see documentation](xref:core/providers/sql-server/index#compatibility-level)), EF will map to the new JSON data type instead: + +```sql +CREATE TABLE [Blogs] ( + ... + [Tags] json + [Posts] json +); +``` + +Note that if you have an existing table and are using , upgrading to EF 10 will cause a migration to be generated which alters all existing `nvarchar(max)` JSON columns to `json`. This alter operation is supported and should get applied seamlessly and without any issues, but is a non-trivial change to your database. + +> [!NOTE] +> For 10.0.0 rc1, support for the new JSON data type has been temporarily disabled for Azure SQL Database, due to lacking support. These issues are expected to be resolved by the time EF 10.0 is released, and the JSON data type will become the default until then. + +#### Why + +The new JSON data type introduced by SQL Server is a superior, 1st-class way to store and interact with JSON data in the database; it notably brings significant performance improvements ([see documentation](/sql/t-sql/data-types/json-data-type)). All applications using Azure SQL Database or SQL Server 2025 are encouraged to migrate to the new JSON data type. + +#### Mitigations + +If you do not wish to transition to the new JSON data type right away, you can configure EF with a compatibility level lower than 170: + +```c# +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +{ + optionsBuilder.UseSqlServer("", o => o.UseCompatibilityLevel(160)); +} +``` + +As an alternative, you can explicitly set the column type for your properties to be `nvarchar(max)`: + +```c# +public class Blog +{ + public string[] Tags { get; set; } + public List Posts { get; set; } +} + +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity().PrimitiveCollection(b => b.Tags).HasColumnType("nvarchar(max)"); + modelBuilder.Entity().OwnsMany(b => b.Posts, b => b.ToJson().HasColumnType("nvarchar(max)")); +} +``` + ### ExecuteUpdateAsync now accepts a regular, non-expression lambda diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 96d278934f..982388790d 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -118,6 +118,9 @@ WHERE JSON_VALUE([b].[Details], '$.Viewers' RETURNING int) > 3 Note that if your EF application already uses JSON via `nvarchar` columns, these columns will be automatically changed to `json` with the first migration. You can opt out of this by manually setting the column type to `nvarchar(max)`, or configuring a compatibility level lower than 170. +> [!NOTE] +> For 10.0.0 rc1, support for the new JSON data type has been temporarily disabled for Azure SQL Database, due to lacking support. These issues are expected to be resolved by the time EF 10.0 is released, and the JSON data type will become the default until then. + ### Custom default constraint names From d0eb41a1831d5c52b13e12f0dda2bd7c55b51c9e Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 2 Sep 2025 17:46:01 +0200 Subject: [PATCH 186/224] Document split query ordering consistency for EF10 (#5091) See https://github.com/dotnet/efcore/issues/26808 --- .../core/what-is-new/ef-core-10.0/whatsnew.md | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 982388790d..8b8bcce103 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -334,6 +334,53 @@ Unfortunately, C# query syntax (`from x select x.Id`) doesn't yet support expres See [#12793](https://github.com/dotnet/efcore/issues/12793) and [#35367](https://github.com/dotnet/efcore/issues/35367) for more details. +### More consistent ordering for split queries + +Split queries can be essential to avoid performance issues associated with JOINs, such as the so-called "cartesian explosion" effect (see [Single vs. Split Queries](xref:core/querying/single-split-queries) to learn more). However, since split queries loads related data in separate SQL queries, consistency issues can arise, possibly leading to non-deterministic, hard-to-detect data corruption. + +For example, consider the following query: + +```C# +var blogs = await context.Blogs + .AsSplitQuery() + .Include(b => b.Posts) + .OrderBy(b => b.Name) + .Take(2) + .ToListAsync(); +``` + +Prior to EF10, the following two SQL queries were generated: + +```sql +SELECT TOP(@__p_0) [b].[Id], [b].[Name] +FROM [Blogs] AS [b] +ORDER BY [b].[Name], [b].[Id] + +SELECT [p].[Id], [p].[BlogId], [p].[Title], [b0].[Id] +FROM ( + SELECT TOP(@__p_0) [b].[Id], [b].[Name] + FROM [Blogs] AS [b] + ORDER BY [b].[Name] +) AS [b0] +INNER JOIN [Post] AS [p] ON [b0].[Id] = [p].[BlogId] +ORDER BY [b0].[Name], [b0].[Id] +``` + +Note that the first query (the one reading Blogs) is integrated as a subquery within the second (the one reading Posts). However, the ordering within the subquery omits the `Id` column, leading to possible incorrect data being returned. + +EF10 fixes this by ensuring that the ordering is consistent across the queries: + +```sql +SELECT [p].[Id], [p].[BlogId], [p].[Title], [b0].[Id] +FROM ( + SELECT TOP(@p) [b].[Id], [b].[Name] + FROM [Blogs] AS [b] + ORDER BY [b].[Name], [b].[Id] +) AS [b0] +INNER JOIN [Post] AS [p] ON [b0].[Id] = [p].[BlogId] +ORDER BY [b0].[Name], [b0].[Id] +``` + ### Other query improvements From d2839f4d4fdabfaa539609f23f6e44b8614a5537 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 4 Sep 2025 09:14:35 +0200 Subject: [PATCH 187/224] Add information about parameterized collection padding (#5092) --- .../core/what-is-new/ef-core-10.0/whatsnew.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 8b8bcce103..6b2616447a 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -291,9 +291,19 @@ FROM [Blogs] AS [b] WHERE [b].[Id] IN (@ids1, @ids2, @ids3) ``` -This allows the collection values to change without resulting in different SQLs - solving the plan cache problem - but at the same time provides the query planner with information on the collection cardinality. Since different cardinalities still cause different SQLs to be generated, the final version of EF 10 will include a "bucketization" feature, where e.g. 10 parameters are sent even when the user only specifies 8, to reduce the SQL variations and optimize the query cache. +This allows the collection values to change without resulting in different SQLs - solving the plan cache problem - but at the same time provides the query planner with information on the collection cardinality. -Unfortunately, parameterized collections are a case where EF simply cannot always make the right choice: selecting between multiple parameters (the new default), a single JSON array parameter or multiple inlined constants can require knowledge about the data in your database, and different choices may work better for different queries. As a result, EF exposes full control to the user to control the translation strategy, both at the global configuration level: +Since different cardinalities still cause different SQLs to be generated, EF also "pads" parameter list. For example, if your `ids` list contains 8 values, EF generates SQL with 10 parameters: + +```sql +SELECT [b].[Id], [b].[Name] +FROM [Blogs] AS [b] +WHERE [b].[Id] IN (@ids1, @ids2, @ids3, @ids4, @ids5, @ids6, @ids7, @ids8, @ids9, @ids10) +``` + +The last two parameters `@ids9` and `@ids10` are added by EF to reduce the number of SQLs generated, and contain the same value as `@ids8`, so that the query returns the same result. + +Unfortunately, parameterized collections are a case where EF simply cannot always make the right choice: selecting between multiple parameters (the new default), a single JSON array parameter (with e.g. SQL Server `OPENJSON`) or multiple inlined constants can require knowledge about the data in your database, and different choices may work better for different queries. As a result, EF exposes full control to the user to control the translation strategy, both at the global configuration level: ```c# protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) From 8923440c063ff5f350ac956cb882ea4b15ff6fe7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 4 Sep 2025 17:22:56 +0200 Subject: [PATCH 188/224] Document ExecuteUpdate support for complex JSON (#5094) See https://github.com/dotnet/efcore/issues/28766 --- .../core/what-is-new/ef-core-10.0/whatsnew.md | 84 +++++++++++++++---- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 6b2616447a..55dbbe38ed 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -224,24 +224,6 @@ In previous versions of EF Core, evolving the model when using Azure Cosmos DB w In EF 10 we improved this experience - EF will now materialize a default value for a required property, if no data is present for it in the document, rather than throw. - - -## Named query filters - -EF's [global query filters](xref:core/querying/filters) feature has long enabled users to configuring filters to entity types which apply to all queries by default. This has simplified implementing common patterns and scenarios such as soft deletion, multitenancy and others. However, up to now EF has only supported a single query filter per entity type, making it difficult to have multiple filters and selectively disabling only some of them in specific queries. - -EF 10 introduces *named query filters*, which allow attaching names to query filter and managing each one separately: - -[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#FilterConfiguration)] - -This notably allows disabling only certain filters in a specific LINQ query: - -[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#DisableSoftDeletionFilter)] - -For more information on named query filters, [see the documentation](xref:core/querying/filters). - -This feature was contributed by [@bittola](https://github.com/bittola). - ## LINQ and SQL translation @@ -414,6 +396,72 @@ ORDER BY [b0].[Name], [b0].[Id] - Optimize `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)). - Simplify parameter names (e.g. from `@__city_0` to `@city`) ([#35200](https://github.com/dotnet/efcore/pull/35200)). + + +## ExecuteUpdate support for relational JSON columns + +> [!NOTE] +> ExecuteUpdate support for JSON requires mapping your types as complex types, and does not work when you types are mapped as owned entities. + +Although EF has support JSON columns for some time and allows updating them via `SaveChanges`, `ExecuteUpdate` lacked support for them. EF10 now allows referencing JSON columns and properties within them in `ExecuteUpdate`, allowing efficient bulk updating of document-modeled data within relational databases. + +For example, given the following model, mapping the `BlogDetails` type to a complex JSON column in the database: + +```c# +public class Blog +{ + public int Id { get; set; } + + public BlogDetails Details { get; set; } +} + +public class BlogDetails +{ + public string Title { get; set; } + public int Views { get; set; } +} + +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity().ComplexProperty(b => b.Details, bd => bd.ToJson()); +} +``` + +You can now use `ExecuteUpdate` as usual, referencing properties within `BlogDetails`: + +```c# +await context.Blogs.ExecuteUpdateAsync(s => + s.SetProperty(b => b.Details.Views, b => b.Details.Views + 1)); +``` + +This generates the following for SQL Server 2025, using the efficient, new `modify` function to increment the JSON property `Views` by one: + +```sql +UPDATE [b] +SET [Details].modify('$.Views', JSON_VALUE([b].[Details], '$.Views' RETURNING int) + 1) +FROM [Blogs] AS [b] +``` + +Older versions of SQL Server are also supported, where the JSON data is stored in an `nvarchar(max)` column rather than the new JSON data type support. For support with other databases, consult the documentation for your EF provider. + + + +## Named query filters + +EF's [global query filters](xref:core/querying/filters) feature has long enabled users to configuring filters to entity types which apply to all queries by default. This has simplified implementing common patterns and scenarios such as soft deletion, multitenancy and others. However, up to now EF has only supported a single query filter per entity type, making it difficult to have multiple filters and selectively disabling only some of them in specific queries. + +EF 10 introduces *named query filters*, which allow attaching names to query filter and managing each one separately: + +[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#FilterConfiguration)] + +This notably allows disabling only certain filters in a specific LINQ query: + +[!code-csharp[Main](../../../../samples/core/Querying/QueryFilters/NamedFilters.cs#DisableSoftDeletionFilter)] + +For more information on named query filters, [see the documentation](xref:core/querying/filters). + +This feature was contributed by [@bittola](https://github.com/bittola). + ## ExecuteUpdateAsync now accepts a regular, non-expression lambda The can be used to express arbitrary update operations in the database. In previous versions, the changes to be performed on the database rows were provided via an expression tree parameter; this made it quite difficult to build those changes dynamically. For example, let's assume we want to update a Blog's Views, but conditionally also its Name. Since the setters argument was an expression tree, code such as the following needed to be written: From ac9790bfa76d70f3ced07275c4de27ee827c7b26 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 8 Sep 2025 23:08:29 +0200 Subject: [PATCH 189/224] Additions to SQL Server JSON breaking changes (#5093) --- .../core/what-is-new/ef-core-10.0/breaking-changes.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md index e217d81cf7..070c493be1 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md @@ -76,6 +76,8 @@ CREATE TABLE [Blogs] ( ); ``` +Although the new JSON data type is the recommended way to store JSON data in SQL Server going forward, there may be some behavioral differences when transitioning from `nvarchar(max)`, and some specific querying forms may not be supported. For example, SQL Server does not support the DISTINCT operator over JSON arrays, and queries attempting to do so will fail. + Note that if you have an existing table and are using , upgrading to EF 10 will cause a migration to be generated which alters all existing `nvarchar(max)` JSON columns to `json`. This alter operation is supported and should get applied seamlessly and without any issues, but is a non-trivial change to your database. > [!NOTE] @@ -87,16 +89,18 @@ The new JSON data type introduced by SQL Server is a superior, 1st-class way to #### Mitigations -If you do not wish to transition to the new JSON data type right away, you can configure EF with a compatibility level lower than 170: +If you are targeting Azure SQL Database and do not wish to transition to the new JSON data type right away, you can configure EF with a compatibility level lower than 170: ```c# protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseSqlServer("", o => o.UseCompatibilityLevel(160)); + optionsBuilder.UseAzureSql("", o => o.UseCompatibilityLevel(160)); } ``` -As an alternative, you can explicitly set the column type for your properties to be `nvarchar(max)`: +If you're targeting on-premises SQL Server, the default compatibility level with `UseSqlServer` is currently 150 (SQL Server 2019), so the JSON data type is not used. + +As an alternative, you can explicitly set the column type on specific properties to be `nvarchar(max)`: ```c# public class Blog @@ -109,6 +113,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().PrimitiveCollection(b => b.Tags).HasColumnType("nvarchar(max)"); modelBuilder.Entity().OwnsMany(b => b.Posts, b => b.ToJson().HasColumnType("nvarchar(max)")); + modelBuilder.Entity().ComplexProperty(e => e.Posts, b => b.ToJson()); } ``` From a0aaace6ca15993e6563535bbe5545772c30dca0 Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Wed, 10 Sep 2025 10:33:06 -0700 Subject: [PATCH 190/224] Add a note about ASP.NET Core Identity migrations (#5069) --- .../ef-core-9.0/breaking-changes.md | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index efbd7319dc..44f38c5155 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -66,10 +66,51 @@ There are several common situations when this exception can be thrown: - **Mitigation**: Add a new migration, examine its contents to locate the cause, and replace the dynamic data with a static, hardcoded value in the model. The migration should be recreated after the model is fixed. If dynamic data has to be used for seeding consider using [the new seeding pattern](/ef/core/what-is-new/ef-core-9.0/whatsnew#improved-data-seeding) instead of `HasData()`. - The last migration was created for a different provider than the one used to apply the migrations. - **Mitigation**: This is an unsupported scenario. The warning can be suppressed using the code snippet below, but this scenario will likely stop working in a future EF Core release. The recommended solution is [to generate a separate set of migrations for each provider](xref:core/managing-schemas/migrations/providers). -- The migrations are generated or chosen dynamically by replacing some of the EF services. - - **Mitigation**: The warning is a false positive in this case and should be suppressed: - +- The migrations are generated, modified or chosen dynamically by replacing some of the EF services. + - **Mitigation**: The warning is a false positive in this case and should be suppressed: `options.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning))` +- You are using ASP.NET Core Identity and change options that affect the model, such as: + + ```csharp + .AddDefaultIdentity(options => + { + options.Stores.SchemaVersion = IdentitySchemaVersions.Version2; + options.Stores.MaxLengthForKeys = 256; + options.SignIn.RequireConfirmedAccount = false; + }) + ``` + + - **Mitigation**: To make sure that the options are applied consistently the app needs to be specified as the startup project when running the EF tools or, alternatively, `IDesignTimeDbContextFactory` needs to be implemented in the project containing the `DbContext`: + + ```csharp + public class DatabaseContextDesignTimeFactory : IDesignTimeDbContextFactory + { + public DatabaseContext CreateDbContext(string[] args) + { + var services = new ServiceCollection(); + AddIdentity(services); + var serviceProvider = services.BuildServiceProvider(); + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseApplicationServiceProvider(serviceProvider); + optionsBuilder.UseSqlServer(); + return new DatabaseContext(optionsBuilder.Options); + } + + public static IServiceCollection AddIdentity(IServiceCollection services) + { + services.AddDefaultIdentity(options => + { + options.Stores.SchemaVersion = IdentitySchemaVersions.Version2; + options.Stores.MaxLengthForKeys = 256; + options.SignIn.RequireConfirmedAccount = false; + }) + .AddRoles() + .AddEntityFrameworkStores(); + + return services; + } + } + ``` If your scenario doesn't fall under any of the above cases and adding a new migration creates the same migration each time or an empty migration and the exception is still thrown then create a small repro project and [share it with the EF team in a new issue](https://github.com/dotnet/efcore/issues/new/choose). From bf71bd041cd47c83d462f7d40d65bec76fa84819 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Tue, 9 Sep 2025 20:58:30 +0200 Subject: [PATCH 191/224] What's new notes on complex types Part of #4413 --- .../core/what-is-new/ef-core-10.0/whatsnew.md | 119 +++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index 55dbbe38ed..ed49c11b08 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -17,10 +17,12 @@ EF10 is available as a preview. See [.NET 10 release notes](https://github.com/d EF10 requires the .NET 10 SDK to build and requires the .NET 10 runtime to run. EF10 will not run on earlier .NET versions, and will not run on .NET Framework. - + ## Azure SQL and SQL Server + + ### Vector search support EF 10 brings full support for the recently-introduced [vector data type](/sql/t-sql/data-types/vector-data-type) and its supporting [`VECTOR_DISTANCE()`](/sql/t-sql/functions/vector-distance-transact-sql) function, available on Azure SQL Database and on SQL Server 2025. The vector data type allows storing *embeddings*, which are representation of meaning that can be efficiently searched over for similarity, powering AI workloads such as semantic search and retrieval-augmented generation (RAG). @@ -63,6 +65,8 @@ var topSimilarBlogs = context.Blogs For more information on vector search, [see the documentation](xref:core/providers/sql-server/vector-search). + + ### JSON type support EF 10 also fully supports the new [json data type](/sql/t-sql/data-types/json-data-type), also available on Azure SQL Database and on SQL Server 2025. While SQL Server has included JSON functionality for several versions, the data itself was stored in plain textual columns in the database; the new data type provides significant efficiency improvements and a safer way to store and interact with JSON. @@ -148,6 +152,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) > [!NOTE] > If you have existing migrations, the next migration you add will rename every single default constraint in your model. + + ## Azure Cosmos DB for NoSQL @@ -224,6 +230,117 @@ In previous versions of EF Core, evolving the model when using Azure Cosmos DB w In EF 10 we improved this experience - EF will now materialize a default value for a required property, if no data is present for it in the document, rather than throw. + + +## Complex types + +Complex types are used to model types which are contained within your entity types and have no identity of their own; while entity types are (usually) mapped to a database table, complex types can be mapped to columns in their container table ("table splitting"), or to a single JSON column. Complex types introduce document modeling techniques, which can bring substantial performance benefits as traditional JOINs are avoided, and can make your database modeling much simpler and more natural. + +### Table splitting + +For example, the following maps a customer's addresses as complex types: + +```c# +modelBuilder.Entity(b => +{ + b.ComplexProperty(c => c.ShippingAddress); + b.ComplexProperty(c => c.BillingAddress); +}); +``` + +On relational database, this causes the addresses to be mapped to additional columns in the main `Customers` table: + +```sql +CREATE TABLE [Customers] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(max) NOT NULL, + [BillingAddress_City] nvarchar(max) NOT NULL, + [BillingAddress_PostalCode] nvarchar(max) NOT NULL, + [BillingAddress_Street] nvarchar(max) NOT NULL, + [BillingAddress_StreetNumber] int NOT NULL, + [ShippingAddress_City] nvarchar(max) NOT NULL, + [ShippingAddress_PostalCode] nvarchar(max) NOT NULL, + [ShippingAddress_Street] nvarchar(max) NOT NULL, + [ShippingAddress_StreetNumber] int NOT NULL, + CONSTRAINT [PK_Customers] PRIMARY KEY ([Id]) +); +``` + +Note the difference with the default, traditional relational behavior of mapping the addresses to a separate table and using a foreign key to represent the customer/address relationship. + +While the above was already possible since EF 8, EF 10 adds support for **optional** types: + +```c# +public class Customer +{ + ... + + public Address ShippingAddress { get; set; } + public Address? BillingAddress { get; set; } +} +``` + +Note that optional complex types currently require at least one required property to be defined on the complex type. + +### JSON + +EF 10 now allows mapping complex types to JSON: + +```c# +modelBuilder.Entity(b => +{ + b.ComplexProperty(c => c.ShippingAddress, c => c.ToJson()); + b.ComplexProperty(c => c.BillingAddress, c => c.ToJson()); +}); +``` + +This causes EF to map each Address to a single JSON column in the customer table. When using the new SQL Server 2025 JSON column ([see above](#sql-server-json-type)), this causes the following table to be created: + +```sql +CREATE TABLE [Customers] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(max) NOT NULL, + [ShippingAddress] json NOT NULL, + [BillingAddress] json NOT NULL NULL, + CONSTRAINT [PK_Customers] PRIMARY KEY ([Id]) +); +``` + +Unlike table splitting, JSON mapping allows collections within the mapped type. You can query and update properties inside your JSON documents just like any other non-JSON property, and perform efficient bulk updating on them via `ExecuteUpdateAsync` ([see release note](#execute-update-json)). + +### Struct support + +Complex types also supports mapping .NET structs instead of classes: + +```c# +public struct Address +{ + public required string Street { get; set; } + public required string City { get; set; } + public required string ZipCode { get; set; } +} +``` + +This aligns well with complex types not having an identity of their own, and only being found within entity types which have an identity. However, collections of structs currently aren't currently supported. + +### Complex and owned entity types + +Both table splitting and JSON mapping have been supported before EF 10 via owned entity modeling. However, this modeling created quite a few issues stemming from the fact that owned entity types are entity types, and therefore still operate with reference semantics and an identity behind the scenes. + +For example, trying to assign a customer's billing address to be the same as their shipping address fails with owned entity types, since the same entity type can't be referenced more than once: + +```c# +var customer = await context.Customers.SingleAsync(c => c.Id == someId); +customer.BillingAddress = customer.ShippingAddress; +await context.SaveChangesAsync(); // ERROR +``` + +In contrast, since complex types have value semantics, assigning them simply copies their properties over, as expected. For the same reasons, bulk assignment of owned entity types is not supported, whereas complex types fully support `ExecuteUpdateAsync` in EF 10 ([see release note](#execute-update-json)). + +Similarly, comparing a customer's shipping and billing addresses in LINQ queries does not work as expected, since entity types are compared by their identities; complex types, on the other hand, are compared by their contents, producing the expected result. + +These issues - as well as various others - make complex types the better choice for modeling JSON and table splitting, and users already using owned entity types for these are advised to switch to complex types. + ## LINQ and SQL translation From d44eeb1b0c153847983c9160d6a2cb5def262b48 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Wed, 10 Sep 2025 22:32:19 +0200 Subject: [PATCH 192/224] Tweak DefaultIfEmpty() note in what's new page --- entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index ed49c11b08..b9fd7c765f 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -507,7 +507,11 @@ ORDER BY [b0].[Name], [b0].[Id] #### Bug fixes and optimizations - Fix Microsoft.Data.Sqlite behavior around `DateTime`, `DateTimeOffset` and UTC, [see breaking change notes](xref:core/what-is-new/ef-core-10.0/breaking-changes#DateTimeOffset-read) ([#36195](https://github.com/dotnet/efcore/issues/36195)). -- Fix translation of `DefaultIfEmpty` in various scenarios ([#19095](https://github.com/dotnet/efcore/issues/19095), [#33343](https://github.com/dotnet/efcore/issues/33343), [#36208](https://github.com/dotnet/efcore/issues/36208)). +- Fix translation of `DefaultIfEmpty` in various scenarios: + - [DefaultIfEmpty applied on child collection wipes the parent info in query result](https://github.com/dotnet/efcore/issues/19095) + - [Logic for lifting DefaultIfEmpty out of SelectMany (to LEFT JOIN/OUTER APPLY) is incorrect](https://github.com/dotnet/efcore/issues/33343) + - [NavigationExpandingExpressionVisitor moves Select() behind DefaultIfEmpty()](https://github.com/dotnet/efcore/issues/36208) + - [EF Core 9 no longer applies COALESCE in SQL translation for DefaultIfEmpty() which causing an InvalidOperationException](https://github.com/dotnet/efcore/issues/35950) - Optimize multiple consecutive `LIMIT`s ([#35384](https://github.com/dotnet/efcore/pull/35384), contributed by [@ranma42](https://github.com/ranma42)). - Optimize use of `Count` operation on `ICollection` ([#35381](https://github.com/dotnet/efcore/pull/35381), contributed by [@ChrisJollyAU](https://github.com/ChrisJollyAU)). - Optimize `MIN`/`MAX` over `DISTINCT` ([#34699](https://github.com/dotnet/efcore/pull/34699), contributed by [@ranma42](https://github.com/ranma42)). From d9a80ad7b6dd16ad61cd52a3258047fc097467cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20C=C3=B4t=C3=A9?= <135025320+ma-cote@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:42:41 +0000 Subject: [PATCH 193/224] Fix typo --- entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md index b9fd7c765f..5b84bddb7d 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md @@ -321,7 +321,7 @@ public struct Address } ``` -This aligns well with complex types not having an identity of their own, and only being found within entity types which have an identity. However, collections of structs currently aren't currently supported. +This aligns well with complex types not having an identity of their own, and only being found within entity types which have an identity. However, collections of structs aren't currently supported. ### Complex and owned entity types From b18418476ed76ccc87664915b6c09c6ebe291c25 Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Sun, 14 Sep 2025 16:07:35 +0200 Subject: [PATCH 194/224] Move stale extensions down and update a few version numbers --- entity-framework/core/extensions/index.md | 175 ++++++++++------------ 1 file changed, 79 insertions(+), 96 deletions(-) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index e0377729f8..67e851f28d 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -17,31 +17,31 @@ These tools and extensions provide additional functionality for Entity Framework ### EF Core Power Tools -EF Core Power Tools is a Visual Studio extension that exposes various EF Core design-time tasks in a simple user interface. It includes reverse engineering of DbContext and entity classes from existing databases and [SQL Server DACPACs](/sql/relational-databases/data-tier-applications/data-tier-applications), and model visualizations and diagrams. For EF Core: 6-9. +EF Core Power Tools is a Visual Studio extension that exposes various EF Core design-time tasks in a simple user interface. It includes reverse engineering of DbContext and entity classes from existing databases and [SQL Server DACPACs](/sql/relational-databases/data-tier-applications/data-tier-applications), and model visualizations and diagrams. For EF Core: 8-10. [GitHub wiki](https://github.com/ErikEJ/EFCorePowerTools/wiki) ### EF Core Power Tools CLI -EF Core Power Tools CLI is a .NET global command line tool. It enables advanced reverse engineering of DbContext and entity classes from existing databases and [SQL Server DACPACs](/sql/relational-databases/data-tier-applications/data-tier-applications). For EF Core: 6-9. +EF Core Power Tools CLI is a .NET global command line tool. It enables advanced reverse engineering of DbContext and entity classes from existing databases and [SQL Server DACPACs](/sql/relational-databases/data-tier-applications/data-tier-applications). For EF Core: 8-10. [NuGet](https://www.nuget.org/packages/ErikEJ.EFCorePowerTools.Cli/#readme-body-tab) ### LLBLGen Pro -LLBLGen Pro is an entity modeling solution with support for Entity Framework and Entity Framework Core. It lets you easily define your entity model and map it to your database, using database first or model first, so you can get started writing queries right away. For EF Core: 2-8. +LLBLGen Pro is an entity modeling solution with support for Entity Framework and Entity Framework Core. It lets you easily define your entity model and map it to your database, using database first or model first, so you can get started writing queries right away. For EF Core: 2-9. [Website](https://www.llblgen.com/) ### Devart Entity Developer -Entity Developer is a powerful O/RM designer for ADO.NET Entity Framework, NHibernate, LinqConnect, Telerik Data Access, and LINQ to SQL. It supports designing EF Core models visually, using model first or database first approaches, and C# or Visual Basic code generation. For EF Core: 2-7. +Entity Developer is a powerful O/RM designer for ADO.NET Entity Framework, NHibernate, LinqConnect, Telerik Data Access, and LINQ to SQL. It supports designing EF Core models visually, using model first or database first approaches, and C# or Visual Basic code generation. For EF Core: 2-9. [Website](https://www.devart.com/entitydeveloper/) ### DevMagic EF Core Sidekick -EF Core Sidekick is a Visual Studio extension that enhances the power of auto code generation in Visual Studio. It provides a set of tools and templates for generating EF Core entities and derived DbContext from existing database, and then generating services and REST APIs from the entities. For EF Core: 6-8. +EF Core Sidekick is a Visual Studio extension that enhances the power of auto code generation in Visual Studio. It provides a set of tools and templates for generating EF Core entities and derived DbContext from existing database, and then generating services and REST APIs from the entities. For EF Core: 6-9. [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=devmagic.efsidekick) | [Website](https://www.devmagic.com/) @@ -72,12 +72,6 @@ With Entity Framework Core query plan debugger visualizer, you can view the quer ## Extensions -### Microsoft.EntityFrameworkCore.AutoHistory - -A plugin library that enables automatically recording the data changes performed by EF Core into a history table. For EF Core: 2-6. - -[GitHub repository](https://github.com/Arch/AutoHistory) | [NuGet](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.AutoHistory) - ### EFCoreSecondLevelCacheInterceptor Second level caching is a query cache. The results of EF commands will be stored in the cache, so that the same EF commands will retrieve their data from the cache rather than executing them against the database again. For EF Core: 3-8. @@ -126,12 +120,6 @@ Flexible projection magic for EF Core. Use properties, methods, and extension me [GitHub repository](https://github.com/koenbeuk/EntityFrameworkCore.Projectables) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Projectables) -### EntityFrameworkCore.Triggered - -Triggers for EF Core. Respond to changes in your DbContext before and after they are committed to the database. Triggers are fully asynchronous and support dependency injection, inheritance, cascading and more. For EF Core: 3-6. - -[GitHub repository](https://github.com/koenbeuk/EntityFrameworkCore.Triggered) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Triggered) - ### Entity Framework Plus Extends your DbContext with features such as: Include Filter, Auditing, Caching, Query Future, Batch Delete, Batch Update, and more. For EF Core: 2-9. @@ -146,7 +134,7 @@ Extends your DbContext with high-performance bulk operations: BulkSaveChanges, B ### Expressionify -Add support for calling extension methods in LINQ lambdas. For EF Core: 3-6. +Add support for calling extension methods in LINQ lambdas. For EF Core: 3-9. [GitHub repository](https://github.com/ClaveConsulting/Expressionify) | [NuGet](https://www.nuget.org/packages/Clave.Expressionify) @@ -163,7 +151,7 @@ As a result SQL becomes just "another" class library exposing its API locally, l ### EFCore.NamingConventions -This will automatically make all your table and column names have snake_case, all UPPER or all lower case naming. For EF Core: 3-8. +This will automatically make all your table and column names have snake_case, all UPPER or all lower case naming. For EF Core: 3-9. [GitHub repository](https://github.com/efcore/EFCore.NamingConventions) | [NuGet](https://www.nuget.org/packages/EFCore.NamingConventions) @@ -179,15 +167,6 @@ Adds native support to EntityFrameworkCore for SQL Server for the NodaTime types [GitHub repository](https://github.com/StevenRasmussen/EFCore.SqlServer.NodaTime) | [NuGet](https://www.nuget.org/packages/SimplerSoftware.EntityFrameworkCore.SqlServer.NodaTime) -### EntityFrameworkCore.SqlServer.HierarchyId - -> [!NOTE] -> The SQL Server hierarchyid data type is supported directly within EF Core as of [EF Core 8](/ef/core/what-is-new/ef-core-8.0/whatsnew#hierarchyid-in-net-and-ef-core). - -Adds hierarchyid support to the SQL Server EF Core provider. For EF Core: 3-7. - -[GitHub repository](https://github.com/efcore/EFCore.SqlServer.HierarchyId) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.SqlServer.HierarchyId) - ### linq2db.EntityFrameworkCore Alternative translator of LINQ queries to SQL expressions. For EF Core: 2-8. @@ -196,12 +175,6 @@ Includes support for advanced SQL features such as CTEs, bulk copy, table hints, [GitHub repository](https://github.com/linq2db/linq2db.EntityFrameworkCore) | [NuGet](https://www.nuget.org/packages/linq2db.EntityFrameworkCore) -### EFCore.SoftDelete - -An implementation for soft deleting entities. For EF Core: 3-6. - -[GitHub repository](https://github.com/AshkanAbd/efCoreSoftDeletes) | [NuGet](https://www.nuget.org/packages/EFCore.SoftDelete) - ### EntityFrameworkCore.ConfigurationManager Extends EF Core to resolve connection strings from App.config. For EF Core: 3-9. @@ -216,7 +189,7 @@ A DTO-Entity mapper with composition/aggregation handling (similar to GraphDiff) ### EntityFrameworkCore.Sqlite.NodaTime -Adds support for [NodaTime](https://nodatime.org) types when using [SQLite](https://sqlite.org). For EF Core: 5-8. +Adds support for [NodaTime](https://nodatime.org) types when using [SQLite](https://sqlite.org). For EF Core: 5-9. [GitHub repository](https://github.com/khellang/EFCore.Sqlite.NodaTime) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Sqlite.NodaTime) @@ -232,24 +205,6 @@ Generate DGML (Graph) content that visualizes your DbContext. Adds the AsDgml() [GitHub repository](https://github.com/ErikEJ/EFCorePowerTools/tree/master/src/GUI/ErikEJ.EntityFrameworkCore.DgmlBuilder) | [NuGet](https://www.nuget.org/packages/ErikEJ.EntityFrameworkCore.DgmlBuilder) -### ErikEJ.EntityFrameworkCore.SqlServer.SqlQuery - -> [!NOTE] -> Raw SQL queries against unmapped types is supported directly within EF Core as of [EF Core 8](/ef/core/what-is-new/ef-core-8.0/whatsnew#raw-sql-queries-for-unmapped-types). - -Provides the `SqlQueryAsync` and `SqlQueryValueAsync` methods to help you populate arbitrary classes or a list of primitive types from a raw SQL query. For EF Core: 6-7. - -[GitHub repository](https://github.com/ErikEJ/EFCorePowerTools/tree/master/src/GUI/ErikEJ.EntityFrameworkCore.6.SqlServer.SqlQuery) | [NuGet](https://www.nuget.org/packages/ErikEJ.EntityFrameworkCore.SqlServer.SqlQuery) - -### ErikEJ.EntityFrameworkCore.SqlServer.DateOnlyTimeOnly - -> [!NOTE] -> SQL Server `DateOnly` and `TimeOnly` mapping is supported directly within EF Core as of [EF Core 8](/ef/core/what-is-new/ef-core-8.0/whatsnew#dateonlytimeonly-supported-on-sql-server). - -Use the `DateOnly` and `TimeOnly` .NET types with the EF Core SQL Server provider. For EF Core: 6-7. - -[GitHub repository](https://github.com/ErikEJ/EFCore.SqlServer.DateOnlyTimeOnly) | [NuGet](https://www.nuget.org/packages/ErikEJ.EntityFrameworkCore.SqlServer.DateOnlyTimeOnly) - ### EntityFramework.Exceptions When using Entity Framework Core all database exceptions are wrapped in DbUpdateException. EntityFramework.Exceptions handles all the database-specific details to find which constraint was violated and allows you to use typed exceptions such as `UniqueConstraintException`, `CannotInsertNullException`, `MaxLengthExceededException`, `NumericOverflowException`, `ReferenceConstraintException` when your query violates database constraints. @@ -258,31 +213,12 @@ Supports SQL Server, Postgres, MySql, SQLite and Oracle. For EF Core: 3-8. [GitHub Repository](https://github.com/Giorgi/EntityFramework.Exceptions) -### EntityFrameworkCore.FSharp - -Adds F# design-time support to EF Core. For EF Core: 5-6. - -[GitHub repository](https://github.com/efcore/EFCore.FSharp) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.FSharp) - ### EntityFrameworkCore.VisualBasic Adds VB design-time support to EF Core. For EF Core: 5-8. [GitHub repository](https://github.com/efcore/EFCore.VisualBasic) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.VisualBasic) -### Krzysztofz01.EFCore.QueryFilterBuilder - -Extension for Entity Framework that allows you to create and manage multiple query filters. For EF Core: 5-7. - -[GitHub repository](https://github.com/Krzysztofz01/EFCore.QueryFilterBuilder) - -### Pagination.EntityFrameworkCore.Extensions - -This is a library for Pagination on EntityFrameworkCore. Works well with Entity Framework Core as an extension, and supports both asynchronous and synchronous. -It also has many useful features commonly used especially on web development. For EF Core: 2-7. - -[GitHub repository](https://github.com/SitholeWB/Pagination.EntityFrameworkCore.Extensions) | [NuGet](https://www.nuget.org/packages/Pagination.EntityFrameworkCore.Extensions) - ### Laraue.EfCoreTriggers Fluent API to declare triggers in `Context.OnModelCreating` which are later built into migrations. Providers to Postgres, MySQL, SQL Server and SQLite. For EF Core: 5-8. @@ -301,17 +237,6 @@ Provides window (analytics) functions and binary functions for EF Core. Provider [GitHub repository](https://github.com/zompinc/efcore-extensions) | [NuGet](https://www.nuget.org/packages/Zomp.EFCore.WindowFunctions.SqlServer) -### Ainoraz.EFCore.IncludeBuilder - -Extension for EF Core that provides alternative `Include` syntax in order to better support the following scenarios: - -- Loading multiple entities on the same level (siblings). -- Writing extension methods that are independent of nesting level. - -For EF Core: 6-7. - -[GitHub repository](https://github.com/AinoraZ/EFCore.IncludeBuilder) | [NuGet](https://www.nuget.org/packages/Ainoraz.EFCore.IncludeBuilder/) - ### Entity Framework Ruler Adds design-time customization of the reverse engineered model including: @@ -325,12 +250,6 @@ For EF Core: 6-8. [GitHub repository](https://github.com/R4ND3LL/EntityFrameworkRuler/) | [CLI Tool NuGet](https://www.nuget.org/packages/EntityFrameworkRuler/) | [Design NuGet](https://www.nuget.org/packages/EntityFrameworkRuler.Design/) -### LessCode.EFCore.StronglyTypedId - -A source generator that can generate strongly-typed-id classes automatically for entities. For EF Core: 7. - -[GitHub repository](https://github.com/yangzhongke/LessCode.EFCore.StronglyTypedId) - ### Microsoft.EntityFrameworkCore.DynamicLinq The Dynamic LINQ library let you execute query with dynamic string and provide some utilities methods such as ParseLambda, Parse, and CreateClass. For EF Core: 2-9. @@ -339,9 +258,7 @@ The Dynamic LINQ library let you execute query with dynamic string and provide s ### EfCoreNexus.Framework -EfCoreNexus helps integrating the entity framework core into blazor apps. Via reflection it adds the entity classes automatically and provides you with basic crud functionality for them without writing additional code. - -For EF Core: 8. +EfCoreNexus helps integrating the entity framework core into blazor apps. Via reflection it adds the entity classes automatically and provides you with basic crud functionality for them without writing additional code. For EF Core: 8. [GitHub repository](https://github.com/thliborius/EfCoreNexus) | [NuGet](https://www.nuget.org/packages/EfCoreNexus.Framework/) @@ -363,6 +280,12 @@ A library that provides seamless auditing capabilities for Entity Framework Core [GitHub repository](https://github.com/ShadyNagy/EntityFrameworkCore.AuditInterceptor) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.AuditInterceptor) +### SanderTenBrinke.EntityFrameworkCore.Extensions.SqlServer.DataMasking + +This package focuses on adding data masking support for SQL Server to EF Core. For EF Core: 8-9. + +[GitHub repository](https://github.com/sander1095/EntityFrameworkCore.Extensions.SqlServer.DataMasking) | [NuGet](https://www.nuget.org/packages/SanderTenBrinke.EntityFrameworkCore.Extensions.SqlServer.DataMasking) + ## API Integrations These packages are designed to integrate directly with EF Core to expose various APIs. @@ -397,13 +320,52 @@ A standard for implementing REST APIs with specifications for discovery, filteri [GitHub repository](https://github.com/OData) | [NuGet](https://www.nuget.org/packages/Microsoft.OData.Core/) -### SanderTenBrinke.EntityFrameworkCore.Extensions.SqlServer.DataMasking +## Extensions for unsupported EF Core versions -This package focuses on adding data masking support for SQL Server to EF Core. For EF Core: 8-9. +### EntityFrameworkCore.SqlServer.HierarchyId -[GitHub repository](https://github.com/sander1095/EntityFrameworkCore.Extensions.SqlServer.DataMasking) | [NuGet](https://www.nuget.org/packages/SanderTenBrinke.EntityFrameworkCore.Extensions.SqlServer.DataMasking) +> [!NOTE] +> The SQL Server hierarchyid data type is supported directly within EF Core as of [EF Core 8](/ef/core/what-is-new/ef-core-8.0/whatsnew#hierarchyid-in-net-and-ef-core). -## Extensions for unsupported EF Core versions +Adds hierarchyid support to the SQL Server EF Core provider. For EF Core: 3-7. + +[GitHub repository](https://github.com/efcore/EFCore.SqlServer.HierarchyId) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.SqlServer.HierarchyId) + +### EntityFrameworkCore.FSharp + +Adds F# design-time support to EF Core. For EF Core: 5-6. + +[GitHub repository](https://github.com/efcore/EFCore.FSharp) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.FSharp) + +### EntityFrameworkCore.Triggered + +Triggers for EF Core. Respond to changes in your DbContext before and after they are committed to the database. Triggers are fully asynchronous and support dependency injection, inheritance, cascading and more. For EF Core: 3-6. + +[GitHub repository](https://github.com/koenbeuk/EntityFrameworkCore.Triggered) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Triggered) + +### Microsoft.EntityFrameworkCore.AutoHistory + +A plugin library that enables automatically recording the data changes performed by EF Core into a history table. For EF Core: 2-6. + +[GitHub repository](https://github.com/Arch/AutoHistory) | [NuGet](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.AutoHistory) + +### ErikEJ.EntityFrameworkCore.SqlServer.SqlQuery + +> [!NOTE] +> Raw SQL queries against unmapped types is supported directly within EF Core as of [EF Core 8](/ef/core/what-is-new/ef-core-8.0/whatsnew#raw-sql-queries-for-unmapped-types). + +Provides the `SqlQueryAsync` and `SqlQueryValueAsync` methods to help you populate arbitrary classes or a list of primitive types from a raw SQL query. For EF Core: 6-7. + +[GitHub repository](https://github.com/ErikEJ/EFCorePowerTools/tree/master/src/GUI/ErikEJ.EntityFrameworkCore.6.SqlServer.SqlQuery) | [NuGet](https://www.nuget.org/packages/ErikEJ.EntityFrameworkCore.SqlServer.SqlQuery) + +### ErikEJ.EntityFrameworkCore.SqlServer.DateOnlyTimeOnly + +> [!NOTE] +> SQL Server `DateOnly` and `TimeOnly` mapping is supported directly within EF Core as of [EF Core 8](/ef/core/what-is-new/ef-core-8.0/whatsnew#dateonlytimeonly-supported-on-sql-server). + +Use the `DateOnly` and `TimeOnly` .NET types with the EF Core SQL Server provider. For EF Core: 6-7. + +[GitHub repository](https://github.com/ErikEJ/EFCore.SqlServer.DateOnlyTimeOnly) | [NuGet](https://www.nuget.org/packages/ErikEJ.EntityFrameworkCore.SqlServer.DateOnlyTimeOnly) ### nHydrate ORM for Entity Framework @@ -469,3 +431,24 @@ An extension library for Dynamic Data Masking (SQL Server) and MigrationBuilder An updated fork for the data masking feature can be found at [EntityFrameworkCore.Extensions.SqlServer.DataMasking](https://github.com/sander1095/EntityFrameworkCore.Extensions.SqlServer.DataMasking) [GitHub repository](https://github.com/nikitasavinov/EntityFrameworkCore.Extensions) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Extensions) + +### EFCore.SoftDelete + +An implementation for soft deleting entities. For EF Core: 3-6. + +[GitHub repository](https://github.com/AshkanAbd/efCoreSoftDeletes) | [NuGet](https://www.nuget.org/packages/EFCore.SoftDelete) + +### Ainoraz.EFCore.IncludeBuilder + +Extension for EF Core that provides alternative `Include` syntax in order to better support the following scenarios: + +- Loading multiple entities on the same level (siblings). +- Writing extension methods that are independent of nesting level. + +For EF Core: 6-7. + +### LessCode.EFCore.StronglyTypedId + +A source generator that can generate strongly-typed-id classes automatically for entities. For EF Core: 7. + +[GitHub repository](https://github.com/yangzhongke/LessCode.EFCore.StronglyTypedId) From 2db96c215ff85f2b8805a960d2bb32aa150627bf Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 18 Sep 2025 10:29:11 +0200 Subject: [PATCH 195/224] Point directly to EF10 release notes from TOC --- entity-framework/toc.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index 981f1181ee..12b1bb3055 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -32,10 +32,10 @@ items: - name: Welcome! href: core/index.md - - name: "What's new in EF Core 9.0" - href: core/what-is-new/ef-core-9.0/whatsnew.md - - name: "Breaking changes in EF Core 9.0" - href: core/what-is-new/ef-core-9.0/breaking-changes.md + - name: "What's new in EF Core 10.0" + href: core/what-is-new/ef-core-10.0/whatsnew.md + - name: "Breaking changes in EF Core 10.0" + href: core/what-is-new/ef-core-10.0/breaking-changes.md - name: Getting started items: - name: EF Core Overview @@ -61,7 +61,7 @@ href: core/what-is-new/index.md - name: Release planning process href: core/what-is-new/release-planning.md - - name: EF Core 10.0 + - name: EF Core 10.0 (RC) items: - name: "What's new?" href: core/what-is-new/ef-core-10.0/whatsnew.md From 9d882f842715f42ddac324c431703d9bd6ab9538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Fri, 19 Sep 2025 09:34:55 +0200 Subject: [PATCH 196/224] Add standup (#5109) --- .../core/learn-more/community-standups.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/entity-framework/core/learn-more/community-standups.md b/entity-framework/core/learn-more/community-standups.md index eebf16e727..55a11a5526 100644 --- a/entity-framework/core/learn-more/community-standups.md +++ b/entity-framework/core/learn-more/community-standups.md @@ -16,6 +16,7 @@ The .NET Data Community Standups are live-streamed monthly (roughly) on Wednesda | Date | Area | Title | |--------------|-----------------------|------------------------------------------------------------------------------------------| +| Sep 18, 2025 | ORMs | [Jiri and Nick talk about experience with Dapper and EF Core](#Sep18_2025) | | Aug 21, 2025 | ORMs | [Learning about jOOQ with Lukas Eder](#Aug21_2025) | | Jul 17, 2025 | Couchbase | [Couchbase has an EF Core provider](#Jul17_2025) | | Jun 19, 2025 | Vector databases | [Microsoft.Extensions.VectorData - Access Vector databases in AI apps](#Jun19_2025) | @@ -107,6 +108,25 @@ The .NET Data Community Standups are live-streamed monthly (roughly) on Wednesda ## 2025 + + +### Sep 18: [Jiri and Nick talk about experience with Dapper and EF Core](https://www.youtube.com/live/ppaf8CZjRkI?si=dcJ9vJAaJPJ8thuC) + +Join Jiri and Nick as they share their hands-on experiences working with Dapper and Entity Framework Core in real-world .NET projects. They'll compare the strengths and trade-offs of each approach. Expect practical insights, tips, and honest reflections on when and why to choose one over the other. + +Featuring: + +- [Nick Cosentino](https://www.devleader.ca/) (Special guest) +- [Jiri Cincura](https://www.tabsoverspaces.com/) (Host) + +Links: + +- [Bluesky post](https://bsky.app/profile/devleader.ca/post/3liumptsj7l2b) +- [StronglyTypedId](https://github.com/andrewlock/StronglyTypedId) +- [Dev Leader YouTube Channel](https://www.youtube.com/@devleader) +- [Code Commute YouTube Channel](https://www.youtube.com/@codecommute) +- [All Nick's Links](https://linktr.ee/devleader) + ### Aug 21: [Learning about jOOQ with Lukas Eder](https://www.youtube.com/live/EbFqlYPvAE4?si=O2ifWoBfxNSS5zL9) From 5489d0c6ba01e294705a374706af80b82d55b61e Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 19 Sep 2025 10:50:03 +0200 Subject: [PATCH 197/224] Update EF 9 end-of-support Closes #5107 --- entity-framework/core/what-is-new/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/what-is-new/index.md b/entity-framework/core/what-is-new/index.md index a3aedef25d..cb0ac447bf 100644 --- a/entity-framework/core/what-is-new/index.md +++ b/entity-framework/core/what-is-new/index.md @@ -12,7 +12,7 @@ uid: core/what-is-new/index | Release | Target framework | Supported until | Links | |----------------------------------------------------------------------------------------|-------------------|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [EF Core 9.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) | .NET 8 | May 12, 2026 | [What's new](xref:core/what-is-new/ef-core-9.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-9.0/breaking-changes) | +| [EF Core 9.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) | .NET 8 | November 10, 2026 | [What's new](xref:core/what-is-new/ef-core-9.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-9.0/breaking-changes) | | [EF Core 8.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore) | .NET 8 | November 10, 2026 | [What's new](xref:core/what-is-new/ef-core-8.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-8.0/breaking-changes) | | ~~[EF Core 7.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/7.0.0)~~ | .NET 6 | Expired May 14, 2024 | [What's new](xref:core/what-is-new/ef-core-7.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-7.0/breaking-changes) | | ~~[EF Core 6.0](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/6.0.0)~~ | .NET 6 | Expired November 12, 2024 | [What's new](xref:core/what-is-new/ef-core-6.0/whatsnew) / [Breaking changes](xref:core/what-is-new/ef-core-6.0/breaking-changes) | From c2db05195e4f18c7123c07f2d49a0b40426e8155 Mon Sep 17 00:00:00 2001 From: Jesse Bourke-Spriggs <165753424+jbs-carsales@users.noreply.github.com> Date: Fri, 26 Sep 2025 14:03:01 +1000 Subject: [PATCH 198/224] fix trivial typo --- entity-framework/core/change-tracking/relationship-changes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/change-tracking/relationship-changes.md b/entity-framework/core/change-tracking/relationship-changes.md index 4c24a8e1f2..79ec272452 100644 --- a/entity-framework/core/change-tracking/relationship-changes.md +++ b/entity-framework/core/change-tracking/relationship-changes.md @@ -358,7 +358,7 @@ Post {Id: 4} Unchanged The `Blog.Posts` navigation on the .NET Blog now has three posts (`Posts: [{Id: 1}, {Id: 2}, {Id: 3}]`). Likewise, the `Blog.Posts` navigation on the Visual Studio blog only has one post (`Posts: [{Id: 4}]`). This is to be expected since the code explicitly changed these collections. -More interestingly, even though the code did not explicitly change the `Post.Blog` navigation, it has been fixed-up to point to the Visual Studio blog (`Blog: {Id: 1}`). Also, the `Post.BlogId` foreign key value has been updated to match the primary key value of the .NET blog. This change to the FK value in then persisted to the database when SaveChanges is called: +More interestingly, even though the code did not explicitly change the `Post.Blog` navigation, it has been fixed-up to point to the Visual Studio blog (`Blog: {Id: 1}`). Also, the `Post.BlogId` foreign key value has been updated to match the primary key value of the .NET blog. This change to the FK value is then persisted to the database when SaveChanges is called: ```sql -- Executed DbCommand (0ms) [Parameters=[@p1='3' (DbType = String), @p0='1' (Nullable = true) (DbType = String)], CommandType='Text', CommandTimeout='30'] From 0ae6eac29e30fca2c9096ce6d70cd34c4959dcd2 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 30 Sep 2025 10:53:08 -0700 Subject: [PATCH 199/224] Document breaking changes for complex types in EF Core 10.0 (#5113) Column name uniquification Nested complex type column naming IDiscriminatorPropertySetConvention signature change Value converters with private methods in compiled models Fixes #4970 Fixes #4947 Fixes https://github.com/dotnet/efcore/issues/35033 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../advanced-performance-topics.md | 1 + .../ef-core-10.0/breaking-changes.md | 90 +++++++++++++++++++ .../ef-core-9.0/breaking-changes.md | 36 ++++++++ 3 files changed, 127 insertions(+) diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index bcd662ae1f..c39b4bfe67 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -295,6 +295,7 @@ Compiled models have some limitations: * [Global query filters are not supported](https://github.com/dotnet/efcore/issues/24897). * [Lazy loading and change-tracking proxies are not supported](https://github.com/dotnet/efcore/issues/24902). +* Value converters that reference private methods are not supported. Make referenced methods public or internal instead. * [The model must be manually synchronized by regenerating it any time the model definition or configuration change](https://github.com/dotnet/efcore/issues/24894). * Custom IModelCacheKeyFactory implementations are not supported. However, you can compile multiple models and load the appropriate one as needed. diff --git a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md index 070c493be1..5f3f2292d6 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md @@ -24,6 +24,9 @@ This page documents API and behavior changes that have the potential to break ex |:--------------------------------------------------------------------------------------------------------------- | -----------| | [SQL Server json data type used by default on Azure SQL and compatibility level 170](#sqlserver-json-data-type) | Low | | [ExecuteUpdateAsync now accepts a regular, non-expression lambda](#ExecuteUpdateAsync-lambda) | Low | +| [Complex type column names are now uniquified](#complex-type-column-uniquification) | Low | +| [Nested complex type properties use full path in column names](#nested-complex-type-column-names) | Low | +| [IDiscriminatorPropertySetConvention signature changed](#discriminator-convention-signature) | Low | ## Low-impact changes @@ -178,6 +181,93 @@ await context.Blogs.ExecuteUpdateAsync(s => }); ``` + + +### Complex type column names are now uniquified + +[Tracking Issue #4970](https://github.com/dotnet/EntityFramework.Docs/issues/4970) + +#### Old behavior + +Previously, when mapping complex types to table columns, if multiple properties in different complex types had the same column name, they would silently share the same column. + +#### New behavior + +Starting with EF Core 10.0, complex type column names are uniquified by appending a number at the end if another column with the same name exists on the table. + +#### Why + +This prevents data corruption that could occur when multiple properties are unintentionally mapped to the same column. + +#### Mitigations + +If you need multiple properties to share the same column, configure them explicitly: + +```c# +modelBuilder.Entity(b => +{ + b.ComplexProperty(c => c.ShippingAddress, p => p.Property(a => a.Street).HasColumnName("Street")); + b.ComplexProperty(c => c.BillingAddress, p => p.Property(a => a.Street).HasColumnName("Street")); +}); +``` + + + +### Nested complex type properties use full path in column names + +#### Old behavior + +Previously, properties on nested complex types were mapped to columns using just the declaring type name. For example, `EntityType.Complex.NestedComplex.Property` was mapped to column `NestedComplex_Property`. + +#### New behavior + +Starting with EF Core 10.0, properties on nested complex types use the full path to the property as part of the column name. For example, `EntityType.Complex.NestedComplex.Property` is now mapped to column `Complex_NestedComplex_Property`. + +#### Why + +This provides better column name uniqueness and makes it clearer which property maps to which column. + +#### Mitigations + +If you need to maintain the old column names, configure them explicitly: + +```c# +modelBuilder.Entity() + .ComplexProperty(e => e.Complex) + .ComplexProperty(o => o.NestedComplex) + .Property(c => c.Property) + .HasColumnName("NestedComplex_Property"); +``` + + + +### IDiscriminatorPropertySetConvention signature changed + +#### Old behavior + +Previously, `IDiscriminatorPropertySetConvention.ProcessDiscriminatorPropertySet` took `IConventionEntityTypeBuilder` as a parameter. + +#### New behavior + +Starting with EF Core 10.0, the method signature changed to take `IConventionTypeBaseBuilder` instead of `IConventionEntityTypeBuilder`. + +#### Why + +This change allows the convention to work with both entity types and complex types. + +#### Mitigations + +Update your custom convention implementations to use the new signature: + +```c# +public virtual void ProcessDiscriminatorPropertySet( + IConventionTypeBaseBuilder typeBaseBuilder, // Changed from IConventionEntityTypeBuilder + string name, + Type type, + MemberInfo memberInfo, + IConventionContext context) +``` + ## Microsoft.Data.Sqlite breaking changes diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index 44f38c5155..459cea6c47 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -29,6 +29,7 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET | [Exception is thrown when applying migrations in an explicit transaction](#migrations-transaction) | High | | [`Microsoft.EntityFrameworkCore.Design` not found when using EF tools](#tools-design) | Medium | | [`EF.Functions.Unhex()` now returns `byte[]?`](#unhex) | Low | +| [Compiled models now reference value converter methods directly](#compiled-model-private-methods) | Low | | [SqlFunctionExpression's nullability arguments' arity validated](#sqlfunctionexpression-nullability) | Low | | [`ToString()` method now returns empty string for `null` instances](#nullable-tostring) | Low | | [Shared framework dependencies were updated to 9.0.x](#shared-framework-dependencies) | Low | @@ -228,6 +229,41 @@ var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString) Otherwise, add runtime checks for null on the return value of Unhex(). + + +### Compiled models now reference value converter methods directly + +[Tracking Issue #35033](https://github.com/dotnet/efcore/issues/35033) + +#### Old behavior + +Previously, when using value converters with compiled models (using `dotnet ef dbcontext optimize`), EF would reference the converter type and everything worked correctly. + +```c# +public sealed class BooleanToCharConverter() : ValueConverter(v => ConvertToChar(v), v => ConvertToBoolean(v)) +{ + public static readonly BooleanToCharConverter Default = new(); + + private static char ConvertToChar(bool value) // Private method + => value ? 'Y' : 'N'; + + private static bool ConvertToBoolean(char value) // Private method + => value == 'Y'; +} +``` + +#### New behavior + +Starting with EF Core 9.0, EF generates code that directly references the conversion methods themselves. If these methods are private, compilation will fail. + +#### Why + +This change was necessary to support NativeAOT. + +#### Mitigations + +Make the methods referenced by value converters public or internal instead of private. + ### SqlFunctionExpression's nullability arguments' arity validated From d0cd799af2bb7f933bf5161ea2a95be2bf1cd52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabien=20M=C3=A9nager?= Date: Wed, 1 Oct 2025 03:32:16 +0200 Subject: [PATCH 200/224] Add PhenX.EntityFrameworkCore.BulkInsert to the tools (#5088) --- entity-framework/core/extensions/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index 67e851f28d..ed328ca1c1 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -280,6 +280,12 @@ A library that provides seamless auditing capabilities for Entity Framework Core [GitHub repository](https://github.com/ShadyNagy/EntityFrameworkCore.AuditInterceptor) | [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.AuditInterceptor) +### PhenX.EntityFrameworkCore.BulkInsert + +A high-performance bulk insert extension for Entity Framework Core. Supports SQL Server, PostgreSQL, SQLite, MySQL and Oracle. For EF Core: 8-9. + +[Website](https://phenx.github.io/PhenX.EntityFrameworkCore.BulkInsert/) | [GitHub repository](https://github.com/PhenX/PhenX.EntityFrameworkCore.BulkInsert) + ### SanderTenBrinke.EntityFrameworkCore.Extensions.SqlServer.DataMasking This package focuses on adding data masking support for SQL Server to EF Core. For EF Core: 8-9. From d6d3d0838b7604491919ff4a8fa0e4767171876f Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:30:31 -0700 Subject: [PATCH 201/224] Remove IWAPI section from extensions (#5121) Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- entity-framework/core/extensions/index.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/entity-framework/core/extensions/index.md b/entity-framework/core/extensions/index.md index ed328ca1c1..ade19ddabe 100644 --- a/entity-framework/core/extensions/index.md +++ b/entity-framework/core/extensions/index.md @@ -2,7 +2,7 @@ title: Tools & Extensions - EF Core description: External tools and extensions for Entity Framework Core author: ErikEJ -ms.date: 05/22/2024 +ms.date: 09/30/2025 uid: core/extensions/index --- @@ -52,12 +52,6 @@ Entity Framework Visual Editor is a Visual Studio extension that adds an O/RM de [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner2022) -### IWAPI - -IWAPI (Instant Web API) is a scaffolding engine for .NET Core that can automate the generation of DbContext classes, entities, models and creates a working Web API from any SQL Server database. - -[Website](https://instantwebapi.com/) - ### efmig efmig is a multi-platform GUI application that speeds up daily development when working with Entity Framework Core. It covers the most popular use cases such as migration code and script generation with simple, one-click interface. For EF Core: 2-8. From f000667fb492e2ddd85ba6474b48be897b762b2a Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Wed, 1 Oct 2025 19:15:23 +0200 Subject: [PATCH 202/224] Release note updates for 10.0.0-rc.2 And add security section --- .../extensions-logging.md | 14 ---- .../core/what-is-new/ef-core-10.0/whatsnew.md | 75 +++++++++++++++++-- .../core/what-is-new/ef-core-8.0/whatsnew.md | 2 +- .../core/what-is-new/ef-core-9.0/whatsnew.md | 2 +- 4 files changed, 69 insertions(+), 24 deletions(-) diff --git a/entity-framework/core/logging-events-diagnostics/extensions-logging.md b/entity-framework/core/logging-events-diagnostics/extensions-logging.md index 86cbb334a7..c18ebea30a 100644 --- a/entity-framework/core/logging-events-diagnostics/extensions-logging.md +++ b/entity-framework/core/logging-events-diagnostics/extensions-logging.md @@ -24,26 +24,12 @@ Other application types can use the [GenericHost](/dotnet/core/extensions/generi `Microsoft.Extensions.Logging` requires creation of a . This factory should be stored as a static/global instance somewhere and used each time a DbContext is created. For example, it is common to store the logger factory as a static property on the DbContext. -### [EF Core 3.0 and above](#tab/v3) - [!code-csharp[Main](../../../samples/core/Miscellaneous/Logging/Logging/BloggingContext.cs#DefineLoggerFactory)] -### [EF Core 2.1](#tab/v2) - -```csharp -public static readonly LoggerFactory MyLoggerFactory - = new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) }); -``` - -> [!WARNING] -> In EF Core 2.1, It is very important that applications do not create a new LoggerFactory instance for each DbContext instance. Doing so will result in a memory leak and poor performance. This has been fixed in EF Core 3.0 and above. - -*** - This singleton/global instance should then be registered with EF Core on the . For example: @@ -34,19 +34,32 @@ The following is a list of the design-time services. Service | Description ------------------------------------------------------------------------------------ | ----------- | Generates the code for corresponding model annotations. + | Generates candidate names for entities and properties. | Helps with generating C# code. + | Generates C# code for migration operations. + | Generates C# code for model snapshots. + | C# code generation utilities. | Pluralizes and singularizes words. | Generates code for a migration. + | Selects the appropriate migrations code generator. | The main class for managing migration files. + | Generates code for compiled model metadata. + | Selects the appropriate compiled model code generator. + | The main class for scaffolding compiled models. | Creates a database model from a database. | Generates code for a model. + | Selects the appropriate model code generator. | Generates OnConfiguring code. | The main class for scaffolding reverse engineered models. | Creates a model from a database model. + | Maps database types to .NET types during scaffolding. + | Processes model snapshots. + | Generates code for precompiled queries. + | Selects the appropriate precompiled query code generator. ## Using services -These services can also be useful for creating your own tools. For example, when you want to automate part of you design-time workflow. +These services can also be useful for creating your own tools. For example, when you want to automate part of your design-time workflow. You can build a service provider containing these services using the AddEntityFrameworkDesignTimeServices and AddDbContextDesignTimeServices extension methods. diff --git a/entity-framework/core/miscellaneous/internals/tools.md b/entity-framework/core/miscellaneous/internals/tools.md index 92b213790d..56b7dc40b0 100644 --- a/entity-framework/core/miscellaneous/internals/tools.md +++ b/entity-framework/core/miscellaneous/internals/tools.md @@ -114,7 +114,7 @@ In a nutshell, here are some of the strategies it uses. ### Design-time services -In addition to the application services and the internal DbContext services, there is a third set of [design-time services](xref:core/cli/services). These aren't added to internal service provider since they're never needed at runtime. The design-time services are built by [DesignTimeServicesBuilder](https://github.com/dotnet/efcore/blob/main/src/EFCore.Design/Design/Internal/DesignTimeServicesBuilder.cs). There are two main path--one with a context instance and one without. The one without is primarily used when scaffolding a new DbContext. There are several extensibility points here to allow the user, providers, and extensions to override and customize the services. +In addition to the application services and the internal DbContext services, there is a third set of [design-time services](xref:core/cli/services). These aren't added to internal service provider since they're never needed at runtime. The design-time services are built by [DesignTimeServicesBuilder](https://github.com/dotnet/efcore/blob/main/src/EFCore.Design/Design/Internal/DesignTimeServicesBuilder.cs). There are two main paths--one with a context instance and one without. The one without is primarily used when scaffolding a new DbContext. There are several extensibility points here to allow the user, providers, and extensions to override and customize the services. The user can customize services by adding an implementation of `IDesignTimeServices` to the startup assembly. diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index c39b4bfe67..7390a3bb8e 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -303,6 +303,10 @@ Because of these limitations, you should only use compiled models if your EF Cor If supporting any of these features is critical to your success, then please vote for the appropriate issues linked above. +### Handling compilation errors due to ambiguous type references + +When compiling models with types that have the same name but exist in different namespaces, the generated code may produce compilation errors due to ambiguous type references. To resolve this, you can customize the code generation to use fully-qualified type names by overriding `CSharpHelper.ShouldUseFullName` to return `true`. See [Design-time services](xref:core/cli/services) for information on how to override design-time services like `ICSharpHelper`. + ## Reducing runtime overhead As with any layer, EF Core adds a bit of runtime overhead compared to coding directly against lower-level database APIs. This runtime overhead is unlikely to impact most real-world applications in a significant way; the other topics in this performance guide, such as query efficiency, index usage and minimizing roundtrips, are far more important. In addition, even for highly-optimized applications, network latency and database I/O will usually dominate any time spent inside EF Core itself. However, for high-performance, low-latency applications where every bit of perf is important, the following recommendations can be used to reduce EF Core overhead to a minimum: diff --git a/samples/core/Miscellaneous/CommandLine/CustomTools.cs b/samples/core/Miscellaneous/CommandLine/CustomTools.cs index d4e20448a1..8450b1c463 100644 --- a/samples/core/Miscellaneous/CommandLine/CustomTools.cs +++ b/samples/core/Miscellaneous/CommandLine/CustomTools.cs @@ -1,7 +1,11 @@ -using System.IO; +using System; +using System.IO; +using System.Reflection; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations.Design; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; namespace CommandLine; @@ -12,19 +16,27 @@ public static void AddMigration(string migrationName) { var projectDir = Directory.GetCurrentDirectory(); var rootNamespace = "ConsoleApp1"; - var outputDir = "Migraitons"; + var outputDir = "Migrations"; #region CustomTools - var db = new MyDbContext(); + using var db = new MyDbContext(); // Create design-time services var serviceCollection = new ServiceCollection(); - serviceCollection.AddEntityFrameworkDesignTimeServices(); serviceCollection.AddDbContextDesignTimeServices(db); + + var provider = db.GetService().Name; + var providerAssembly = Assembly.Load(new AssemblyName(provider)); + var providerServicesAttribute = providerAssembly.GetCustomAttribute(); + var designTimeServicesType = providerAssembly.GetType(providerServicesAttribute.TypeName, throwOnError: true); + ((IDesignTimeServices)Activator.CreateInstance(designTimeServicesType)!).ConfigureDesignTimeServices(serviceCollection); + + serviceCollection.AddEntityFrameworkDesignTimeServices(); + var serviceProvider = serviceCollection.BuildServiceProvider(); // Add a migration - var migrationsScaffolder = serviceProvider.GetService(); + var migrationsScaffolder = serviceProvider.GetRequiredService(); var migration = migrationsScaffolder.ScaffoldMigration(migrationName, rootNamespace); migrationsScaffolder.Save(projectDir, migration, outputDir); #endregion @@ -33,4 +45,16 @@ public static void AddMigration(string migrationName) internal class MyDbContext : DbContext { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseSqlite(@"Data Source=test.db"); + } + + public DbSet Blogs { get; set; } +} + +internal class Blog +{ + public int Id { get; set; } + public string Title { get; set; } } \ No newline at end of file From b3ecb10c6f4b7a6d7fc4f1c148bdd9d58046253d Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Oct 2025 13:52:56 -0700 Subject: [PATCH 204/224] Document Cosmos trigger execution support (#5114) Fixes #5080 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- .../core/providers/cosmos/modeling.md | 24 +++++- samples/core/Cosmos/Cosmos.csproj | 4 +- .../Cosmos/ModelBuilding/TriggerSample.cs | 73 +++++++++++++++++++ samples/global.json | 5 ++ 4 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 samples/core/Cosmos/ModelBuilding/TriggerSample.cs create mode 100644 samples/global.json diff --git a/entity-framework/core/providers/cosmos/modeling.md b/entity-framework/core/providers/cosmos/modeling.md index 2ceebf6728..119775be25 100644 --- a/entity-framework/core/providers/cosmos/modeling.md +++ b/entity-framework/core/providers/cosmos/modeling.md @@ -2,7 +2,7 @@ title: Modeling - Azure Cosmos DB Provider - EF Core description: Configuring the model with the Azure Cosmos DB EF Core Provider author: roji -ms.date: 09/19/2024 +ms.date: 09/26/2024 uid: core/providers/cosmos/modeling --- # Configuring the model with the EF Core Azure Cosmos DB Provider @@ -334,3 +334,25 @@ To configure an entity type to use [optimistic concurrency](xref:core/saving/con To make it easier to resolve concurrency errors you can map the eTag to a CLR property using . [!code-csharp[Main](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=ETagProperty)] + +## Database triggers + +> [!NOTE] +> Database trigger execution support was introduced in EF Core 10.0. + +Azure Cosmos DB supports pre- and post-triggers that run before or after database operations. EF Core can be configured to execute these triggers when performing save operations. + +> [!IMPORTANT] +> Triggers are executed server-side by Azure Cosmos DB when EF Core performs operations, but they are not enforced - operations can be performed without running triggers if accessing the database directly. This means triggers should not be used for security-related functionality such as authentication or auditing, as they can be bypassed by applications that access the database directly without using EF Core. + +To configure triggers on an entity type, use the `HasTrigger` method: + +[!code-csharp[TriggerConfiguration](../../../../samples/core/Cosmos/ModelBuilding/TriggerSample.cs?name=TriggerConfiguration)] + +The `HasTrigger` method requires: + +* **modelName**: The name of the trigger in Azure Cosmos DB +* **triggerType**: Either `TriggerType.Pre` (executed before the operation) or `TriggerType.Post` (executed after the operation) +* **triggerOperation**: The operation that should execute the trigger - `Create`, `Replace`, `Delete`, or `All` + +Before triggers can be executed, they must be created in Azure Cosmos DB using the Cosmos SDK or Azure portal. The trigger name configured in EF Core must match the trigger name in Azure Cosmos DB. diff --git a/samples/core/Cosmos/Cosmos.csproj b/samples/core/Cosmos/Cosmos.csproj index 8539b9f9df..7ba28aaa96 100644 --- a/samples/core/Cosmos/Cosmos.csproj +++ b/samples/core/Cosmos/Cosmos.csproj @@ -2,11 +2,11 @@ Exe - net8.0 + net10.0 - + diff --git a/samples/core/Cosmos/ModelBuilding/TriggerSample.cs b/samples/core/Cosmos/ModelBuilding/TriggerSample.cs new file mode 100644 index 0000000000..68a75e5ae9 --- /dev/null +++ b/samples/core/Cosmos/ModelBuilding/TriggerSample.cs @@ -0,0 +1,73 @@ +using Microsoft.Azure.Cosmos.Scripts; +using Microsoft.EntityFrameworkCore; +using System.Threading.Tasks; + +namespace Cosmos.ModelBuilding; + +public static class TriggerSample +{ + public static async Task ConfigureTriggers() + { + var contextOptions = new DbContextOptionsBuilder() + .UseCosmos("https://localhost:8081/", "account-key", "sample"); + + using var context = new TriggerContext(contextOptions.Options); + + // Ensure database is created + await context.Database.EnsureCreatedAsync(); + + // Create a new product - this will trigger the PreInsertTrigger + var product = new Product + { + Id = 1, + Name = "Sample Product", + Price = 19.99m, + Category = "Electronics" + }; + + context.Products.Add(product); + await context.SaveChangesAsync(); + + // Update the product - this will trigger the UpdateTrigger + product.Price = 24.99m; + await context.SaveChangesAsync(); + + // Delete the product - this will trigger the PostDeleteTrigger + context.Products.Remove(product); + await context.SaveChangesAsync(); + } +} + +public class TriggerContext : DbContext +{ + public TriggerContext(DbContextOptions options) : base(options) { } + + public DbSet Products { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasPartitionKey(p => p.Category); + + #region TriggerConfiguration + // Configure pre-trigger for create operations + entity.HasTrigger("PreInsertTrigger", TriggerType.Pre, TriggerOperation.Create); + + // Configure post-trigger for delete operations + entity.HasTrigger("PostDeleteTrigger", TriggerType.Post, TriggerOperation.Delete); + + // Configure trigger for replace operations + entity.HasTrigger("UpdateTrigger", TriggerType.Pre, TriggerOperation.Replace); + #endregion + }); + } +} + +public class Product +{ + public int Id { get; set; } + public string Name { get; set; } = null!; + public decimal Price { get; set; } + public string Category { get; set; } = null!; +} \ No newline at end of file diff --git a/samples/global.json b/samples/global.json new file mode 100644 index 0000000000..be4942c34f --- /dev/null +++ b/samples/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "10.0.100-rc.1.25451.107" + } +} \ No newline at end of file From 45aece5b29fb9af718a282977d75b1c8ab1e31e1 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:44:43 -0700 Subject: [PATCH 205/224] Fix cross-reference warnings in entity-framework/core/cli/services.md (#5123) Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> --- entity-framework/core/cli/services.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/entity-framework/core/cli/services.md b/entity-framework/core/cli/services.md index 73926d4e7b..dbb3b66be0 100644 --- a/entity-framework/core/cli/services.md +++ b/entity-framework/core/cli/services.md @@ -34,12 +34,10 @@ The following is a list of the design-time services. Service | Description ------------------------------------------------------------------------------------ | ----------- | Generates the code for corresponding model annotations. - | Generates candidate names for entities and properties. | Helps with generating C# code. - | Generates C# code for migration operations. - | Generates C# code for model snapshots. - | C# code generation utilities. | Pluralizes and singularizes words. + | Generates C# code for migration operations. + | Generates C# code for model snapshots. | Generates code for a migration. | Selects the appropriate migrations code generator. | The main class for managing migration files. @@ -52,8 +50,6 @@ Service | Generates OnConfiguring code. | The main class for scaffolding reverse engineered models. | Creates a model from a database model. - | Maps database types to .NET types during scaffolding. - | Processes model snapshots. | Generates code for precompiled queries. | Selects the appropriate precompiled query code generator. From 20408569fcd66af4bf3a9bb5f094cb36f547a570 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 9 Oct 2025 13:24:22 +0200 Subject: [PATCH 206/224] Add breaking change note about SQL Server application name Related to #35730 --- .../ef-core-10.0/breaking-changes.md | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md index 5f3f2292d6..d4b2d07d17 100644 --- a/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-10.0/breaking-changes.md @@ -1,8 +1,8 @@ --- title: Breaking changes in EF Core 10 (EF10) - EF Core description: List of breaking changes introduced in Entity Framework Core 10 (EF10) -author: maumar -ms.date: 01/05/2025 +author: roji +ms.date: 10/09/2025 uid: core/what-is-new/ef-core-10.0/breaking-changes --- @@ -22,6 +22,7 @@ This page documents API and behavior changes that have the potential to break ex | **Breaking change** | **Impact** | |:--------------------------------------------------------------------------------------------------------------- | -----------| +| [Application Name is now injected into the connection string](#sqlserver-application-name) | Low | | [SQL Server json data type used by default on Azure SQL and compatibility level 170](#sqlserver-json-data-type) | Low | | [ExecuteUpdateAsync now accepts a regular, non-expression lambda](#ExecuteUpdateAsync-lambda) | Low | | [Complex type column names are now uniquified](#complex-type-column-uniquification) | Low | @@ -30,6 +31,20 @@ This page documents API and behavior changes that have the potential to break ex ## Low-impact changes + + +### Application Name is now injected into the connection string + +[Tracking Issue #35730](https://github.com/dotnet/efcore/issues/35730) + +#### New behavior + +When a connection string without an `Application Name` is passed to EF, EF now inserts an `Application Name` containing anonymous information about the EF and SqlClient versions being used. In the vast majority of cases, this doesn't impact the application in any way, but can affect behavior in some edge cases. For example, if you connect to the same database with both EF and another non-EF data access technology (e.g. Dapper, ADO.NET), SqlClient will use a different internal connection pool, as EF will now use a different, updated connection string (one where `Application Name` has been injected). If this sort of mixed access is done within a `TransactionScope`, this can cause escalation to a distributed transaction where previously none was necessary, due of the usage of two connection strings which SqlClient identifies as two distinct databases. + +#### Mitigations + +A mitigation is to simply define an `Application Name` in your connection string. Once one is defined, EF does not overwrite it and the original connection string is preserved exactly as-is. + ### SQL Server json data type used by default on Azure SQL and compatibility level 170 @@ -83,9 +98,6 @@ Although the new JSON data type is the recommended way to store JSON data in SQL Note that if you have an existing table and are using , upgrading to EF 10 will cause a migration to be generated which alters all existing `nvarchar(max)` JSON columns to `json`. This alter operation is supported and should get applied seamlessly and without any issues, but is a non-trivial change to your database. -> [!NOTE] -> For 10.0.0 rc1, support for the new JSON data type has been temporarily disabled for Azure SQL Database, due to lacking support. These issues are expected to be resolved by the time EF 10.0 is released, and the JSON data type will become the default until then. - #### Why The new JSON data type introduced by SQL Server is a superior, 1st-class way to store and interact with JSON data in the database; it notably brings significant performance improvements ([see documentation](/sql/t-sql/data-types/json-data-type)). All applications using Azure SQL Database or SQL Server 2025 are encouraged to migrate to the new JSON data type. From a641bb82f888cf02f31f4bd0eaaa316aa27bdf88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Fri, 17 Oct 2025 10:00:14 +0200 Subject: [PATCH 207/224] Add standup (#5127) --- .../core/learn-more/community-standups.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/entity-framework/core/learn-more/community-standups.md b/entity-framework/core/learn-more/community-standups.md index 55a11a5526..a99e165e01 100644 --- a/entity-framework/core/learn-more/community-standups.md +++ b/entity-framework/core/learn-more/community-standups.md @@ -16,6 +16,7 @@ The .NET Data Community Standups are live-streamed monthly (roughly) on Wednesda | Date | Area | Title | |--------------|-----------------------|------------------------------------------------------------------------------------------| +| Oct 16, 2025 | Migrations | [Jeremy Miller shares his view on migrations and Marten](#Oct16_2025) | | Sep 18, 2025 | ORMs | [Jiri and Nick talk about experience with Dapper and EF Core](#Sep18_2025) | | Aug 21, 2025 | ORMs | [Learning about jOOQ with Lukas Eder](#Aug21_2025) | | Jul 17, 2025 | Couchbase | [Couchbase has an EF Core provider](#Jul17_2025) | @@ -108,6 +109,25 @@ The .NET Data Community Standups are live-streamed monthly (roughly) on Wednesda ## 2025 + + +### Oct 16: [Jeremy Miller shares his view on migrations and Marten](https://www.youtube.com/live/_ICoF0utyt4?si=Mrcy0WbQ8f74dOXE) + +Join the .NET Data Community team as we welcome Jeremy Miller, developer of Marten, to share his insights on database migrations and the evolving capabilities of Marten. + +Featuring: + +- [Jeremy Miller](https://jeremydmiller.com/) (Special guest) +- [Jiri Cincura](https://www.tabsoverspaces.com/) (Host) + +Links: + +- [Bluesky post](https://bsky.app/profile/jeremydmiller.bsky.social/post/3lp7m2renvk2u) +- [Marten](https://martendb.io/) +- [Wolverine](https://wolverinefx.io/) +- [JasperFX](https://jasperfx.net/) +- [Sable](https://bloomberg.github.io/sable/) + ### Sep 18: [Jiri and Nick talk about experience with Dapper and EF Core](https://www.youtube.com/live/ppaf8CZjRkI?si=dcJ9vJAaJPJ8thuC) From b812190901548b52f15384780535f69ea137efd3 Mon Sep 17 00:00:00 2001 From: Maksym Konotop <43847461+kanilsz@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:23:55 +0300 Subject: [PATCH 208/224] Duplication in conventions for relationship discovery (#4980) (#5130) Co-authored-by: Shay Rojansky --- entity-framework/core/modeling/relationships/conventions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/modeling/relationships/conventions.md b/entity-framework/core/modeling/relationships/conventions.md index 5005c9b16a..836c5a61d9 100644 --- a/entity-framework/core/modeling/relationships/conventions.md +++ b/entity-framework/core/modeling/relationships/conventions.md @@ -118,7 +118,7 @@ The type of relationship is determined by whether the navigation and its inverse Discovery of each of these types of relationship is shown in the examples below: -A single, one-to-many relationship is discovered between `Blog` and `Post` is discovered by pairing the `Blog.Posts` and `Post.Blog` navigations: +A single, one-to-many relationship between `Blog` and `Post` is discovered by pairing the `Blog.Posts` and `Post.Blog` navigations: + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + From 468736588c95967fb42b59f0270e11163cbb5225 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:07:57 -0700 Subject: [PATCH 216/224] Update notification subscribers in config file (#5139) --- .openpublishing.publish.config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.openpublishing.publish.config.json b/.openpublishing.publish.config.json index a8d18bd616..373c9d7588 100644 --- a/.openpublishing.publish.config.json +++ b/.openpublishing.publish.config.json @@ -23,7 +23,7 @@ ], "notification_subscribers": [ "sampatel@microsoft.com", - "riande@microsoft.com" + "jiricincura@microsoft.com" ], "sync_notification_subscribers": [], "branches_to_filter": [], @@ -64,4 +64,4 @@ "need_generate_pdf_url_template": true, "contribution_branch_mappings": {}, "need_generate_intellisense": false -} \ No newline at end of file +} From 106326dc341e0cde1aa6607f708222e657151344 Mon Sep 17 00:00:00 2001 From: cincuranet <4540597+cincuranet@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:24:30 +0000 Subject: [PATCH 217/224] Initialize Docs repository: https://github.com/dotnet/EntityFramework.Docs of branch live --- .openpublishing.publish.config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.openpublishing.publish.config.json b/.openpublishing.publish.config.json index 373c9d7588..4ccab6704b 100644 --- a/.openpublishing.publish.config.json +++ b/.openpublishing.publish.config.json @@ -27,7 +27,7 @@ ], "sync_notification_subscribers": [], "branches_to_filter": [], - "git_repository_branch_open_to_public_contributors": "live", + "git_repository_branch_open_to_public_contributors": "main", "need_preview_pull_request": true, "need_pr_comments": false, "dependent_repositories": [ @@ -64,4 +64,4 @@ "need_generate_pdf_url_template": true, "contribution_branch_mappings": {}, "need_generate_intellisense": false -} +} \ No newline at end of file From b47342e5bc760a2d5123142a887475365e751a66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Thu, 30 Oct 2025 20:06:28 +0100 Subject: [PATCH 218/224] Delete SECURITY.md added by initialization --- SECURITY.md | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index e138ec5d6a..0000000000 --- a/SECURITY.md +++ /dev/null @@ -1,41 +0,0 @@ - - -## Security - -Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). - -If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. - -## Reporting Security Issues - -**Please do not report security vulnerabilities through public GitHub issues.** - -Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). - -If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). - -You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). - -Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: - - * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. - -## Preferred Languages - -We prefer all communications to be in English. - -## Policy - -Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). - - From e96b6c413f9c2312f8e1df3ff3f9823f5cf986d8 Mon Sep 17 00:00:00 2001 From: cincuranet <4540597+cincuranet@users.noreply.github.com> Date: Thu, 30 Oct 2025 19:11:33 +0000 Subject: [PATCH 219/224] Initialize Docs repository: https://github.com/dotnet/EntityFramework.Docs of branch main --- SECURITY.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..e138ec5d6a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + From 0142b160db51b4f66d2c252fad25ed11d26ea5e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Thu, 30 Oct 2025 20:12:43 +0100 Subject: [PATCH 220/224] Delete SECURITY.md added by initialization --- SECURITY.md | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index e138ec5d6a..0000000000 --- a/SECURITY.md +++ /dev/null @@ -1,41 +0,0 @@ - - -## Security - -Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). - -If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. - -## Reporting Security Issues - -**Please do not report security vulnerabilities through public GitHub issues.** - -Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). - -If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). - -You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). - -Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: - - * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. - -## Preferred Languages - -We prefer all communications to be in English. - -## Policy - -Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). - - From 8d81a48f090f1763ef3b4bbf192e0dadb159a870 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Thu, 30 Oct 2025 20:19:45 +0100 Subject: [PATCH 221/224] Revert "Update github links to point to live branch (#5046)" (#5142) This reverts commit cd28d5bccc859cad1d5f2e5f7e237ed9090796db. --- .../core/change-tracking/change-detection.md | 2 +- .../core/change-tracking/debug-views.md | 2 +- .../core/change-tracking/entity-entries.md | 2 +- .../core/change-tracking/explicit-tracking.md | 2 +- .../change-tracking/identity-resolution.md | 2 +- .../core/change-tracking/index.md | 2 +- .../core/change-tracking/miscellaneous.md | 2 +- .../change-tracking/relationship-changes.md | 2 +- .../core/get-started/overview/first-app.md | 2 +- entity-framework/core/get-started/winforms.md | 2 +- entity-framework/core/get-started/wpf.md | 2 +- .../diagnostic-listeners.md | 4 +- .../core/logging-events-diagnostics/events.md | 4 +- .../interceptors.md | 14 ++--- .../simple-logging.md | 2 +- .../managing-schemas/migrations/projects.md | 2 +- .../managing-schemas/migrations/providers.md | 2 +- .../core/miscellaneous/multitenancy.md | 2 +- .../core/modeling/bulk-configuration.md | 2 +- .../core/modeling/data-seeding.md | 2 +- .../core/modeling/dynamic-model.md | 2 +- entity-framework/core/modeling/index.md | 4 +- .../core/modeling/keyless-entity-types.md | 2 +- .../core/modeling/owned-entities.md | 2 +- .../modeling/relationships/conventions.md | 2 +- .../foreign-and-principal-keys.md | 2 +- .../modeling/relationships/many-to-many.md | 2 +- .../relationships/mapping-attributes.md | 2 +- .../modeling/relationships/one-to-many.md | 2 +- .../core/modeling/relationships/one-to-one.md | 2 +- .../core/modeling/table-splitting.md | 2 +- .../core/modeling/value-comparers.md | 2 +- .../core/modeling/value-conversions.md | 2 +- .../advanced-performance-topics.md | 4 +- .../core/performance/efficient-querying.md | 2 +- .../performance/modeling-for-performance.md | 2 +- .../core/performance/performance-diagnosis.md | 4 +- .../core/providers/cosmos/index.md | 2 +- .../core/providers/sql-server/hierarchyid.md | 2 +- .../providers/sql-server/temporal-tables.md | 2 +- entity-framework/core/querying/client-eval.md | 2 +- .../core/querying/complex-query-operators.md | 2 +- entity-framework/core/querying/filters.md | 2 +- entity-framework/core/querying/index.md | 2 +- .../core/querying/related-data/index.md | 2 +- entity-framework/core/querying/tags.md | 2 +- entity-framework/core/querying/tracking.md | 2 +- entity-framework/core/saving/basic.md | 2 +- .../core/saving/cascade-delete.md | 2 +- entity-framework/core/saving/concurrency.md | 2 +- .../core/saving/disconnected-entities.md | 2 +- entity-framework/core/saving/related-data.md | 2 +- entity-framework/core/saving/transactions.md | 2 +- .../core/what-is-new/ef-core-6.0/whatsnew.md | 10 ++-- .../core/what-is-new/ef-core-7.0/whatsnew.md | 60 +++++++++---------- .../core/what-is-new/ef-core-8.0/whatsnew.md | 20 +++---- .../core/what-is-new/ef-core-9.0/whatsnew.md | 24 ++++---- 57 files changed, 121 insertions(+), 121 deletions(-) diff --git a/entity-framework/core/change-tracking/change-detection.md b/entity-framework/core/change-tracking/change-detection.md index b61b76cf90..53fc30ddfe 100644 --- a/entity-framework/core/change-tracking/change-detection.md +++ b/entity-framework/core/change-tracking/change-detection.md @@ -13,7 +13,7 @@ Each instance tracks changes made Tracking property and relationship changes requires that the DbContext is able to detect these changes. This document covers how this detection happens, as well as how to use property notifications or change-tracking proxies to force immediate detection of changes. > [!TIP] -> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/ChangeDetectionAndNotifications). +> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/ChangeDetectionAndNotifications). ## Snapshot change tracking diff --git a/entity-framework/core/change-tracking/debug-views.md b/entity-framework/core/change-tracking/debug-views.md index 78f9fdcaa9..d73ccceefc 100644 --- a/entity-framework/core/change-tracking/debug-views.md +++ b/entity-framework/core/change-tracking/debug-views.md @@ -17,7 +17,7 @@ The Entity Framework Core (EF Core) change tracker generates two kinds of output > This document assumes that entity states and the basics of EF Core change tracking are understood. See [Change Tracking in EF Core](xref:core/change-tracking/index) for more information on these topics. > [!TIP] -> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/ChangeTrackerDebugging). +> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/ChangeTrackerDebugging). ## Change tracker debug view diff --git a/entity-framework/core/change-tracking/entity-entries.md b/entity-framework/core/change-tracking/entity-entries.md index 8548e9184f..8dd8c89e25 100644 --- a/entity-framework/core/change-tracking/entity-entries.md +++ b/entity-framework/core/change-tracking/entity-entries.md @@ -21,7 +21,7 @@ Each of these is described in more detail in the sections below. > This document assumes that entity states and the basics of EF Core change tracking are understood. See [Change Tracking in EF Core](xref:core/change-tracking/index) for more information on these topics. > [!TIP] -> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/AccessingTrackedEntities). +> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/AccessingTrackedEntities). ## Using DbContext.Entry and EntityEntry instances diff --git a/entity-framework/core/change-tracking/explicit-tracking.md b/entity-framework/core/change-tracking/explicit-tracking.md index 372b3be840..4fb359d737 100644 --- a/entity-framework/core/change-tracking/explicit-tracking.md +++ b/entity-framework/core/change-tracking/explicit-tracking.md @@ -16,7 +16,7 @@ Entity Framework Core (EF Core) change tracking works best when the same This document assumes that entity states and the basics of EF Core change tracking are understood. See [Change Tracking in EF Core](xref:core/change-tracking/index) for more information on these topics. > [!TIP] -> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/ChangeTrackingInEFCore). +> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/ChangeTrackingInEFCore). ## Introduction diff --git a/entity-framework/core/change-tracking/identity-resolution.md b/entity-framework/core/change-tracking/identity-resolution.md index 48a53e1c5e..c13c304174 100644 --- a/entity-framework/core/change-tracking/identity-resolution.md +++ b/entity-framework/core/change-tracking/identity-resolution.md @@ -14,7 +14,7 @@ A can only track one entity insta > This document assumes that entity states and the basics of EF Core change tracking are understood. See [Change Tracking in EF Core](xref:core/change-tracking/index) for more information on these topics. > [!TIP] -> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/IdentityResolutionInEFCore). +> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/IdentityResolutionInEFCore). ## Introduction diff --git a/entity-framework/core/change-tracking/index.md b/entity-framework/core/change-tracking/index.md index 8393957ca8..b83a717308 100644 --- a/entity-framework/core/change-tracking/index.md +++ b/entity-framework/core/change-tracking/index.md @@ -13,7 +13,7 @@ Each instance tracks changes made This document presents an overview of Entity Framework Core (EF Core) change tracking and how it relates to queries and updates. > [!TIP] -> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/ChangeTrackingInEFCore). +> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/ChangeTrackingInEFCore). ## How to track entities diff --git a/entity-framework/core/change-tracking/miscellaneous.md b/entity-framework/core/change-tracking/miscellaneous.md index 5a1aa8e6c5..25289c34f7 100644 --- a/entity-framework/core/change-tracking/miscellaneous.md +++ b/entity-framework/core/change-tracking/miscellaneous.md @@ -14,7 +14,7 @@ This document covers miscellaneous features and scenarios involving change track > This document assumes that entity states and the basics of EF Core change tracking are understood. See [Change Tracking in EF Core](xref:core/change-tracking/index) for more information on these topics. > [!TIP] -> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/AdditionalChangeTrackingFeatures). +> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/AdditionalChangeTrackingFeatures). ## `Add` versus `AddAsync` diff --git a/entity-framework/core/change-tracking/relationship-changes.md b/entity-framework/core/change-tracking/relationship-changes.md index 79ec272452..01ab9ad361 100644 --- a/entity-framework/core/change-tracking/relationship-changes.md +++ b/entity-framework/core/change-tracking/relationship-changes.md @@ -20,7 +20,7 @@ Navigations can be used on both sides of the relationship, on one side only, or > This document assumes that entity states and the basics of EF Core change tracking are understood. See [Change Tracking in EF Core](xref:core/change-tracking/index) for more information on these topics. > [!TIP] -> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/ChangeTracking/ChangingFKsAndNavigations). +> You can run and debug into all the code in this document by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/ChangeTracking/ChangingFKsAndNavigations). ### Example model diff --git a/entity-framework/core/get-started/overview/first-app.md b/entity-framework/core/get-started/overview/first-app.md index d3e47e7a07..e68a22c606 100644 --- a/entity-framework/core/get-started/overview/first-app.md +++ b/entity-framework/core/get-started/overview/first-app.md @@ -12,7 +12,7 @@ In this tutorial, you create a .NET console app that performs data access agains You can follow the tutorial by using Visual Studio on Windows, or by using the .NET CLI on Windows, macOS, or Linux. -[View this article's sample on GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/GetStarted). +[View this article's sample on GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/GetStarted). ## Prerequisites diff --git a/entity-framework/core/get-started/winforms.md b/entity-framework/core/get-started/winforms.md index 898ea90a2e..3e339dbada 100644 --- a/entity-framework/core/get-started/winforms.md +++ b/entity-framework/core/get-started/winforms.md @@ -13,7 +13,7 @@ This step-by-step walkthrough shows how to build a simple Windows Forms (WinForm The screen shots and code listings in this walkthrough are taken from Visual Studio 2022 17.3.0. > [!TIP] -> You can view this article's [sample on GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/WinForms). +> You can view this article's [sample on GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/WinForms). ## Prerequisites diff --git a/entity-framework/core/get-started/wpf.md b/entity-framework/core/get-started/wpf.md index 3d06ae909c..9b5c5ffa26 100644 --- a/entity-framework/core/get-started/wpf.md +++ b/entity-framework/core/get-started/wpf.md @@ -15,7 +15,7 @@ The model defines two types that participate in one-to-many relationship: **Cate The screen shots and code listings in this walkthrough are taken from Visual Studio 2019 16.6.5. > [!TIP] -> You can view this article's [sample on GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/WPF). +> You can view this article's [sample on GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/WPF). ## Pre-Requisites diff --git a/entity-framework/core/logging-events-diagnostics/diagnostic-listeners.md b/entity-framework/core/logging-events-diagnostics/diagnostic-listeners.md index da113f8006..147ecf38bd 100644 --- a/entity-framework/core/logging-events-diagnostics/diagnostic-listeners.md +++ b/entity-framework/core/logging-events-diagnostics/diagnostic-listeners.md @@ -9,7 +9,7 @@ uid: core/logging-events-diagnostics/diagnostic-listeners # Using Diagnostic Listeners in EF Core > [!TIP] -> You can [download this article's sample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/DiagnosticListeners) from GitHub. +> You can [download this article's sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/DiagnosticListeners) from GitHub. Diagnostic listeners allow listening for any EF Core event that occurs in the current .NET process. The class is a part of a [common mechanism across .NET](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.DiagnosticSource/src/DiagnosticSourceUsersGuide.md) for obtaining diagnostic information from running applications. @@ -92,7 +92,7 @@ For example, the code above handles the [!TIP] > ToString is overridden in every EF Core event data class to generate the equivalent log message for the event. For example, calling `ContextInitializedEventData.ToString` generates "Entity Framework Core 5.0.0 initialized 'BlogsContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite' with options: None". -The [sample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/DiagnosticListeners) contains a simple console application that makes changes to the blogging database and prints out the diagnostic events encountered. +The [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/DiagnosticListeners) contains a simple console application that makes changes to the blogging database and prints out the diagnostic events encountered. > [!TIP] -> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Saving/Disconnected/) on GitHub. +> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Saving/Disconnected/) on GitHub. > [!TIP] > EF Core can only track one instance of any entity with a given primary key value. The best way to avoid this being an issue is to use a short-lived context for each unit-of-work such that the context starts empty, has entities attached to it, saves those entities, and then the context is disposed and discarded. diff --git a/entity-framework/core/saving/related-data.md b/entity-framework/core/saving/related-data.md index 7964fd9006..5b5c3cfcee 100644 --- a/entity-framework/core/saving/related-data.md +++ b/entity-framework/core/saving/related-data.md @@ -10,7 +10,7 @@ uid: core/saving/related-data In addition to isolated entities, you can also make use of the relationships defined in your model. > [!TIP] -> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Saving/RelatedData/) on GitHub. +> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Saving/RelatedData/) on GitHub. ## Adding a graph of new entities diff --git a/entity-framework/core/saving/transactions.md b/entity-framework/core/saving/transactions.md index 6091da0723..6788e93d87 100644 --- a/entity-framework/core/saving/transactions.md +++ b/entity-framework/core/saving/transactions.md @@ -10,7 +10,7 @@ uid: core/saving/transactions Transactions allow several database operations to be processed in an atomic manner. If the transaction is committed, all of the operations are successfully applied to the database. If the transaction is rolled back, none of the operations are applied to the database. > [!TIP] -> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Saving/Transactions/) on GitHub. +> You can view this article's [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Saving/Transactions/) on GitHub. ## Default transaction behavior diff --git a/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md index 3ff9c8b6cd..c9b6574e1a 100644 --- a/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-6.0/whatsnew.md @@ -11,7 +11,7 @@ uid: core/what-is-new/ef-core-6.0/whatsnew EF Core 6.0 has [shipped to NuGet](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/). This page contains an overview of interesting changes introduced in this release. > [!TIP] -> You can run and debug into the samples shown below by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore6). +> You can run and debug into the samples shown below by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore6). ## SQL Server temporal tables @@ -682,7 +682,7 @@ If supporting any of these features is critical to your success, then please vot ### Benchmarks > [!TIP] -> You can try compiling a large model and running a benchmark on it by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/CompiledModels). +> You can try compiling a large model and running a benchmark on it by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/CompiledModels). The model in the GitHub repo referenced above contains 449 entity types, 6390 properties, and 720 relationships. This is a moderately large model. Using [BenchmarkDotNet](https://www.nuget.org/packages/BenchmarkDotNet) to measure, the average time to first query is 1.02 seconds on a reasonably powerful laptop. Using compiled models brings this down to 117 milliseconds on the same hardware. An 8x to 10x improvement like this stays relatively constant as the model size increases. @@ -712,7 +712,7 @@ After these improvements, the gap between the popular "micro-ORM" [Dapper](https EF Core 6.0 contains many improvements to the Azure Cosmos DB database provider. > [!TIP] -> You can run and debug into all the the Cosmos-specific samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore6.Cosmos). +> You can run and debug into all the the Cosmos-specific samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore6.Cosmos). ### Default to implicit ownership @@ -2622,7 +2622,7 @@ modelBuilder --> [!code-csharp[WithDifferentTable](../../../../samples/core/Miscellaneous/NewInEFCore6/OptionalDependentsSample.cs?name=WithDifferentTable)] -See the [OptionalDependentsSample](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore6) in GitHub for more examples of optional dependents, including cases with nested optional dependents. +See the [OptionalDependentsSample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore6) in GitHub for more examples of optional dependents, including cases with nested optional dependents. ## New mapping attributes @@ -3568,7 +3568,7 @@ The EF Core codebase now uses [C# nullable reference types (NRTs)](/dotnet/cshar ## Microsoft.Data.Sqlite 6.0 > [!TIP] -> You can run and debug into all the samples shown below by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore6). +> You can run and debug into all the samples shown below by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore6). ### Connection Pooling diff --git a/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md index 99f6a091a7..1a8a775baf 100644 --- a/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md @@ -30,7 +30,7 @@ And a second aggregate type for post metadata: [!code-csharp[PostMetadataAggregate](../../../../samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs?name=PostMetadataAggregate)] > [!TIP] -> The sample model can be found in [BlogsContext.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs). +> The sample model can be found in [BlogsContext.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/BlogsContext.cs). ## JSON Columns @@ -96,7 +96,7 @@ The aggregate type is configured in `OnModelCreating` using `OwnsOne`: [!code-csharp[TableSharingAggregate](../../../../samples/core/Miscellaneous/NewInEFCore7/JsonColumnsSample.cs?name=TableSharingAggregate)] > [!TIP] -> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/JsonColumnsSample.cs). +> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/JsonColumnsSample.cs). By default, relational database providers map aggregate types like this to the same table as the owning entity type. That is, each property of the `ContactDetails` and `Address` classes is mapped to a column in the `Authors` table. @@ -549,7 +549,7 @@ All of this means that the `ExecuteUpdate` and `ExecuteDelete` methods complemen ### Basic `ExecuteDelete` examples > [!TIP] -> The code shown here comes from [ExecuteDeleteSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ExecuteDeleteSample.cs). +> The code shown here comes from [ExecuteDeleteSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ExecuteDeleteSample.cs). Calling `ExecuteDelete` or `ExecuteDeleteAsync` on a `DbSet` immediately deletes all entities of that `DbSet` from the database. For example, to delete all `Tag` entities: @@ -602,7 +602,7 @@ WHERE NOT EXISTS ( ### Basic `ExecuteUpdate` examples > [!TIP] -> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ExecuteUpdateSample.cs). +> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ExecuteUpdateSample.cs). `ExecuteUpdate` and `ExecuteUpdateAsync` behave in a very similar way to the `ExecuteDelete` methods. The main difference is that an update requires knowing _which_ properties to update, and _how_ to update them. This is achieved using one or more calls to `SetProperty`. For example, to update the `Name` of every blog: @@ -790,7 +790,7 @@ Some examples of these improvements are shown below. > See [Announcing Entity Framework Core 7 Preview 6: Performance Edition](https://devblogs.microsoft.com/dotnet/announcing-ef-core-7-preview6-performance-optimizations/) on the .NET Blog for an in-depth discussion of these changes. > [!TIP] -> The code shown here comes from [SaveChangesPerformanceSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/SaveChangesPerformanceSample.cs). +> The code shown here comes from [SaveChangesPerformanceSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/SaveChangesPerformanceSample.cs). ### Unneeded transactions are eliminated @@ -1020,7 +1020,7 @@ In addition, different database systems require different SQL for many of these By default, EF Core maps an inheritance hierarchy of .NET types to a single database table. This is known as the [table-per-hierarchy (TPH)](xref:core/modeling/inheritance#table-per-hierarchy-and-discriminator-configuration) mapping strategy. EF Core 5.0 introduced the [table-per-type (TPT)](xref:core/modeling/inheritance#table-per-type-configuration) strategy, which supports mapping each .NET type to a different database table. EF7 introduces the table-per-concrete-type (TPC) strategy. TPC also maps .NET types to different tables, but in a way that addresses some common performance issues with the TPT strategy. > [!TIP] -> The code shown here comes from [TpcInheritanceSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/TpcInheritanceSample.cs). +> The code shown here comes from [TpcInheritanceSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/TpcInheritanceSample.cs). > [!TIP] > The EF Team demonstrated and talked in depth about TPC mapping in an episode of the .NET Data Community Standup. As with [all Community Standup episodes](https://aka.ms/efstandups), you can [watch the TPC episode now on YouTube](https://youtu.be/HaL6DKW1mrg). @@ -1486,7 +1486,7 @@ protected override void ConfigureConventions(ModelConfigurationBuilder configura > To find all built-in model building conventions, look for every class that implements the interface. > [!TIP] -> The code shown here comes from [ModelBuildingConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingConventionsSample.cs). +> The code shown here comes from [ModelBuildingConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingConventionsSample.cs). ### Removing an existing convention @@ -2324,7 +2324,7 @@ The following sections show some examples of using these new interception capabi ### Simple actions on entity creation > [!TIP] -> The code shown here comes from [SimpleMaterializationSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/SimpleMaterializationSample.cs). +> The code shown here comes from [SimpleMaterializationSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/SimpleMaterializationSample.cs). The new supports interception before and after an entity instance is created, and before and after properties of that instance are initialized. The interceptor can change or replace the entity instance at each point. This allows: @@ -2418,7 +2418,7 @@ Customer 'Alice' was retrieved at '9/22/2022 5:25:54 PM' ### Injecting services into entities > [!TIP] -> The code shown here comes from [InjectLoggerSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/InjectLoggerSample.cs). +> The code shown here comes from [InjectLoggerSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/InjectLoggerSample.cs). EF Core already has built-in support for injecting some special services into context instances; for example, see [Lazy loading without proxies](xref:core/querying/related-data/lazy#lazy-loading-without-proxies), which works by injecting the `ILazyLoader` service. @@ -2503,7 +2503,7 @@ info: CustomersLogger[1] ### LINQ expression tree interception > [!TIP] -> The code shown here comes from [QueryInterceptionSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/QueryInterceptionSample.cs). +> The code shown here comes from [QueryInterceptionSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/QueryInterceptionSample.cs). EF Core makes use of [.NET LINQ queries](xref:core/querying/how-query-works). This typically involves using the C#, VB, or F# compiler to build an expression tree which is then translated by EF Core into the appropriate SQL. For example, consider a method that returns a page of customers: @@ -2649,7 +2649,7 @@ In this case the `ThenBy` is simply added to the query. Yes, it may need to be d ### Optimistic concurrency interception > [!TIP] -> The code shown here comes from [OptimisticConcurrencyInterceptionSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/OptimisticConcurrencyInterceptionSample.cs). +> The code shown here comes from [OptimisticConcurrencyInterceptionSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/OptimisticConcurrencyInterceptionSample.cs). EF Core supports the [optimistic concurrency pattern](xref:core/saving/concurrency) by checking that the number of rows actually affected by an update or delete is the same as the number of rows expected to be affected. This is often coupled with a concurrency token; that is, a column value that will only match its expected value if the row has not been updated since the expected value was read. @@ -2694,7 +2694,7 @@ There are several things worth noting about this interceptor: ### Lazy initialization of a connection string > [!TIP] -> The code shown here comes from [LazyConnectionStringSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/LazyConnectionStringSample.cs). +> The code shown here comes from [LazyConnectionStringSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/LazyConnectionStringSample.cs). Connection strings are often static assets read from a configuration file. These can easily be passed to `UseSqlServer` or similar when configuring a `DbContext`. However, sometimes the connection string can change for each context instance. For example, each tenant in a multi-tenant system may have a different connection string. @@ -2783,7 +2783,7 @@ Finally, the interceptor uses this service to obtain the connection string async ### Logging SQL Server query statistics > [!TIP] -> The code shown here comes from [QueryStatisticsLoggerSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/QueryStatisticsLoggerSample.cs). +> The code shown here comes from [QueryStatisticsLoggerSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/QueryStatisticsLoggerSample.cs). Finally, let's create two interceptors that work together to send SQL Server query statistics to the application log. To generate the statistics, we need an to do two things. @@ -2870,7 +2870,7 @@ EF7 contains many improvements in the translation of LINQ queries. ### GroupBy as final operator > [!TIP] -> The code shown here comes from [GroupByFinalOperatorSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs). +> The code shown here comes from [GroupByFinalOperatorSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs). EF7 supports using `GroupBy` as the final operator in a query. For example, this LINQ query: @@ -2893,7 +2893,7 @@ ORDER BY [b].[Price] ### GroupJoin as final operator > [!TIP] -> The code shown here comes from [GroupJoinFinalOperatorSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs). +> The code shown here comes from [GroupJoinFinalOperatorSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs). EF7 supports using `GroupJoin` as the final operator in a query. For example, this LINQ query: @@ -2919,7 +2919,7 @@ ORDER BY [c].[Id] ### GroupBy entity type > [!TIP] -> The code shown here comes from [GroupByEntityTypeSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs). +> The code shown here comes from [GroupByEntityTypeSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs). EF7 supports grouping by an entity type. For example, this LINQ query: @@ -2961,7 +2961,7 @@ FROM [Authors] AS [a] ### Subqueries don't reference ungrouped columns from outer query > [!TIP] -> The code shown here comes from [UngroupedColumnsQuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/UngroupedColumnsQuerySample.cs). +> The code shown here comes from [UngroupedColumnsQuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/UngroupedColumnsQuerySample.cs). In EF Core 6.0, a `GROUP BY` clause would reference columns in the outer query, which fails with some databases and is inefficient in others. For example, consider the following query: @@ -3005,7 +3005,7 @@ GROUP BY [t].[Key] ### Read-only collections can be used for `Contains` > [!TIP] -> The code shown here comes from [ReadOnlySetQuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ReadOnlySetQuerySample.cs). +> The code shown here comes from [ReadOnlySetQuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ReadOnlySetQuerySample.cs). EF7 supports using `Contains` when the items to search for are contained in an `IReadOnlySet` or `IReadOnlyCollection`, or `IReadOnlyList`. For example, this LINQ query: @@ -3040,7 +3040,7 @@ EF7 introduces better extensibility for providers to translate aggregate functio #### String aggregate functions > [!TIP] -> The code shown here comes from [StringAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/StringAggregateFunctionsSample.cs). +> The code shown here comes from [StringAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/StringAggregateFunctionsSample.cs). Queries using and are now translated when appropriate. For example: @@ -3109,7 +3109,7 @@ ORDER BY [t].[Name] #### Spatial aggregate functions > [!TIP] -> The code shown here comes from [SpatialAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/SpatialAggregateFunctionsSample.cs). +> The code shown here comes from [SpatialAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/SpatialAggregateFunctionsSample.cs). It is now possible for [database providers that support for NetTopologySuite](xref:core/modeling/spatial) to translate the following spatial aggregate functions: @@ -3147,7 +3147,7 @@ GROUP BY [c].[Owner] #### Statistical aggregate functions > [!TIP] -> The code shown here comes from [StatisticalAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/StatisticalAggregateFunctionsSample.cs). +> The code shown here comes from [StatisticalAggregateFunctionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/StatisticalAggregateFunctionsSample.cs). SQL Server translations have been implemented for the following statistical functions: @@ -3190,7 +3190,7 @@ GROUP BY [u].[Id] ### Translation of `string.IndexOf` > [!TIP] -> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). +> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). EF7 now translates in LINQ queries. For example: @@ -3212,7 +3212,7 @@ WHERE (CAST(CHARINDEX(N'Entity', [p].[Content]) AS int) - 1) > 0 ### Translation of `GetType` for entity types > [!TIP] -> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). +> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). EF7 now translates in LINQ queries. For example: @@ -3248,7 +3248,7 @@ And will return both `Post` and `FeaturedPost` entities. ### Support for `AT TIME ZONE` > [!TIP] -> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). +> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). EF7 introduces new functions for and . These functions translate to `AT TIME ZONE` clauses in the generated SQL. For example: @@ -3276,7 +3276,7 @@ FROM [Posts] AS [p] ### Filtered Include on hidden navigations > [!TIP] -> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). +> The code shown here comes from [MiscellaneousTranslationsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/MiscellaneousTranslationsSample.cs). The [Include methods](xref:core/querying/related-data/eager) can now be used with . This allows [filtering and ordering](xref:core/querying/related-data/eager#filtered-include) even for private navigation properties, or private navigations represented by fields. For example: @@ -3315,7 +3315,7 @@ ORDER BY [b].[Id], [t].[Title] ### Cosmos translation for `Regex.IsMatch` > [!TIP] -> The code shown here comes from [CosmosQueriesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/CosmosQueriesSample.cs). +> The code shown here comes from [CosmosQueriesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/CosmosQueriesSample.cs). EF7 supports using in LINQ queries against Azure Cosmos DB. For example: @@ -3339,7 +3339,7 @@ WHERE ((c["Discriminator"] = "Triangle") AND RegexMatch(c["Name"], "[a-z]t[a-z]" EF7 contains a variety of small improvements to and related classes. > [!TIP] -> The code for samples in this section comes from [DbContextApiSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/DbContextApiSample.cs). +> The code for samples in this section comes from [DbContextApiSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/DbContextApiSample.cs). ### Suppressor for uninitialized DbSet properties @@ -3553,7 +3553,7 @@ Notice: EF7 contains a variety of small improvements in model building. > [!TIP] -> The code for samples in this section comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs). +> The code for samples in this section comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs). ### Indexes can be ascending or descending @@ -4067,7 +4067,7 @@ If these types are mapped to the same table, then in EF7 that table can be made EF7 includes two significant improvements to the automatic generation of values for key properties. > [!TIP] -> The code for samples in this section comes from [ValueGenerationSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore7/ValueGenerationSample.cs). +> The code for samples in this section comes from [ValueGenerationSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore7/ValueGenerationSample.cs). ### Value generation for DDD guarded types @@ -4331,4 +4331,4 @@ public partial class MainForm : Form } ``` -See [Getting Started with Windows Forms](xref:core/get-started/winforms) for a complete walkthrough and [downloadable WinForms sample application](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/WinForms). +See [Getting Started with Windows Forms](xref:core/get-started/winforms) for a complete walkthrough and [downloadable WinForms sample application](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/WinForms). diff --git a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md index e4163bf8da..00dd937cac 100644 --- a/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-8.0/whatsnew.md @@ -665,7 +665,7 @@ The first option has advantages in many situations--we'll take a quick look at i Starting with Preview 4, EF8 now includes built-in support for the second option, using JSON as the serialization format. JSON works well for this since modern relational databases include built-in mechanisms for querying and manipulating JSON, such that the JSON column can, effectively, be treated as a table when needed, without the overhead of actually creating that table. These same mechanisms allow JSON to be passed in parameters and then used in similar way to table-valued parameters in queries--more about this later. > [!TIP] -> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs). +> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs). ### Primitive collection properties @@ -1017,7 +1017,7 @@ In all the examples above, column for primitive collection contains JSON. Howeve [!code-csharp[Pub](../../../../samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs?name=Pub)] > [!TIP] -> The code shown here comes from [PrimitiveCollectionsInJsonSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs). +> The code shown here comes from [PrimitiveCollectionsInJsonSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsInJsonSample.cs). We can now run a variation of our final query that, this time, extracts data from the JSON document, including queries into the primitive collections contained in the document: @@ -1120,7 +1120,7 @@ CREATE TABLE [Beer] ( EF8 includes improvements to the [JSON column mapping support introduced in EF7](xref:core/what-is-new/ef-core-7.0/whatsnew#json-columns). > [!TIP] -> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs). +> The code shown here comes from [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs). ### Translate element access into JSON arrays @@ -1241,7 +1241,7 @@ EF7 introduced support for mapping to JSON columns when using Azure SQL/SQL Serv The existing [documentation from What's New in EF7](xref:core/what-is-new/ef-core-7.0/whatsnew#json-columns) provides detailed information on JSON mapping, queries, and updates. This documentation now also applies to SQLite. > [!TIP] -> The code shown in the EF7 documentation has been updated to also run on SQLite can can be found in [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs). +> The code shown in the EF7 documentation has been updated to also run on SQLite can can be found in [JsonColumnsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs). #### Queries into JSON columns @@ -1347,7 +1347,7 @@ The `HierarchyId` type can be used for properties of an entity type. For example [!code-csharp[Halfling](../../../../samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs?name=Halfling)] > [!TIP] -> The code shown here and in the examples below comes from [HierarchyIdSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs). +> The code shown here and in the examples below comes from [HierarchyIdSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/HierarchyIdSample.cs). > [!TIP] > If desired, `HierarchyId` is suitable for use as a key property type. @@ -1661,7 +1661,7 @@ Following the update, querying for the descendents of "Mungo" returns "Bungo", " EF7 introduced [raw SQL queries returning scalar types](xref:core/querying/sql-queries#querying-scalar-(non-entity)-types). This is enhanced in EF8 to include raw SQL queries returning any mappable CLR type, without including that type in the EF model. > [!TIP] -> The code shown here comes from [RawSqlSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/RawSqlSample.cs). +> The code shown here comes from [RawSqlSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/RawSqlSample.cs). Queries using unmapped types are executed using or . The former uses string interpolation to parameterize the query, which helps ensure that all non-constant values are parameterized. For example, consider the following database table: @@ -1850,7 +1850,7 @@ The returned `IQueryable` can be composed upon when it is the result of a view o EF8 adds support for [lazy-loading of navigations](xref:core/querying/related-data/lazy) on entities that are not being tracked by the `DbContext`. This means a no-tracking query can be followed by lazy-loading of navigations on the entities returned by the no-tracking query. > [!TIP] -> The code for the lazy-loading examples shown below comes from [LazyLoadingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/LazyLoadingSample.cs). +> The code for the lazy-loading examples shown below comes from [LazyLoadingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/LazyLoadingSample.cs). For example, consider a no-tracking query for blogs: @@ -1943,7 +1943,7 @@ EF8 contains new public APIs so that applications can now use these data structu [!code-csharp[LookupByPrimaryKey](../../../../samples/core/Miscellaneous/NewInEFCore8/LookupByKeySample.cs?name=LookupByPrimaryKey)] > [!TIP] -> The code shown here comes from [LookupByKeySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/LookupByKeySample.cs). +> The code shown here comes from [LookupByKeySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/LookupByKeySample.cs). The [`FindEntry`](https://github.com/dotnet/efcore/blob/81886272a761df8fafe4970b895b1e1fe35effb8/src/EFCore/ChangeTracking/LocalView.cs#L543) method returns either the for the tracked entity, or `null` if no entity with the given key is being tracked. Like all methods on `LocalView`, the database is never queried, even if the entity is not found. The returned entry contains the entity itself, as well as tracking information. For example: @@ -2082,7 +2082,7 @@ public class OpeningHours [!code-csharp[BritishSchools](../../../../samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs?name=BritishSchools)] > [!TIP] -> The code shown here comes from [DateOnlyTimeOnlySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs). +> The code shown here comes from [DateOnlyTimeOnlySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/DateOnlyTimeOnlySample.cs). > [!NOTE] > This model represents only British schools and stores times as local (GMT) times. Handling different timezones would complicate this code significantly. Note that using `DateTimeOffset` would not help here, since opening and closing times have different offsets depending whether daylight saving time is active or not. @@ -2283,7 +2283,7 @@ b.Property(e => e.LeaseDate).HasDefaultValueSql("getutcdate()"); ``` > [!TIP] -> The code shown below comes from [DefaultConstraintSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs). +> The code shown below comes from [DefaultConstraintSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs). In order for EF to make use of this, it must determine when and when not to send a value for the column. By default, EF uses the CLR default as a sentinel for this. That is, when the value of `Status` or `LeaseDate` in the examples above are the CLR defaults for these types, then EF _interprets that to mean that the property has not been set_, and so does not send a value to the database. This works well for reference types--for example, if the `string` property `Status` is `null`, then EF doesn't send `null` to the database, but rather does not include any value so that the database default (`"Hidden"`) is used. Likewise, for the `DateTime` property `LeaseDate`, EF will not insert the CLR default value of `1/1/0001 12:00:00 AM`, but will instead omit this value so that database default is used. 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 9607381168..dd6003db2b 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 @@ -75,7 +75,7 @@ To learn more about querying with partition keys and point reads, [see the query ### Hierarchical partition keys > [!TIP] -> The code shown here comes from [HierarchicalPartitionKeysSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs). +> The code shown here comes from [HierarchicalPartitionKeysSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9.Cosmos/HierarchicalPartitionKeysSample.cs). Azure Cosmos DB originally supported a single partition key, but has since expanded partitioning capabilities to also support [subpartitioning through the specification of up to three levels of hierarchy in the partition key](/azure/cosmos-db/hierarchical-partition-keys). EF Core 9 brings full support for hierarchical partition keys, allowing you take advantage of the better performance and cost savings associated with this feature. @@ -342,7 +342,7 @@ We'd like to call out Andrea Canciani ([@ranma42](https://github.com/ranma42)) f #### GroupBy > [!TIP] -> The code shown here comes from [ComplexTypesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs). +> The code shown here comes from [ComplexTypesSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ComplexTypesSample.cs). EF9 supports grouping by a complex type instance. For example: @@ -365,7 +365,7 @@ GROUP BY [s].[StoreAddress_City], [s].[StoreAddress_Country], [s].[StoreAddress_ #### ExecuteUpdate > [!TIP] -> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs). +> The code shown here comes from [ExecuteUpdateSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ExecuteUpdateSample.cs). Similarly, in EF9 `ExecuteUpdate` has also been improved to accept complex type properties. However, each member of the complex type must be specified explicitly. For example: @@ -506,7 +506,7 @@ FROM ( ### Translations involving GREATEST/LEAST > [!TIP] -> The code shown here comes from [LeastGreatestSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/LeastGreatestSample.cs). +> The code shown here comes from [LeastGreatestSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/LeastGreatestSample.cs). Several new translations have been introduced that use the `GREATEST` and `LEAST` SQL functions. @@ -584,7 +584,7 @@ FROM [Pubs] AS [p] ### Force or prevent query parameterization > [!TIP] -> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). +> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). Except in some special cases, EF Core parameterizes variables used in a LINQ query, but includes constants in the generated SQL. For example, consider the following query method: @@ -710,7 +710,7 @@ Moreover, EF9 introduces `TranslateParameterizedCollectionsToConstants` [context ### Inlined uncorrelated subqueries > [!TIP] -> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). +> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). In EF8, an IQueryable referenced in another query may be executed as a separate database roundtrip. For example, consider the following LINQ query: @@ -824,7 +824,7 @@ var topRatedPostsAverageRatingByLanguage = await context.Blogs. ### Queries using Count != 0 are optimized > [!TIP] -> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). +> The code shown here comes from [QuerySample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/QuerySample.cs). In EF8, the following LINQ query was translated to use the SQL `COUNT` function: @@ -1121,7 +1121,7 @@ More information can be found [here](/ef/core/modeling/data-seeding#use-seeding- ### Auto-compiled models > [!TIP] -> The code shown here comes from the [NewInEFCore9.CompiledModels](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9.CompiledModels/) sample. +> 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: @@ -1221,7 +1221,7 @@ For more information see [MSBuild integration](xref:core/cli/msbuild). ### Read-only primitive collections > [!TIP] -> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs). +> The code shown here comes from [PrimitiveCollectionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/PrimitiveCollectionsSample.cs). EF8 introduced support for [mapping arrays and mutable lists of primitive types](xref:core/what-is-new/ef-core-8.0/whatsnew#primitive-collections). This has been expanded in EF9 to include read-only collections/lists. Specifically, EF9 supports collections typed as `IReadOnlyList`, `IReadOnlyCollection`, or `ReadOnlyCollection`. For example, in the following code, `DaysVisited` will be mapped by convention as a primitive collection of dates: @@ -1281,7 +1281,7 @@ INNER JOIN "Pubs" AS "p" ON "w"."ClosestPubId" = "p"."Id" ### Specify fill-factor for keys and indexes > [!TIP] -> The code shown here comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs). +> The code shown here comes from [ModelBuildingSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/ModelBuildingSample.cs). EF9 supports specification of the [SQL Server fill-factor](/sql/relational-databases/indexes/specify-fill-factor-for-an-index) when using EF Core Migrations to create keys and indexes. From the SQL Server docs, "When an index is created or rebuilt, the fill-factor value determines the percentage of space on each leaf-level page to be filled with data, reserving the remainder on each page as free space for future growth." @@ -1328,7 +1328,7 @@ This enhancement was contributed by [@deano-hunter](https://github.com/deano-hun ### Make existing model building conventions more extensible > [!TIP] -> The code shown here comes from [CustomConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/CustomConventionsSample.cs). +> The code shown here comes from [CustomConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/CustomConventionsSample.cs). Public model building conventions for applications were [introduced in EF7](xref:core/modeling/bulk-configuration#Conventions). In EF9, we have made it easier to extend some of the existing conventions. For example, [the code to map properties by attribute in EF7](xref:core/what-is-new/ef-core-7.0/whatsnew#model-building-conventions) is this: @@ -1451,7 +1451,7 @@ As an aside, some people think this pattern is an abomination because it couples ## SQL Server HierarchyId > [!TIP] -> The code shown here comes from [HierarchyIdSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/live/samples/core/Miscellaneous/NewInEFCore9/HierarchyIdSample.cs). +> The code shown here comes from [HierarchyIdSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Miscellaneous/NewInEFCore9/HierarchyIdSample.cs). From c5cde0e11ab8919dfcaf9e7ab17c79418673eded Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Thu, 30 Oct 2025 20:21:50 +0100 Subject: [PATCH 222/224] Revert "Correct a few more links to the samples (main -> live) (#5063)" (#5143) This reverts commit 3463369c6d1aa30a7cc1cd04b5d56733e16baf68. --- .../core/performance/advanced-performance-topics.md | 2 +- entity-framework/core/testing/testing-with-the-database.md | 4 ++-- .../core/testing/testing-without-the-database.md | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/entity-framework/core/performance/advanced-performance-topics.md b/entity-framework/core/performance/advanced-performance-topics.md index c46809a1fe..7c69c33411 100644 --- a/entity-framework/core/performance/advanced-performance-topics.md +++ b/entity-framework/core/performance/advanced-performance-topics.md @@ -89,7 +89,7 @@ When EF receives a LINQ query tree for execution, it must first "compile" that t However, EF must still perform certain tasks before it can make use of the internal query cache. For example, your query's expression tree must be recursively compared with the expression trees of cached queries, to find the correct cached query. The overhead for this initial processing is negligible in the majority of EF applications, especially when compared to other costs associated with query execution (network I/O, actual query processing and disk I/O at the database...). However, in certain high-performance scenarios it may be desirable to eliminate it. -EF supports *compiled queries*, which allow the explicit compilation of a LINQ query into a .NET delegate. Once this delegate is acquired, it can be invoked directly to execute the query, without providing the LINQ expression tree. This technique bypasses the cache lookup, and provides the most optimized way to execute a query in EF Core. Following are some benchmark results comparing compiled and non-compiled query performance; benchmark on your platform before making any decisions. [The source code is available here](https://github.com/dotnet/EntityFramework.Docs/blob/live/samples/core/Benchmarks/CompiledQueries.cs), feel free to use it as a basis for your own measurements. +EF supports *compiled queries*, which allow the explicit compilation of a LINQ query into a .NET delegate. Once this delegate is acquired, it can be invoked directly to execute the query, without providing the LINQ expression tree. This technique bypasses the cache lookup, and provides the most optimized way to execute a query in EF Core. Following are some benchmark results comparing compiled and non-compiled query performance; benchmark on your platform before making any decisions. [The source code is available here](https://github.com/dotnet/EntityFramework.Docs/blob/main/samples/core/Benchmarks/CompiledQueries.cs), feel free to use it as a basis for your own measurements. | Method | NumBlogs | Mean | Error | StdDev | Gen 0 | Allocated | |--------------------- |--------- |---------:|---------:|---------:|-------:|----------:| diff --git a/entity-framework/core/testing/testing-with-the-database.md b/entity-framework/core/testing/testing-with-the-database.md index 26df736ec1..7903fece8a 100644 --- a/entity-framework/core/testing/testing-with-the-database.md +++ b/entity-framework/core/testing/testing-with-the-database.md @@ -9,7 +9,7 @@ uid: core/testing/testing-with-the-database In this page, we discuss techniques for writing automated tests which involve the database system against which the application runs in production. Alternate testing approaches exist, where the production database system is swapped out by test doubles; see the [testing overview page](xref:core/testing/index) for more information. Note that testing against a different database than what is used in production (e.g. Sqlite) is not covered here, since the different database is used as a test double; this approach is covered in [Testing without your production database system](xref:core/testing/testing-without-the-database). -The main hurdle with testing which involves a real database is to ensure proper test isolation, so that tests running in parallel (or even in serial) don't interfere with each other. The full sample code for the below can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/live/samples/core/Testing/TestingWithTheDatabase). +The main hurdle with testing which involves a real database is to ensure proper test isolation, so that tests running in parallel (or even in serial) don't interfere with each other. The full sample code for the below can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/main/samples/core/Testing/TestingWithTheDatabase). > [!TIP] > This page shows [xUnit](https://xunit.net/) techniques, but similar concepts exist in other testing frameworks, including [NUnit](https://nunit.org/). @@ -96,7 +96,7 @@ Finally, we make our test class disposable, arranging for the fixture's `Cleanup Note that since xUnit only ever instantiates the collection fixture once, there is no need for us to use locking around database creation and seeding as we did above. -The full sample code for the above can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/live/samples/core/Testing/TestingWithTheDatabase/TransactionalBloggingControllerTest.cs). +The full sample code for the above can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/main/samples/core/Testing/TestingWithTheDatabase/TransactionalBloggingControllerTest.cs). > [!TIP] > If you have multiple test classes with tests which modify the database, you can still run them in parallel by having different fixtures, each referencing its own database. Creating and using many test databases isn't problematic and should be done whenever it's helpful. diff --git a/entity-framework/core/testing/testing-without-the-database.md b/entity-framework/core/testing/testing-without-the-database.md index 55f19e3bea..311804028e 100644 --- a/entity-framework/core/testing/testing-without-the-database.md +++ b/entity-framework/core/testing/testing-without-the-database.md @@ -49,7 +49,7 @@ At this point, your application is architected according to the repository patte [!code-csharp[Main](../../../samples/core/Testing/TestingWithoutTheDatabase/RepositoryBloggingControllerTest.cs?name=GetBlog)] -The full sample code can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/live/samples/core/Testing/TestingWithoutTheDatabase/RepositoryBloggingControllerTest.cs). +The full sample code can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/main/samples/core/Testing/TestingWithoutTheDatabase/RepositoryBloggingControllerTest.cs). ## SQLite in-memory @@ -61,7 +61,7 @@ To use in-memory SQLite, it's important to understand that a **new database is c Tests can now call `CreateContext`, which returns a context using the connection we set up in the constructor, ensuring we have a clean database with the seeded data. -The full sample code for SQLite in-memory testing can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/live/samples/core/Testing/TestingWithoutTheDatabase/SqliteInMemoryBloggingControllerTest.cs). +The full sample code for SQLite in-memory testing can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/main/samples/core/Testing/TestingWithoutTheDatabase/SqliteInMemoryBloggingControllerTest.cs). ## In-memory provider @@ -69,7 +69,7 @@ As discussed in the [testing overview page](xref:core/testing/choosing-a-testing [!code-csharp[Main](../../../samples/core/Testing/TestingWithoutTheDatabase/InMemoryBloggingControllerTest.cs?name=Constructor)] -The full sample code for in-memory testing can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/live/samples/core/Testing/TestingWithoutTheDatabase/InMemoryBloggingControllerTest.cs). +The full sample code for in-memory testing can be viewed [here](https://github.com/dotnet/EntityFramework.Docs/blob/main/samples/core/Testing/TestingWithoutTheDatabase/InMemoryBloggingControllerTest.cs). ### In-memory database naming From d772dbb9a9195f2b43eadd4c0756b34bd7e7afec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jiri=20Cincura=20=E2=86=B9?= Date: Thu, 30 Oct 2025 20:58:33 +0100 Subject: [PATCH 223/224] Fix author field (#5146) --- entity-framework/dotnet-data/index.yml | 1 - entity-framework/index.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/entity-framework/dotnet-data/index.yml b/entity-framework/dotnet-data/index.yml index 3bb44b8fc5..fa791286b6 100644 --- a/entity-framework/dotnet-data/index.yml +++ b/entity-framework/dotnet-data/index.yml @@ -10,7 +10,6 @@ metadata: ms.product: entity-framework ms.topic: hub-page author: jcjiang - ms.author: jiacjian ms.date: 03/08/2023 # highlightedContent section (optional) diff --git a/entity-framework/index.yml b/entity-framework/index.yml index eefa0ce7a6..dceb7a7fe0 100644 --- a/entity-framework/index.yml +++ b/entity-framework/index.yml @@ -9,7 +9,6 @@ metadata: description: Entity Framework is a modern object-relation mapper that lets you build a clean, portable, and high-level data access layer with .NET (C#) across a variety of databases, including SQL Database (on-premises and Azure), SQLite, MySQL, PostgreSQL, and Azure Cosmos DB. It supports LINQ queries, change tracking, updates, and schema migrations. ms.topic: hub-page author: jcjiang - ms.author: jiacjian ms.date: 03/08/2023 # highlightedContent section (optional) From 428ea174180de38d49249cad9411cc8cab037e7a Mon Sep 17 00:00:00 2001 From: Branden Hammann Date: Sat, 1 Nov 2025 09:25:48 -0500 Subject: [PATCH 224/224] Fix wording for clarity in best practices section Corrected the wording from 'specific versions' to 'specific version' for clarity. --- entity-framework/core/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/index.md b/entity-framework/core/index.md index 24665b69b5..c6482c1d05 100644 --- a/entity-framework/core/index.md +++ b/entity-framework/core/index.md @@ -47,7 +47,7 @@ While EF Core is good at abstracting many programming details, there are some be * Intermediate-level knowledge or higher of the underlying database server is essential to architect, debug, profile, and migrate data in high performance production apps. For example, knowledge of primary and foreign keys, constraints, indexes, normalization, DML and DDL statements, data types, profiling, etc. * Functional and integration testing: It's important to replicate the production environment as closely as possible to: - * Find issues in the app that only show up when using a specific versions or edition of the database server. + * Find issues in the app that only show up when using a specific version or edition of the database server. * Catch breaking changes when upgrading EF Core and other dependencies. For example, adding or upgrading frameworks like ASP.NET Core, OData, or AutoMapper. These dependencies can affect EF Core in unexpected ways. * Performance and stress testing with representative loads. The naïve usage of some features doesn't scale well. For example, multiple collections Includes, heavy use of lazy loading, conditional queries on non-indexed columns, massive updates and inserts with store-generated values, lack of concurrency handling, large models, inadequate cache policy. * Security review: For example, handling of connection strings and other secrets, database permissions for non-deployment operation, input validation for raw SQL, encryption for sensitive data. See [Secure authentication flows](/aspnet/core/security/#secure-authentication-flows) for secure configuration and authentication flow.