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 ea2ff0e650..0afadee2a1 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 @@ -2,20 +2,18 @@ title: What's New in EF Core 8 description: Overview of new features in EF Core 8 author: ajcvickers -ms.date: 09/19/2023 +ms.date: 11/13/2023 uid: core/what-is-new/ef-core-8.0/whatsnew --- # What's New in EF Core 8 -EF Core 8.0 (EF8) is the next release after EF Core 7.0 and is scheduled for release in November 2023. See [_Plan for Entity Framework Core 8_](xref:core/what-is-new/ef-core-8.0/plan) for details and [_Latest news and progress on .NET 8 and EF8_](https://github.com/dotnet/efcore/issues/29989) for progress on the plan. - -EF8 is available as [daily builds](https://github.com/dotnet/efcore/blob/main/docs/DailyBuilds.md) which contain all the latest EF8 features and API tweaks. The samples here make use of these daily builds. +EF Core 8.0 (EF8) was [released in November 2023](https://devblogs.microsoft.com/dotnet/announcing-ef8/). > [!TIP] > You can run and debug into the samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs). Each section links to the source code specific to that section. -EF8 requires the [latest .NET 8 Preview SDK](https://dotnet.microsoft.com/download/dotnet/8.0). EF8 will not run on earlier .NET versions, and will not run on .NET Framework. +EF8 requires the [.NET 8 SDK](https://aka.ms/get-dotnet-8) to build and requires the .NET 8 runtime to run. EF8 will not run on earlier .NET versions, and will not run on .NET Framework. ## Value objects using Complex Types @@ -678,7 +676,6 @@ public class PrimitiveCollections { public IEnumerable Ints { get; set; } public ICollection Strings { get; set; } - public ISet DateTimes { get; set; } public IList Dates { get; set; } public uint[] UnsignedInts { get; set; } public List Booleans { get; set; } @@ -1201,6 +1198,37 @@ FROM [Posts] AS [p] AND (CAST(JSON_VALUE([p].[Metadata],'$.Updates[1].UpdatedOn') AS date) IS NOT NULL) ``` +### Translate queries into embedded collections + +EF8 supports queries against collections of both primitive (discussed above) and non-primitive types embedded in the JSON document. For example, the following query returns all posts with any of an arbitrary list of search terms: + + +[!code-csharp[PostsWithSearchTerms](../../../../samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs?name=PostsWithSearchTerms)] + +This translates into the following SQL when using SQL Server: + +```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 EXISTS ( + SELECT 1 + FROM OPENJSON([p].[Metadata], '$.TopSearches') WITH ( + [Count] int '$.Count', + [Term] nvarchar(max) '$.Term' + ) AS [t] + WHERE EXISTS ( + SELECT 1 + FROM OPENJSON(@__searchTerms_0) WITH ([value] nvarchar(max) '$') AS [s] + WHERE [s].[value] = [t].[Term])) +``` + ### JSON Columns for SQLite EF7 introduced support for mapping to JSON columns when using Azure SQL/SQL Server. EF8 extends this support to SQLite databases. As for the SQL Server support, this includes: @@ -2237,3 +2265,391 @@ In EF Core 8, we now use the data format and column type name in addition to the | '1970-01-01 00:00:00' | ~~string~~ **DateTime** | | '00:00:00' | ~~string~~ **TimeSpan** | | '00000000-0000-0000-0000-000000000000' | ~~string~~ **Guid** | + +## Sentinel values and database defaults + +Databases allow columns to be configured to generate a default value if no value is provided when inserting a row. This can be represented in EF using `HasDefaultValue` for constants: + +```csharp +b.Property(e => e.Status).HasDefaultValue("Hidden"); +``` + +Or `HasDefaultValueSql` for arbitrary SQL clauses: + +```csharp +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). + +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. + +However, in some cases the CLR default value is a valid value to insert. EF8 handles this by allowing the sentinel value for a colum to change. For example, consider an integer column configured with a database default: + +```csharp +b.Property(e => e.Credits).HasDefaultValueSql(10); +``` + +In this case, we want the new entity to be inserted with the given number of credits, unless this is not specified, in which case 10 credits are assigned. However, this means that inserting a record with zero credits is not possible, since zero is the CLR default, and hence will cause EF to send no value. In EF8, this can be fixed by changing the sentinel for the property from zero to `-1`: + +```csharp +b.Property(e => e.Credits).HasDefaultValueSql(10).HasSentinel(-1); +``` + +EF will now only use the database default if `Credits` is set to `-1`; a value of zero will be inserted like any other amount. + +It can often be useful to reflect this in the entity type as well as in the EF configuration. For example: + +```csharp +public class Person +{ + public int Id { get; set; } + public int Credits { get; set; } = -1; +} +``` + +This means that the sentinel value of -1 gets set automatically when the instance is created, meaning that the property starts in its "not-set" state. + +> [!TIP] +> If you want to configure the database default constraint for use when `Migrations` creates the column, but you want EF to always insert a value, then configure the property as not-generated. For example, `b.Property(e => e.Credits).HasDefaultValueSql(10).ValueGeneratedNever();`. + +### Database defaults for booleans + +Boolean properties present an extreme form of this problem, since the CLR default (`false`) is one of only two valid values. This means that a `bool` property with a database default constraint will only have a value inserted if that value is `true`. When the database default value is `false`, then this means when the property value is `false`, then the database default will be used, which is `false`. Otherwise, if the property value is `true`, then `true` will be inserted. So when the database default is `false`, then the database column ends up with the correct value. + +On the other hand, if the database default value is `true`, this means when the property value is `false`, then the database default will be used, which is `true`! And when the property value is `true`, then `true` will be inserted. So, the value in the column will always end `true` in the database, regardless of what the property value is. + +EF8 fixes this problem by setting the sentinel for bool properties to the same value as the database default value. Both cases above then result in the correct value being inserted, regardless of whether the database default is `true` or `false`. + +> [!TIP] +> When scaffolding from an existing database, EF8 parses and then includes simple default values into `HasDefaultValue` calls. (Previously, all default values were scaffolded as opaque `HasDefaultValueSql` calls.) This means that non-nullable bool columns with a `true` or `false` constant database default are no longer scaffolded as nullable. + +### Database defaults for enums + +Enum properties can have similar problems to `bool` properties because enums typically have a very small set of valid values, and the CLR default may be one of these values. For example, consider this entity type and enum: + +```csharp +public class Course +{ + public int Id { get; set; } + public Level Level { get; set; } +} + +public enum Level +{ + Beginner, + Intermediate, + Advanced, + Unspecified +} +``` + +The `Level` property is then configured with a database default: + +```csharp +modelBuilder.Entity() + .Property(e => e.Level) + .HasDefaultValue(Level.Intermediate); +``` + +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: + +```csharp +public enum Level +{ + Unspecified, + Beginner, + Intermediate, + Advanced +} +``` + +However, it is not always possible to change an existing enum, so in EF8, the sentinel can again be specified. For example, going back to the original enum: + +```csharp +modelBuilder.Entity() + .Property(e => e.Level) + .HasDefaultValue(Level.Intermediate) + .HasSentinel(Level.Unspecified); +``` + +Now `Level.Beginner` will be inserted as normal, and the database default will only be used when the property value is `Level.Unspecified`. It can again be useful to reflect this in the entity type itself. For example: + +```csharp +public class Course +{ + public int Id { get; set; } + public Level Level { get; set; } = Level.Unspecified; +} +``` + +### Using a nullable backing field + +A more general way to handle the problem described above is to create a nullable backing field for the non-nullable property. For example, consider the following entity type with a `bool` property: + +```csharp +public class Account +{ + public int Id { get; set; } + public bool IsActive { get; set; } +} +``` + +The property can be given a nullable backing field: + +```csharp +public class Account +{ + public int Id { get; set; } + + private bool? _isActive; + + public bool IsActive + { + get => _isActive ?? false; + set => _isActive = value; + } +} +``` + +The backing field here will remain `null` _unless the property setter is actually called_. That is, the value of the backing field is a better indication of whether the property has been set or not than the CLR default of the property. This works out-of-the box with EF, since EF will use the backing field to read and write the property by default. + +## Better ExecuteUpdate and ExecuteDelete + +SQL commands that perform updates and deletes, such as those generated by `ExecuteUpdate` and `ExecuteDelete` methods, must target a single database table. However, in EF7, `ExecuteUpdate` and `ExecuteDelete` did not support updates accessing multiple entity types _even when the query ultimately affected a single table_. EF8 removes this limitation. For example, consider a `Customer` entity type with `CustomerInfo` owned type: + + +[!code-csharp[CustomerAndInfo](../../../../samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs?name=CustomerAndInfo)] + +Both of these entity types map to the `Customers` table. However, the following bulk update fails on EF7 because it uses both entity types: + + +[!code-csharp[UpdateWithOwned](../../../../samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs?name=UpdateWithOwned)] + +In EF8, this now translates to the following SQL when using Azure SQL: + +```sql +UPDATE [c] +SET [c].[Name] = [c].[Name] + N'_Tagged', + [c].[CustomerInfo_Tag] = N'Tagged' +FROM [Customers] AS [c] +WHERE [c].[Name] = @__name_0 +``` + +Similarly, instances returned from a `Union` query can be updated as long as the updates all target the same table. For example, we can update any `Customer` with a region of `France`, and at the same time, any `Customer` who has visited a store with the region `France`: + + +[!code-csharp[UpdateWithUnion](../../../../samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs?name=UpdateWithUnion)] + +In EF8, this query generates the following when using Azure SQL: + +```sql +UPDATE [c] +SET [c].[Tag] = N'The French Connection' +FROM [CustomersWithStores] AS [c] +INNER JOIN ( + SELECT [c0].[Id], [c0].[Name], [c0].[Region], [c0].[StoreId], [c0].[Tag] + FROM [CustomersWithStores] AS [c0] + WHERE [c0].[Region] = N'France' + UNION + SELECT [c1].[Id], [c1].[Name], [c1].[Region], [c1].[StoreId], [c1].[Tag] + FROM [Stores] AS [s] + INNER JOIN [CustomersWithStores] AS [c1] ON [s].[Id] = [c1].[StoreId] + WHERE [s].[Region] = N'France' +) AS [t] ON [c].[Id] = [t].[Id] +``` + +As a final example, in EF8, `ExecuteUpdate` can be used to update entities in a TPT hierarchy as long as all updated properties are mapped to the same table. For example, consider these entity types mapped using TPT: + + +[!code-csharp[CustomerTpt](../../../../samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs?name=CustomerTpt)] + +With EF8, the `Note` property can be updated: + + +[!code-csharp[TptUpdateNote](../../../../samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs?name=TptUpdateNote)] + +Or the `Name` property can be updated: + + +[!code-csharp[TptUpdateName](../../../../samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs?name=TptUpdateName)] + +However, EF8 fails attempting to update both the `Name` and the `Note` properties because they are mapped to different tables. For example: + + +[!code-csharp[TptUpdateBoth](../../../../samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs?name=TptUpdateBoth)] + +Throws the following exception: + +```text +The LINQ expression 'DbSet() + .Where(s => s.Name == __name_0) + .ExecuteUpdate(s => s.SetProperty( + propertyExpression: b => b.Note, + valueExpression: "Noted").SetProperty( + propertyExpression: b => b.Name, + valueExpression: b => b.Name + " (Noted)"))' could not be translated. Additional information: Multiple 'SetProperty' invocations refer to different tables ('b => b.Note' and 'b => b.Name'). A single 'ExecuteUpdate' call can only update the columns of a single table. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information. +``` + +## Better use of `IN` queries + +When the `Contains` LINQ operator is used with a subquery, EF Core now generates better queries using SQL `IN` instead of `EXISTS`; aside from producing more readable SQL, in some cases this can result in dramatically faster queries. For example, consider the following LINQ query: + +```csharp +var blogsWithPosts = await context.Blogs + .Where(b => context.Posts.Select(p => p.BlogId).Contains(b.Id)) + .ToListAsync(); +``` + +EF7 generates the following for PostgreSQL: + +```sql +SELECT b."Id", b."Name" + FROM "Blogs" AS b + WHERE EXISTS ( + SELECT 1 + FROM "Posts" AS p + WHERE p."BlogId" = b."Id") +``` + +Since the subquery references the external `Blogs` table (via `b."Id"`), this is a _correlated subquery_, meaning that the `Posts` subquery must be executed for each row in the `Blogs` table. In EF8, the following SQL is generated instead: + +```sql +SELECT b."Id", b."Name" + FROM "Blogs" AS b + WHERE b."Id" IN ( + SELECT p."BlogId" + FROM "Posts" AS p + ) +``` + +Since the subquery no longer references `Blogs`, it can be evaluated once, yielding massive performance improvements on most database systems. However, some database systems, most notably SQL Server, the database is able to optimize the first query to the second query so that the performance is the same. + +## Numeric rowversions for SQL Azure/SQL Server + +SQL Server automatic [optimistic concurrency](xref:core/saving/concurrency) is handled using [`rowversion` columns](/sql/t-sql/data-types/rowversion-transact-sql). A `rowversion` is an 8-byte opaque value passed between database, client, and server. By default, SqlClient exposes `rowversion` types as `byte[]`, despite mutable reference types being a bad match for `rowversion` semantics. In EF8, it is easy instead map `rowversion` columns to `long` or `ulong` properties. For example: + +```csharp +modelBuilder.Entity() + .Property(e => e.RowVersion) + .HasConversion() + .IsRowVersion(); +``` + +## Parentheses elimination + +Generating readable SQL is an important goal for EF Core. In EF8, the generated SQL is more readable through automatic elimination of unneeded parenthesis. For example, the following LINQ query: + +```csharp +await ctx.Customers + .Where(c => c.Id * 3 + 2 > 0 && c.FirstName != null || c.LastName != null) + .ToListAsync(); +``` + +Translates to the following Azure SQL when using EF7: + +```sql +SELECT [c].[Id], [c].[City], [c].[FirstName], [c].[LastName], [c].[Street] +FROM [Customers] AS [c] +WHERE ((([c].[Id] * 3) + 2) > 0 AND ([c].[FirstName] IS NOT NULL)) OR ([c].[LastName] IS NOT NULL) +``` + +Which has been improved to the following when using EF8: + +```sql +SELECT [c].[Id], [c].[City], [c].[FirstName], [c].[LastName], [c].[Street] +FROM [Customers] AS [c] +WHERE ([c].[Id] * 3 + 2 > 0 AND [c].[FirstName] IS NOT NULL) OR [c].[LastName] IS NOT NULL +``` + +## Specific opt-out for RETURNING/OUTPUT clause + +EF7 changed the default update SQL to use `RETURNING`/`OUTPUT` for fetching back database-generated columns. Some cases where identified where this does not work, and so EF8 introduces explicit opt-outs for this behavior. + +For example, to opt-out of `OUTPUT` when using the SQL Server/Azure SQL provider: + +```csharp + modelBuilder.Entity().ToTable(tb => tb.UseSqlOutputClause(false)); +``` + +Or to opt-out of `RETURNING` when using the SQLite provider: + +```csharp + modelBuilder.Entity().ToTable(tb => tb.UseSqlReturningClause(false)); +``` + +## Other minor changes + +In addition to the enhancements described above, there have been many smaller changes made to EF8. This includes: + +- [NativeAOT/trimming compatibility for Microsoft.Data.Sqlite](https://github.com/dotnet/efcore/issues/29725) +- [Allow Multi-region or Application Preferred Regions in EF Core Cosmos](https://github.com/dotnet/efcore/issues/29424) +- [SQLite: Add EF.Functions.Unhex](https://github.com/dotnet/efcore/issues/31355) +- [SQL Server Index options SortInTempDB and DataCompression](https://github.com/dotnet/efcore/issues/30408) +- [Allow 'unsharing' connection between contexts](https://github.com/dotnet/efcore/issues/30704) +- [Add Generic version of EntityTypeConfiguration Attribute](https://github.com/dotnet/efcore/issues/30072) +- [Query: add support for projecting JSON entities that have been composed on](https://github.com/dotnet/efcore/issues/31365) +- [Remove unneeded subquery and projection when using ordering without limit/offset in set operations](https://github.com/dotnet/efcore/issues/30684) +- [Allow pooling DbContext with singleton services](https://github.com/dotnet/efcore/issues/27752) +- [Optional RestartSequenceOperation.StartValue](https://github.com/dotnet/efcore/issues/26560) +- [Allow UseSequence and HiLo on non-key properties](https://github.com/dotnet/efcore/issues/29758) +- [Provide more information when 'No DbContext was found' error is generated](https://github.com/dotnet/efcore/issues/18715) +- [Pass query tracking behavior to materialization interceptor](https://github.com/dotnet/efcore/issues/29910) +- [Use case-insensitive string key comparisons on SQL Server](https://github.com/dotnet/efcore/issues/27526) +- [Allow value converters to change the DbType](https://github.com/dotnet/efcore/issues/24771) +- [Resolve application services in EF services](https://github.com/dotnet/efcore/issues/13540) +- [Allow transfer of ownership of DbConnection from application to DbContext](https://github.com/dotnet/efcore/issues/24199) diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index e0d2cbf85e..91b17d1715 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -32,9 +32,9 @@ href: core/index.md - name: "The plan for EF Core 8 (EF8)" href: /ef/core/what-is-new/ef-core-8.0/plan - - name: "What's new in EF Core 8.0 (EF8)" + - name: "What's new in EF Core 8 (EF8)" href: /ef/core/what-is-new/ef-core-8.0/whatsnew - - name: "Breaking changes in EF Core 8.0 (EF8)" + - name: "Breaking changes in EF Core 8 (EF8)" href: /ef/core/what-is-new/ef-core-8.0/breaking-changes - name: Getting started items: diff --git a/samples/core/Benchmarks/Benchmarks.csproj b/samples/core/Benchmarks/Benchmarks.csproj index dd1d25425e..1fd25c6828 100644 --- a/samples/core/Benchmarks/Benchmarks.csproj +++ b/samples/core/Benchmarks/Benchmarks.csproj @@ -7,7 +7,7 @@ - - + + diff --git a/samples/core/CascadeDeletes/CascadeDeletes.csproj b/samples/core/CascadeDeletes/CascadeDeletes.csproj index c110d669ce..39d7a1f235 100644 --- a/samples/core/CascadeDeletes/CascadeDeletes.csproj +++ b/samples/core/CascadeDeletes/CascadeDeletes.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/samples/core/ChangeTracking/AccessingTrackedEntities/AccessingTrackedEntities.csproj b/samples/core/ChangeTracking/AccessingTrackedEntities/AccessingTrackedEntities.csproj index 88b2a16b12..fcfafd76c8 100644 --- a/samples/core/ChangeTracking/AccessingTrackedEntities/AccessingTrackedEntities.csproj +++ b/samples/core/ChangeTracking/AccessingTrackedEntities/AccessingTrackedEntities.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/samples/core/ChangeTracking/AdditionalChangeTrackingFeatures/AdditionalChangeTrackingFeatures.csproj b/samples/core/ChangeTracking/AdditionalChangeTrackingFeatures/AdditionalChangeTrackingFeatures.csproj index 88b2a16b12..fcfafd76c8 100644 --- a/samples/core/ChangeTracking/AdditionalChangeTrackingFeatures/AdditionalChangeTrackingFeatures.csproj +++ b/samples/core/ChangeTracking/AdditionalChangeTrackingFeatures/AdditionalChangeTrackingFeatures.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/samples/core/ChangeTracking/ChangeDetectionAndNotifications/ChangeDetectionAndNotifications.csproj b/samples/core/ChangeTracking/ChangeDetectionAndNotifications/ChangeDetectionAndNotifications.csproj index 155a162a6a..01be6655bf 100644 --- a/samples/core/ChangeTracking/ChangeDetectionAndNotifications/ChangeDetectionAndNotifications.csproj +++ b/samples/core/ChangeTracking/ChangeDetectionAndNotifications/ChangeDetectionAndNotifications.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/samples/core/ChangeTracking/ChangeTrackerDebugging/ChangeTrackerDebugging.csproj b/samples/core/ChangeTracking/ChangeTrackerDebugging/ChangeTrackerDebugging.csproj index 88b2a16b12..fcfafd76c8 100644 --- a/samples/core/ChangeTracking/ChangeTrackerDebugging/ChangeTrackerDebugging.csproj +++ b/samples/core/ChangeTracking/ChangeTrackerDebugging/ChangeTrackerDebugging.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/samples/core/ChangeTracking/ChangeTrackingInEFCore/ChangeTrackingInEFCore.csproj b/samples/core/ChangeTracking/ChangeTrackingInEFCore/ChangeTrackingInEFCore.csproj index 88b2a16b12..fcfafd76c8 100644 --- a/samples/core/ChangeTracking/ChangeTrackingInEFCore/ChangeTrackingInEFCore.csproj +++ b/samples/core/ChangeTracking/ChangeTrackingInEFCore/ChangeTrackingInEFCore.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/samples/core/ChangeTracking/ChangingFKsAndNavigations/ChangingFKsAndNavigations.csproj b/samples/core/ChangeTracking/ChangingFKsAndNavigations/ChangingFKsAndNavigations.csproj index 88b2a16b12..fcfafd76c8 100644 --- a/samples/core/ChangeTracking/ChangingFKsAndNavigations/ChangingFKsAndNavigations.csproj +++ b/samples/core/ChangeTracking/ChangingFKsAndNavigations/ChangingFKsAndNavigations.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/samples/core/ChangeTracking/IdentityResolutionInEFCore/IdentityResolutionInEFCore.csproj b/samples/core/ChangeTracking/IdentityResolutionInEFCore/IdentityResolutionInEFCore.csproj index ef13cadf99..d84d82edfc 100644 --- a/samples/core/ChangeTracking/IdentityResolutionInEFCore/IdentityResolutionInEFCore.csproj +++ b/samples/core/ChangeTracking/IdentityResolutionInEFCore/IdentityResolutionInEFCore.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/samples/core/Cosmos/Cosmos.csproj b/samples/core/Cosmos/Cosmos.csproj index 7cd1ec09cf..8539b9f9df 100644 --- a/samples/core/Cosmos/Cosmos.csproj +++ b/samples/core/Cosmos/Cosmos.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/core/DbContextPooling/DbContextPooling.csproj b/samples/core/DbContextPooling/DbContextPooling.csproj index c66b1d02e1..61b9c7923c 100644 --- a/samples/core/DbContextPooling/DbContextPooling.csproj +++ b/samples/core/DbContextPooling/DbContextPooling.csproj @@ -5,6 +5,6 @@ Samples - + diff --git a/samples/core/GetStarted/EFGetStarted.csproj b/samples/core/GetStarted/EFGetStarted.csproj index adbe933bb9..3c56604be5 100644 --- a/samples/core/GetStarted/EFGetStarted.csproj +++ b/samples/core/GetStarted/EFGetStarted.csproj @@ -7,8 +7,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/samples/core/Intro/Intro.csproj b/samples/core/Intro/Intro.csproj index 43c629037c..457fe7c0dd 100644 --- a/samples/core/Intro/Intro.csproj +++ b/samples/core/Intro/Intro.csproj @@ -7,8 +7,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/samples/core/Miscellaneous/Async/Async.csproj b/samples/core/Miscellaneous/Async/Async.csproj index bc058823cb..68695caf3c 100644 --- a/samples/core/Miscellaneous/Async/Async.csproj +++ b/samples/core/Miscellaneous/Async/Async.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Miscellaneous/AsyncWithSystemInteractive/AsyncWithSystemInteractive.csproj b/samples/core/Miscellaneous/AsyncWithSystemInteractive/AsyncWithSystemInteractive.csproj index 15fb0b884c..7bf753d26b 100644 --- a/samples/core/Miscellaneous/AsyncWithSystemInteractive/AsyncWithSystemInteractive.csproj +++ b/samples/core/Miscellaneous/AsyncWithSystemInteractive/AsyncWithSystemInteractive.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Miscellaneous/CachingInterception/CachingInterception.csproj b/samples/core/Miscellaneous/CachingInterception/CachingInterception.csproj index 2fe9c733d5..a6f8f3ff5b 100644 --- a/samples/core/Miscellaneous/CachingInterception/CachingInterception.csproj +++ b/samples/core/Miscellaneous/CachingInterception/CachingInterception.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/Collations/Collations.csproj b/samples/core/Miscellaneous/Collations/Collations.csproj index 3ca005b072..326b6b0f6a 100644 --- a/samples/core/Miscellaneous/Collations/Collations.csproj +++ b/samples/core/Miscellaneous/Collations/Collations.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Miscellaneous/CommandInterception/CommandInterception.csproj b/samples/core/Miscellaneous/CommandInterception/CommandInterception.csproj index 1bec7fbadb..ff1e4880e7 100644 --- a/samples/core/Miscellaneous/CommandInterception/CommandInterception.csproj +++ b/samples/core/Miscellaneous/CommandInterception/CommandInterception.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/CommandLine/CommandLine.csproj b/samples/core/Miscellaneous/CommandLine/CommandLine.csproj index 10f611f836..e7433bff38 100644 --- a/samples/core/Miscellaneous/CommandLine/CommandLine.csproj +++ b/samples/core/Miscellaneous/CommandLine/CommandLine.csproj @@ -5,8 +5,8 @@ - - + + diff --git a/samples/core/Miscellaneous/CompiledModels/CompiledModels.csproj b/samples/core/Miscellaneous/CompiledModels/CompiledModels.csproj index 72a4a0033d..54d2e90c19 100644 --- a/samples/core/Miscellaneous/CompiledModels/CompiledModels.csproj +++ b/samples/core/Miscellaneous/CompiledModels/CompiledModels.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Miscellaneous/ConfiguringDbContext/ConfiguringDbContext.csproj b/samples/core/Miscellaneous/ConfiguringDbContext/ConfiguringDbContext.csproj index 36c69ce9cf..fb34b81e0b 100644 --- a/samples/core/Miscellaneous/ConfiguringDbContext/ConfiguringDbContext.csproj +++ b/samples/core/Miscellaneous/ConfiguringDbContext/ConfiguringDbContext.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/core/Miscellaneous/ConnectionInterception/ConnectionInterception.csproj b/samples/core/Miscellaneous/ConnectionInterception/ConnectionInterception.csproj index 4b56a93ad2..f063051d2b 100644 --- a/samples/core/Miscellaneous/ConnectionInterception/ConnectionInterception.csproj +++ b/samples/core/Miscellaneous/ConnectionInterception/ConnectionInterception.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Miscellaneous/ConnectionResiliency/ConnectionResiliency.csproj b/samples/core/Miscellaneous/ConnectionResiliency/ConnectionResiliency.csproj index 35d2ef5da7..3d74d7d685 100644 --- a/samples/core/Miscellaneous/ConnectionResiliency/ConnectionResiliency.csproj +++ b/samples/core/Miscellaneous/ConnectionResiliency/ConnectionResiliency.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Miscellaneous/DiagnosticListeners/DiagnosticListeners.csproj b/samples/core/Miscellaneous/DiagnosticListeners/DiagnosticListeners.csproj index 2fe9c733d5..a6f8f3ff5b 100644 --- a/samples/core/Miscellaneous/DiagnosticListeners/DiagnosticListeners.csproj +++ b/samples/core/Miscellaneous/DiagnosticListeners/DiagnosticListeners.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/Events/Events.csproj b/samples/core/Miscellaneous/Events/Events.csproj index 2fe9c733d5..a6f8f3ff5b 100644 --- a/samples/core/Miscellaneous/Events/Events.csproj +++ b/samples/core/Miscellaneous/Events/Events.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/Logging/Logging/Logging.csproj b/samples/core/Miscellaneous/Logging/Logging/Logging.csproj index 12bc7d4ded..adf2b27836 100644 --- a/samples/core/Miscellaneous/Logging/Logging/Logging.csproj +++ b/samples/core/Miscellaneous/Logging/Logging/Logging.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Miscellaneous/Logging/SimpleLogging/SimpleLogging.csproj b/samples/core/Miscellaneous/Logging/SimpleLogging/SimpleLogging.csproj index 446450d307..bb6287286b 100755 --- a/samples/core/Miscellaneous/Logging/SimpleLogging/SimpleLogging.csproj +++ b/samples/core/Miscellaneous/Logging/SimpleLogging/SimpleLogging.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/samples/core/Miscellaneous/Multitenancy/MultiDb/MultiDb.csproj b/samples/core/Miscellaneous/Multitenancy/MultiDb/MultiDb.csproj index 583ca92722..6368edd32e 100644 --- a/samples/core/Miscellaneous/Multitenancy/MultiDb/MultiDb.csproj +++ b/samples/core/Miscellaneous/Multitenancy/MultiDb/MultiDb.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/Multitenancy/SingleDbSingleTable/SingleDbSingleTable.csproj b/samples/core/Miscellaneous/Multitenancy/SingleDbSingleTable/SingleDbSingleTable.csproj index 583ca92722..6368edd32e 100644 --- a/samples/core/Miscellaneous/Multitenancy/SingleDbSingleTable/SingleDbSingleTable.csproj +++ b/samples/core/Miscellaneous/Multitenancy/SingleDbSingleTable/SingleDbSingleTable.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/NewInEFCore6.Cosmos.csproj b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/NewInEFCore6.Cosmos.csproj index 3bd01cebed..25923d0177 100644 --- a/samples/core/Miscellaneous/NewInEFCore6.Cosmos/NewInEFCore6.Cosmos.csproj +++ b/samples/core/Miscellaneous/NewInEFCore6.Cosmos/NewInEFCore6.Cosmos.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Miscellaneous/NewInEFCore6/NewInEFCore6.csproj b/samples/core/Miscellaneous/NewInEFCore6/NewInEFCore6.csproj index 0c8e3a9201..04eec172fa 100644 --- a/samples/core/Miscellaneous/NewInEFCore6/NewInEFCore6.csproj +++ b/samples/core/Miscellaneous/NewInEFCore6/NewInEFCore6.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/samples/core/Miscellaneous/NewInEFCore7/ExecuteUpdateSample.cs b/samples/core/Miscellaneous/NewInEFCore7/ExecuteUpdateSample.cs index a6d4e2cbe0..8f066a011d 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/ExecuteUpdateSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/ExecuteUpdateSample.cs @@ -48,9 +48,6 @@ private static async Task ExecuteUpdateTest() await UpdateTagsOnOldPosts(); - // https://github.com/dotnet/efcore/issues/28921 (EF.Default doesn't work for value types) - // await ResetPostPublishedOnToDefault(); - Console.WriteLine(); } @@ -160,30 +157,6 @@ await context.Tags Console.WriteLine(); } - private static async Task ResetPostPublishedOnToDefault() - where TContext : BlogsContext, new() - { - await using var context = new TContext(); - await context.Database.BeginTransactionAsync(); - - Console.WriteLine("Reset PublishedOn on posts to its default value"); - Console.WriteLine( - $"Posts before update: {string.Join(", ", await context.Posts.AsNoTracking().Select(e => "'..." + e.Title.Substring(e.Title.Length - 12) + "' " + e.PublishedOn.Date).ToListAsync())}"); - Console.WriteLine(); - - // context.LoggingEnabled = true; - // await context.Set() - // .ExecuteUpdateAsync( - // setPropertyCalls => setPropertyCalls - // .SetProperty(post => post.PublishedOn, post => EF.Default())); - // context.LoggingEnabled = false; - - Console.WriteLine(); - Console.WriteLine( - $"Posts after update: {string.Join(", ", await context.Posts.AsNoTracking().Select(e => "'..." + e.Title.Substring(e.Title.Length - 12) + "' " + e.PublishedOn.Date).ToListAsync())}"); - Console.WriteLine(); - } - private static void PrintSampleName([CallerMemberName] string? methodName = null) { Console.WriteLine($">>>> Sample: {methodName}"); diff --git a/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs b/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs index c285e06ed1..979d833dcb 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore7/ModelBuildingSample.cs @@ -193,58 +193,56 @@ await context.AddRangeAsync( Console.WriteLine(); Console.WriteLine("Historical data for Rainbow Dash:"); - // GitHub Issue https://github.com/dotnet/efcore/issues/29156 - // #region TemporalAll - // var history = await context - // .Employees - // .TemporalAll() - // .Where(e => e.Name == "Rainbow Dash") - // .OrderBy(e => EF.Property(e, "PeriodStart")) - // .Select( - // e => new - // { - // Employee = e, - // PeriodStart = EF.Property(e, "PeriodStart"), - // PeriodEnd = EF.Property(e, "PeriodEnd") - // }) - // .ToListAsync(); - // - // foreach (var pointInTime in history) - // { - // Console.WriteLine( - // $" Employee {pointInTime.Employee.Name} was '{pointInTime.Employee.Info.Position}' from {pointInTime.PeriodStart} to {pointInTime.PeriodEnd}"); - // } - // #endregion + #region TemporalAll + var history = await context + .Employees + .TemporalAll() + .Where(e => e.Name == "Rainbow Dash") + .OrderBy(e => EF.Property(e, "PeriodStart")) + .Select( + e => new + { + Employee = e, + PeriodStart = EF.Property(e, "PeriodStart"), + PeriodEnd = EF.Property(e, "PeriodEnd") + }) + .ToListAsync(); + + foreach (var pointInTime in history) + { + Console.WriteLine( + $" Employee {pointInTime.Employee.Name} was '{pointInTime.Employee.Info.Position}' from {pointInTime.PeriodStart} to {pointInTime.PeriodEnd}"); + } + #endregion } - // GitHub Issue https://github.com/dotnet/efcore/issues/29156 - // await using (var context = new EntitySplittingContext()) - // { - // Console.WriteLine(); - // Console.WriteLine($"Historical data for Rainbow Dash between {timeStamp2} and {timeStamp3}:"); - // - // #region TemporalBetween - // var history = await context - // .Employees - // .TemporalBetween(timeStamp2, timeStamp3) - // .Where(e => e.Name == "Rainbow Dash") - // .OrderBy(e => EF.Property(e, "PeriodStart")) - // .Select( - // e => new - // { - // Employee = e, - // PeriodStart = EF.Property(e, "PeriodStart"), - // PeriodEnd = EF.Property(e, "PeriodEnd") - // }) - // .ToListAsync(); - // #endregion - // - // foreach (var pointInTime in history) - // { - // Console.WriteLine( - // $" Employee {pointInTime.Employee.Name} was '{pointInTime.Employee.Info.Position}' from {pointInTime.PeriodStart} to {pointInTime.PeriodEnd}"); - // } - // } + await using (var context = new EntitySplittingContext()) + { + Console.WriteLine(); + Console.WriteLine($"Historical data for Rainbow Dash between {timeStamp2} and {timeStamp3}:"); + + #region TemporalBetween + var history = await context + .Employees + .TemporalBetween(timeStamp2, timeStamp3) + .Where(e => e.Name == "Rainbow Dash") + .OrderBy(e => EF.Property(e, "PeriodStart")) + .Select( + e => new + { + Employee = e, + PeriodStart = EF.Property(e, "PeriodStart"), + PeriodEnd = EF.Property(e, "PeriodEnd") + }) + .ToListAsync(); + #endregion + + foreach (var pointInTime in history) + { + Console.WriteLine( + $" Employee {pointInTime.Employee.Name} was '{pointInTime.Employee.Info.Position}' from {pointInTime.PeriodStart} to {pointInTime.PeriodEnd}"); + } + } await using (var context = new EntitySplittingContext()) { @@ -518,7 +516,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) }); }); #endregion - + #region LinkingForeignKey modelBuilder.Entity() .HasOne() diff --git a/samples/core/Miscellaneous/NewInEFCore7/NewInEFCore7.csproj b/samples/core/Miscellaneous/NewInEFCore7/NewInEFCore7.csproj index 8cdc440a9e..3a5ae50fa2 100644 --- a/samples/core/Miscellaneous/NewInEFCore7/NewInEFCore7.csproj +++ b/samples/core/Miscellaneous/NewInEFCore7/NewInEFCore7.csproj @@ -9,13 +9,13 @@ - - - - - - - + + + + + + + diff --git a/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs b/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs new file mode 100644 index 0000000000..f070317aa8 --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore8/DefaultConstraintSample.cs @@ -0,0 +1,196 @@ +namespace NewInEfCore8; + +public static class DefaultConstraintSample +{ + public static Task Insert_rows_using_database_default_constraint() + => DefaultConstraintTest(sqlite: false); + + public static Task Insert_rows_using_database_default_constraint_SQLite() + => DefaultConstraintTest(sqlite: true); + + public static async Task DefaultConstraintTest(bool sqlite) + { + PrintSampleName(); + + await using var context = new DatabaseDefaultsContext(useSqlite: sqlite); + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); + + context.ChangeTracker.Clear(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with int database default:"); + + context.AddRange(new User(), new User { Credits = 77 }, new User { Credits = 0 }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with enum database default:"); + + context.AddRange(new Course(), new Course { Level = Level.Intermediate }, new Course { Level = Level.Beginner }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with bool database default:"); + + context.AddRange(new Account(), new Account { IsActive = true }, new Account { IsActive = false }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with int database default, sentinel configured:"); + + context.AddRange(new UserWithSentinel(), new UserWithSentinel { Credits = 77 }, new UserWithSentinel { Credits = 0 }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with enum database default, sentinel configured:"); + + context.AddRange(new CourseWithSentinel(), new CourseWithSentinel { Level = Level.Intermediate }, new CourseWithSentinel { Level = Level.Beginner }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with bool database default, sentinel configured:"); + + context.AddRange(new AccountWithSentinel(), new AccountWithSentinel { IsActive = true }, new AccountWithSentinel { IsActive = false }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with int database default, nullable backing field:"); + + context.AddRange(new UserWithNullableBackingField(), new UserWithNullableBackingField { Credits = 77 }, new UserWithNullableBackingField { Credits = 0 }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with enum database default, nullable backing field:"); + + context.AddRange(new CourseWithNullableBackingField(), new CourseWithNullableBackingField { Level = Level.Intermediate }, new CourseWithNullableBackingField { Level = Level.Beginner }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + Console.WriteLine("Insert user property with bool database default, nullable backing field:"); + + context.AddRange(new AccountWithNullableBackingField(), new AccountWithNullableBackingField { IsActive = true }, new AccountWithNullableBackingField { IsActive = false }); + await context.SaveChangesAsync(); + + Console.WriteLine(); + } + + + private static void PrintSampleName([CallerMemberName] string? methodName = null) + { + Console.WriteLine($">>>> Sample: {methodName}"); + Console.WriteLine(); + } + + public class User + { + public int Id { get; set; } + public int Credits { get; set; } + } + + public class Account + { + public int Id { get; set; } + public bool IsActive { get; set; } + } + + public class Course + { + public int Id { get; set; } + public Level Level { get; set; } + } + + public class UserWithSentinel + { + public int Id { get; set; } + public int Credits { get; set; } = -1; + } + + public class AccountWithSentinel + { + public int Id { get; set; } + public bool IsActive { get; set; } = true; + } + + public class CourseWithSentinel + { + public int Id { get; set; } + public Level Level { get; set; } = Level.Unspecified; + } + + public class UserWithNullableBackingField + { + public int Id { get; set; } + + private int? _credits; + + public int Credits + { + get => _credits ?? 0; + set => _credits = value; + } + } + + public class AccountWithNullableBackingField + { + public int Id { get; set; } + + private bool? _isActive; + + public bool IsActive + { + get => _isActive ?? false; + set => _isActive = value; + } + } + + public class CourseWithNullableBackingField + { + public int Id { get; set; } + + private Level? _level; + + public Level Level + { + get => _level ?? Level.Unspecified; + set => _level = value; + } + } + + public enum Level + { + Beginner, + Intermediate, + Advanced, + Unspecified + } + + public class DatabaseDefaultsContext(bool useSqlite = false) : DbContext + { + public bool UseSqlite { get; } = useSqlite; + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => (UseSqlite + ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") + : optionsBuilder.UseSqlServer( + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}", + sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) + .EnableSensitiveDataLogging() + .LogTo(Console.WriteLine, LogLevel.Information); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().Property(e => e.IsActive).HasDefaultValueSql("1"); + modelBuilder.Entity().Property(e => e.Credits).HasDefaultValue(100); + modelBuilder.Entity().Property(e => e.Level).HasDefaultValue(Level.Intermediate); + + modelBuilder.Entity().Property(e => e.IsActive).HasDefaultValueSql("1").HasSentinel(true); + modelBuilder.Entity().Property(e => e.Credits).HasDefaultValue(100).HasSentinel(-1); + modelBuilder.Entity().Property(e => e.Level).HasDefaultValue(Level.Intermediate).HasSentinel(Level.Unspecified); + + modelBuilder.Entity().Property(e => e.IsActive).HasDefaultValueSql("1"); + modelBuilder.Entity().Property(e => e.Credits).HasDefaultValue(100); + modelBuilder.Entity().Property(e => e.Level).HasDefaultValue(Level.Intermediate); + } + } +} diff --git a/samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs b/samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs new file mode 100644 index 0000000000..8957425a1f --- /dev/null +++ b/samples/core/Miscellaneous/NewInEFCore8/ExecuteUpdateDeleteSample.cs @@ -0,0 +1,171 @@ +namespace NewInEfCore8; + +public static class ExecuteUpdateDeleteSample +{ + public static Task ExecuteUpdate_ExecuteDelete_with_multiple_entities_targeting_one_table() + => ExecuteUpdateDeleteTest(sqlite: false); + + public static Task ExecuteUpdate_ExecuteDelete_with_multiple_entities_targeting_one_table_SQLite() + => ExecuteUpdateDeleteTest(sqlite: true); + + public static async Task ExecuteUpdateDeleteTest(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 = "France" } }, Region = "France" }, + new Customer { Name = "Smokey", CustomerInfo = new() { Tag = "EF" } }, + new CustomerTpt { Name = "Willow" }, + new SpecialCustomerTpt { Name = "Olive" }); + + await context.SaveChangesAsync(); + context.ChangeTracker.Clear(); + + Console.WriteLine(); + Console.WriteLine("Update properties of owner and owned type mapped to the same table:"); + + var name = "Smokey"; + + #region UpdateWithOwned + await context.Customers + .Where(e => e.Name == name) + .ExecuteUpdateAsync( + s => s.SetProperty(b => b.CustomerInfo.Tag, "Tagged") + .SetProperty(b => b.Name, b => b.Name + "_Tagged")); + #endregion + + Console.WriteLine(); + Console.WriteLine("Update properties of entities returned by union but targeting a single table:"); + + #region UpdateWithUnion + await context.CustomersWithStores + .Where(e => e.Region == "France") + .Union(context.Stores.Where(e => e.Region == "France").SelectMany(e => e.Customers)) + .ExecuteUpdateAsync(s => s.SetProperty(b => b.Tag, "The French Connection")); + #endregion + + + Console.WriteLine(); + Console.WriteLine("Update properties of a single table in a TPT hierarchy:"); + + #region TptUpdateName + await context.TptSpecialCustomers + .Where(e => e.Name == name) + .ExecuteUpdateAsync(s => s.SetProperty(b => b.Name, b => b.Name + " (Noted)")); + #endregion + + #region TptUpdateNote + await context.TptSpecialCustomers + .Where(e => e.Name == name) + .ExecuteUpdateAsync(s => s.SetProperty(b => b.Note, "Noted")); + #endregion + + try + { + Console.WriteLine(); + Console.WriteLine("Attempt to update properties of two tables in a TPT hierarchy:"); + + #region TptUpdateBoth + await context.TptSpecialCustomers + .Where(e => e.Name == name) + .ExecuteUpdateAsync(s => s.SetProperty(b => b.Note, "Noted") + .SetProperty(b => b.Name, b => b.Name + " (Noted)")); + #endregion + } + catch (InvalidOperationException e) + { + Console.WriteLine(e.Message); + } + + Console.WriteLine(); + Console.WriteLine("Delete owner with owned type mapped to the same table:"); + + await context.Customers.Where(e => e.Name == name).ExecuteDeleteAsync(); + + Console.WriteLine(); + Console.WriteLine("Delete entities returned by union but targeting a single table:"); + + await context.CustomersWithStores + .Where(e => e.Region == "France") + .Union(context.Stores.Where(e => e.Region == "France").SelectMany(e => e.Customers)) + .ExecuteDeleteAsync(); + + Console.WriteLine(); + } + + + private static void PrintSampleName([CallerMemberName] string? methodName = null) + { + Console.WriteLine($">>>> Sample: {methodName}"); + Console.WriteLine(); + } + + #region CustomerTpt + [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; } + } + #endregion + + #region CustomerAndInfo + public class Customer + { + public int Id { get; set; } + public required string Name { get; set; } + public required CustomerInfo CustomerInfo { get; set; } + } + + [Owned] + public class CustomerInfo + { + public string? Tag { get; set; } + } + #endregion + + 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 class CustomerContext(bool useSqlite = false) : DbContext + { + public bool UseSqlite { get; } = useSqlite; + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => (UseSqlite + ? optionsBuilder.UseSqlite(@$"DataSource={GetType().Name}.db") + : optionsBuilder.UseSqlServer( + @$"Server=(localdb)\mssqllocaldb;Database={GetType().Name}", + sqlServerOptionsBuilder => sqlServerOptionsBuilder.UseNetTopologySuite())) + .EnableSensitiveDataLogging() + .LogTo(Console.WriteLine, LogLevel.Information); + + 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/NewInEFCore8/JsonColumnsSample.cs b/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs index da0871173a..f4f4728b50 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/JsonColumnsSample.cs @@ -203,6 +203,23 @@ private static async Task JsonColumnsTest() Console.WriteLine(); + #region PostsWithSearchTerms + var searchTerms = new[] { "Search #2", "Search #3", "Search #5", "Search #8", "Search #13", "Search #21", "Search #34" }; + + var postsWithSearchTerms = await context.Posts + .Where(post => post.Metadata!.TopSearches.Any(s => searchTerms.Contains(s.Term))) + .ToListAsync(); + #endregion + + Console.WriteLine(); + foreach (var postWithTerm in postsWithSearchTerms) + { + Console.WriteLine( + $"Post {postWithTerm.Id} with terms '{string.Join("', '", postWithTerm.Metadata!.TopSearches.Select(s => s.Term))}'"); + } + + Console.WriteLine(); + context.ChangeTracker.Clear(); Console.WriteLine("Updating a 'Contact' JSON document..."); diff --git a/samples/core/Miscellaneous/NewInEFCore8/NewInEFCore8.csproj b/samples/core/Miscellaneous/NewInEFCore8/NewInEFCore8.csproj index 785d17ae61..9266e61830 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/NewInEFCore8.csproj +++ b/samples/core/Miscellaneous/NewInEFCore8/NewInEFCore8.csproj @@ -10,15 +10,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs b/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs index ae7ee16223..61dbac5a5e 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/PrimitiveCollectionsSample.cs @@ -148,7 +148,8 @@ public class PrimitiveCollections public List Booleans { get; set; } = null!; public List Urls { get; set; } = null!; - public MyCollection SomeInts { get; set; } = null!; + // https://github.com/dotnet/efcore/issues/32055 + // public MyCollection SomeInts { get; set; } = null!; public List GetOnlyInts { get; } = new(); @@ -316,7 +317,7 @@ public async Task Seed() 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 }, + //SomeInts = new() { 1, 2, 3 }, // DddIds = new() { new(1), new(2), new(3) } }); diff --git a/samples/core/Miscellaneous/NewInEFCore8/Program.cs b/samples/core/Miscellaneous/NewInEFCore8/Program.cs index ce14f81cd9..02c38291e6 100644 --- a/samples/core/Miscellaneous/NewInEFCore8/Program.cs +++ b/samples/core/Miscellaneous/NewInEFCore8/Program.cs @@ -23,8 +23,7 @@ public static async Task Main() await RawSqlSample.SqlQuery_for_unmapped_types(); - // https://github.com/dotnet/efcore/issues/31597 - // await LazyLoadingSample.Lazy_loading_for_no_tracking_queries(); + await LazyLoadingSample.Lazy_loading_for_no_tracking_queries(); await InheritanceSample.Discriminator_length_TPH(); @@ -43,5 +42,11 @@ public static async Task Main() await PrimitiveCollectionsInJsonSample.Queries_using_primitive_collections_in_JSON_documents_SQLite(); await PrimitiveCollectionToTableSample.Queries_against_a_table_wrapping_a_primitive_type(); + + await DefaultConstraintSample.Insert_rows_using_database_default_constraint(); + await DefaultConstraintSample.Insert_rows_using_database_default_constraint_SQLite(); + + await ExecuteUpdateDeleteSample.ExecuteUpdate_ExecuteDelete_with_multiple_entities_targeting_one_table(); + await ExecuteUpdateDeleteSample.ExecuteUpdate_ExecuteDelete_with_multiple_entities_targeting_one_table_SQLite(); } } diff --git a/samples/core/Miscellaneous/NullableReferenceTypes/NullableReferenceTypes.csproj b/samples/core/Miscellaneous/NullableReferenceTypes/NullableReferenceTypes.csproj index ca806712ef..ce86cc8f58 100644 --- a/samples/core/Miscellaneous/NullableReferenceTypes/NullableReferenceTypes.csproj +++ b/samples/core/Miscellaneous/NullableReferenceTypes/NullableReferenceTypes.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Miscellaneous/SaveChangesInterception/SaveChangesInterception.csproj b/samples/core/Miscellaneous/SaveChangesInterception/SaveChangesInterception.csproj index 2fe9c733d5..a6f8f3ff5b 100644 --- a/samples/core/Miscellaneous/SaveChangesInterception/SaveChangesInterception.csproj +++ b/samples/core/Miscellaneous/SaveChangesInterception/SaveChangesInterception.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Modeling/BackingFields/BackingFields.csproj b/samples/core/Modeling/BackingFields/BackingFields.csproj index 6e544018a5..89eac803af 100644 --- a/samples/core/Modeling/BackingFields/BackingFields.csproj +++ b/samples/core/Modeling/BackingFields/BackingFields.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/BulkConfiguration/BulkConfiguration.csproj b/samples/core/Modeling/BulkConfiguration/BulkConfiguration.csproj index b9bf713603..f90f9efb62 100644 --- a/samples/core/Modeling/BulkConfiguration/BulkConfiguration.csproj +++ b/samples/core/Modeling/BulkConfiguration/BulkConfiguration.csproj @@ -9,7 +9,7 @@ - + diff --git a/samples/core/Modeling/ConcurrencyTokens/ConcurrencyTokens.csproj b/samples/core/Modeling/ConcurrencyTokens/ConcurrencyTokens.csproj index 36f9fd024f..7d6f140b54 100644 --- a/samples/core/Modeling/ConcurrencyTokens/ConcurrencyTokens.csproj +++ b/samples/core/Modeling/ConcurrencyTokens/ConcurrencyTokens.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/DataSeeding/DataSeeding.csproj b/samples/core/Modeling/DataSeeding/DataSeeding.csproj index 7b31d69ec6..a166c7e088 100644 --- a/samples/core/Modeling/DataSeeding/DataSeeding.csproj +++ b/samples/core/Modeling/DataSeeding/DataSeeding.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Modeling/DynamicModel/DynamicModel.csproj b/samples/core/Modeling/DynamicModel/DynamicModel.csproj index 194cf54205..18ff91942c 100644 --- a/samples/core/Modeling/DynamicModel/DynamicModel.csproj +++ b/samples/core/Modeling/DynamicModel/DynamicModel.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/EntityProperties/EntityProperties.csproj b/samples/core/Modeling/EntityProperties/EntityProperties.csproj index b634ad1790..1779029a46 100644 --- a/samples/core/Modeling/EntityProperties/EntityProperties.csproj +++ b/samples/core/Modeling/EntityProperties/EntityProperties.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/EntityTypes/EntityTypes.csproj b/samples/core/Modeling/EntityTypes/EntityTypes.csproj index 753f14257e..2ac15c43d4 100644 --- a/samples/core/Modeling/EntityTypes/EntityTypes.csproj +++ b/samples/core/Modeling/EntityTypes/EntityTypes.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/GeneratedProperties/GeneratedProperties.csproj b/samples/core/Modeling/GeneratedProperties/GeneratedProperties.csproj index 16b0bce684..4f9926d3d5 100644 --- a/samples/core/Modeling/GeneratedProperties/GeneratedProperties.csproj +++ b/samples/core/Modeling/GeneratedProperties/GeneratedProperties.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/IndexesAndConstraints/IndexesAndConstraints.csproj b/samples/core/Modeling/IndexesAndConstraints/IndexesAndConstraints.csproj index f57b7ecaa6..6832ce2c32 100644 --- a/samples/core/Modeling/IndexesAndConstraints/IndexesAndConstraints.csproj +++ b/samples/core/Modeling/IndexesAndConstraints/IndexesAndConstraints.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/Inheritance/Inheritance.csproj b/samples/core/Modeling/Inheritance/Inheritance.csproj index c5ebbd8ecf..a88cd6747c 100644 --- a/samples/core/Modeling/Inheritance/Inheritance.csproj +++ b/samples/core/Modeling/Inheritance/Inheritance.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/KeylessEntityTypes/KeylessEntityTypes.csproj b/samples/core/Modeling/KeylessEntityTypes/KeylessEntityTypes.csproj index 51fc744905..05ab1181aa 100644 --- a/samples/core/Modeling/KeylessEntityTypes/KeylessEntityTypes.csproj +++ b/samples/core/Modeling/KeylessEntityTypes/KeylessEntityTypes.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/Keys/Keys.csproj b/samples/core/Modeling/Keys/Keys.csproj index c7a3f85ad5..9310010757 100644 --- a/samples/core/Modeling/Keys/Keys.csproj +++ b/samples/core/Modeling/Keys/Keys.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/Misc/Misc.csproj b/samples/core/Modeling/Misc/Misc.csproj index 36f9fd024f..7d6f140b54 100644 --- a/samples/core/Modeling/Misc/Misc.csproj +++ b/samples/core/Modeling/Misc/Misc.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/OwnedEntities/OwnedEntities.csproj b/samples/core/Modeling/OwnedEntities/OwnedEntities.csproj index 9a0e5a9c7b..2114c13dc8 100644 --- a/samples/core/Modeling/OwnedEntities/OwnedEntities.csproj +++ b/samples/core/Modeling/OwnedEntities/OwnedEntities.csproj @@ -8,11 +8,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/samples/core/Modeling/Relationships/Relationships.csproj b/samples/core/Modeling/Relationships/Relationships.csproj index bdc94ef438..20ed1fb921 100644 --- a/samples/core/Modeling/Relationships/Relationships.csproj +++ b/samples/core/Modeling/Relationships/Relationships.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Modeling/Sequences/Sequences.csproj b/samples/core/Modeling/Sequences/Sequences.csproj index d9ad174cc1..c77a3f73f0 100644 --- a/samples/core/Modeling/Sequences/Sequences.csproj +++ b/samples/core/Modeling/Sequences/Sequences.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/ShadowAndIndexerProperties/ShadowAndIndexerProperties.csproj b/samples/core/Modeling/ShadowAndIndexerProperties/ShadowAndIndexerProperties.csproj index 630df7be59..5099214a9a 100644 --- a/samples/core/Modeling/ShadowAndIndexerProperties/ShadowAndIndexerProperties.csproj +++ b/samples/core/Modeling/ShadowAndIndexerProperties/ShadowAndIndexerProperties.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Modeling/TableSplitting/TableSplitting.csproj b/samples/core/Modeling/TableSplitting/TableSplitting.csproj index f149b9dd08..6ee6113b21 100644 --- a/samples/core/Modeling/TableSplitting/TableSplitting.csproj +++ b/samples/core/Modeling/TableSplitting/TableSplitting.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Modeling/ValueConversions/ValueConversions.csproj b/samples/core/Modeling/ValueConversions/ValueConversions.csproj index fb1e2affb1..2e2e87b595 100644 --- a/samples/core/Modeling/ValueConversions/ValueConversions.csproj +++ b/samples/core/Modeling/ValueConversions/ValueConversions.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Performance/AspNetContextPooling/AspNetContextPooling.csproj b/samples/core/Performance/AspNetContextPooling/AspNetContextPooling.csproj index be72b70767..cc0a52e48a 100644 --- a/samples/core/Performance/AspNetContextPooling/AspNetContextPooling.csproj +++ b/samples/core/Performance/AspNetContextPooling/AspNetContextPooling.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/samples/core/Performance/AspNetContextPoolingWithState/AspNetContextPoolingWithState.csproj b/samples/core/Performance/AspNetContextPoolingWithState/AspNetContextPoolingWithState.csproj index 9808bfb14f..e107293ac6 100644 --- a/samples/core/Performance/AspNetContextPoolingWithState/AspNetContextPoolingWithState.csproj +++ b/samples/core/Performance/AspNetContextPoolingWithState/AspNetContextPoolingWithState.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/samples/core/Performance/Other/Other.csproj b/samples/core/Performance/Other/Other.csproj index 6d23d617ad..65847f0f41 100644 --- a/samples/core/Performance/Other/Other.csproj +++ b/samples/core/Performance/Other/Other.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/ClientEvaluation/ClientEvaluation.csproj b/samples/core/Querying/ClientEvaluation/ClientEvaluation.csproj index 4032bdf11b..7c6272d507 100644 --- a/samples/core/Querying/ClientEvaluation/ClientEvaluation.csproj +++ b/samples/core/Querying/ClientEvaluation/ClientEvaluation.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/ComplexQuery/ComplexQuery.csproj b/samples/core/Querying/ComplexQuery/ComplexQuery.csproj index 4e826dea14..57c040223b 100644 --- a/samples/core/Querying/ComplexQuery/ComplexQuery.csproj +++ b/samples/core/Querying/ComplexQuery/ComplexQuery.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/NullSemantics/NullSemantics.csproj b/samples/core/Querying/NullSemantics/NullSemantics.csproj index e43960761f..f164a1aa2f 100644 --- a/samples/core/Querying/NullSemantics/NullSemantics.csproj +++ b/samples/core/Querying/NullSemantics/NullSemantics.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/core/Querying/Overview/Overview.csproj b/samples/core/Querying/Overview/Overview.csproj index f8f955d54b..63ceb28890 100644 --- a/samples/core/Querying/Overview/Overview.csproj +++ b/samples/core/Querying/Overview/Overview.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/Pagination/Pagination.csproj b/samples/core/Querying/Pagination/Pagination.csproj index 2b2e9bbd49..d5e704682c 100644 --- a/samples/core/Querying/Pagination/Pagination.csproj +++ b/samples/core/Querying/Pagination/Pagination.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/QueryFilters/QueryFilters.csproj b/samples/core/Querying/QueryFilters/QueryFilters.csproj index 1606a414ee..b0eb3ed38b 100644 --- a/samples/core/Querying/QueryFilters/QueryFilters.csproj +++ b/samples/core/Querying/QueryFilters/QueryFilters.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/RelatedData/RelatedData.csproj b/samples/core/Querying/RelatedData/RelatedData.csproj index ecfdea1a80..ace4f1d23d 100644 --- a/samples/core/Querying/RelatedData/RelatedData.csproj +++ b/samples/core/Querying/RelatedData/RelatedData.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/SqlQueries/SqlQueries.csproj b/samples/core/Querying/SqlQueries/SqlQueries.csproj index 825429ef62..3e19393e44 100644 --- a/samples/core/Querying/SqlQueries/SqlQueries.csproj +++ b/samples/core/Querying/SqlQueries/SqlQueries.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/Tags/Tags.csproj b/samples/core/Querying/Tags/Tags.csproj index 6f38cb6382..443e96fd4f 100644 --- a/samples/core/Querying/Tags/Tags.csproj +++ b/samples/core/Querying/Tags/Tags.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Querying/Tracking/Tracking.csproj b/samples/core/Querying/Tracking/Tracking.csproj index 631ccd1ce1..d0fea1b385 100644 --- a/samples/core/Querying/Tracking/Tracking.csproj +++ b/samples/core/Querying/Tracking/Tracking.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Querying/UserDefinedFunctionMapping/UserDefinedFunctionMapping.csproj b/samples/core/Querying/UserDefinedFunctionMapping/UserDefinedFunctionMapping.csproj index 4f9d4c3caf..b488b88200 100644 --- a/samples/core/Querying/UserDefinedFunctionMapping/UserDefinedFunctionMapping.csproj +++ b/samples/core/Querying/UserDefinedFunctionMapping/UserDefinedFunctionMapping.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/samples/core/Saving/Saving.csproj b/samples/core/Saving/Saving.csproj index c7eeb843b9..0d2f88441b 100644 --- a/samples/core/Saving/Saving.csproj +++ b/samples/core/Saving/Saving.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Schemas/Migrations/Migrations.csproj b/samples/core/Schemas/Migrations/Migrations.csproj index 8d10d836ba..700b1069c0 100644 --- a/samples/core/Schemas/Migrations/Migrations.csproj +++ b/samples/core/Schemas/Migrations/Migrations.csproj @@ -5,7 +5,7 @@ - + diff --git a/samples/core/Schemas/ThreeProjectMigrations/WebApplication1.Data/WebApplication1.Data.csproj b/samples/core/Schemas/ThreeProjectMigrations/WebApplication1.Data/WebApplication1.Data.csproj index e005b280bd..6454d0772f 100644 --- a/samples/core/Schemas/ThreeProjectMigrations/WebApplication1.Data/WebApplication1.Data.csproj +++ b/samples/core/Schemas/ThreeProjectMigrations/WebApplication1.Data/WebApplication1.Data.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/core/Schemas/ThreeProjectMigrations/WebApplication1/WebApplication1.csproj b/samples/core/Schemas/ThreeProjectMigrations/WebApplication1/WebApplication1.csproj index 6bf004fe2c..3676f54a2a 100644 --- a/samples/core/Schemas/ThreeProjectMigrations/WebApplication1/WebApplication1.csproj +++ b/samples/core/Schemas/ThreeProjectMigrations/WebApplication1/WebApplication1.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/core/Schemas/TwoProjectMigrations/WorkerService1/WorkerService1.csproj b/samples/core/Schemas/TwoProjectMigrations/WorkerService1/WorkerService1.csproj index ba435aa3e6..adb3a45c4e 100644 --- a/samples/core/Schemas/TwoProjectMigrations/WorkerService1/WorkerService1.csproj +++ b/samples/core/Schemas/TwoProjectMigrations/WorkerService1/WorkerService1.csproj @@ -6,9 +6,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/samples/core/Spatial/SqlServer/SqlServer.csproj b/samples/core/Spatial/SqlServer/SqlServer.csproj index c8433d370e..79f0dce83d 100644 --- a/samples/core/Spatial/SqlServer/SqlServer.csproj +++ b/samples/core/Spatial/SqlServer/SqlServer.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/core/SqlServer/SqlServer.csproj b/samples/core/SqlServer/SqlServer.csproj index e43960761f..f164a1aa2f 100644 --- a/samples/core/SqlServer/SqlServer.csproj +++ b/samples/core/SqlServer/SqlServer.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/core/Testing/BusinessLogic/BusinessLogic.csproj b/samples/core/Testing/BusinessLogic/BusinessLogic.csproj index f05e5cf120..e02ac91f1f 100644 --- a/samples/core/Testing/BusinessLogic/BusinessLogic.csproj +++ b/samples/core/Testing/BusinessLogic/BusinessLogic.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/core/Testing/TestingWithoutTheDatabase/TestingWithoutTheDatabase.csproj b/samples/core/Testing/TestingWithoutTheDatabase/TestingWithoutTheDatabase.csproj index 2825494468..88cfd81fe5 100644 --- a/samples/core/Testing/TestingWithoutTheDatabase/TestingWithoutTheDatabase.csproj +++ b/samples/core/Testing/TestingWithoutTheDatabase/TestingWithoutTheDatabase.csproj @@ -8,8 +8,8 @@ - - + +