Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async conversion for change tracking code samples #4922

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions entity-framework/core/managing-schemas/ensure-created.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,39 @@ uid: core/managing-schemas/ensure-created
---
# Create and Drop APIs

The <xref:Microsoft.EntityFrameworkCore.Storage.IDatabaseCreator.EnsureCreated> and <xref:Microsoft.EntityFrameworkCore.Storage.IDatabaseCreator.EnsureDeleted> methods provide a lightweight alternative to [Migrations](xref:core/managing-schemas/migrations/index) for managing the database schema. These methods are useful in scenarios when the data is transient and can be dropped when the schema changes. For example during prototyping, in tests, or for local caches.
The <xref:Microsoft.EntityFrameworkCore.Storage.IDatabaseCreator.EnsureCreatedAsync*> and <xref:Microsoft.EntityFrameworkCore.Storage.IDatabaseCreator.EnsureDeletedAsync*> methods provide a lightweight alternative to [Migrations](xref:core/managing-schemas/migrations/index) for managing the database schema. These methods are useful in scenarios when the data is transient and can be dropped when the schema changes. For example during prototyping, in tests, or for local caches.

Some providers (especially non-relational ones) don't support Migrations. For these providers, `EnsureCreated` is often the easiest way to initialize the database schema.
Some providers (especially non-relational ones) don't support Migrations. For these providers, `EnsureCreatedAsync` is often the easiest way to initialize the database schema.

> [!WARNING]
> `EnsureCreated` and Migrations don't work well together. If you're using Migrations, don't use `EnsureCreated` to initialize the schema.
> `EnsureCreatedAsync` and Migrations don't work well together. If you're using Migrations, don't use `EnsureCreatedAsync` to initialize the schema.

Transitioning from `EnsureCreated` to Migrations is not a seamless experience. The simplest way to do it is to drop the database and re-create it using Migrations. If you anticipate using migrations in the future, it's best to just start with Migrations instead of using `EnsureCreated`.
Transitioning from `EnsureCreatedAsync` to Migrations is not a seamless experience. The simplest way to do it is to drop the database and re-create it using Migrations. If you anticipate using migrations in the future, it's best to just start with Migrations instead of using `EnsureCreatedAsync`.

## EnsureDeleted
## EnsureDeletedAsync

The `EnsureDeleted` method will drop the database if it exists. If you don't have the appropriate permissions, an exception is thrown.
The `EnsureDeletedAsync` method will drop the database if it exists. If you don't have the appropriate permissions, an exception is thrown.

```csharp
// Drop the database if it exists
dbContext.Database.EnsureDeleted();
await dbContext.Database.EnsureDeletedAsync();
```

## EnsureCreated
## EnsureCreatedAsync

`EnsureCreated` will create the database if it doesn't exist and initialize the database schema. If any tables exist (including tables for another `DbContext` class), the schema won't be initialized.
`EnsureCreatedAsync` will create the database if it doesn't exist and initialize the database schema. If any tables exist (including tables for another `DbContext` class), the schema won't be initialized.

```csharp
// Create the database if it doesn't exist
dbContext.Database.EnsureCreated();
dbContext.Database.EnsureCreatedAsync();
```

> [!TIP]
> Async versions of these methods are also available.

## SQL Script

To get the SQL used by `EnsureCreated`, you can use the <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GenerateCreateScript*> method.
To get the SQL used by `EnsureCreatedAsync`, you can use the <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.GenerateCreateScript*> method.

```csharp
var sql = dbContext.Database.GenerateCreateScript();
Expand Down
10 changes: 5 additions & 5 deletions entity-framework/core/managing-schemas/migrations/applying.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,26 +317,26 @@ It's possible for the application itself to apply migrations programmatically, t
* 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.
* The SQL commands are applied directly by the program, without giving the developer a chance to inspect or modify them. This can be dangerous in a production environment.

To apply migrations programmatically, call `context.Database.Migrate()`. For example, a typical ASP.NET application can do the following:
To apply migrations programmatically, call `context.Database.MigrateAsync()`. For example, a typical ASP.NET application can do the following:

```csharp
public static void Main(string[] args)
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();

using (var scope = host.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
db.Database.Migrate();
await db.Database.MigrateAsync();
}

host.Run();
}
```

Note that `Migrate()` builds on top of the `IMigrator` service, which can be used for more advanced scenarios. Use `myDbContext.GetInfrastructure().GetService<IMigrator>()` to access it.
Note that `MigrateAsync()` builds on top of the `IMigrator` service, which can be used for more advanced scenarios. Use `myDbContext.GetInfrastructure().GetService<IMigrator>()` to access it.

> [!WARNING]
>
> * Carefully consider before using this approach in production. Experience has shown that the simplicity of this deployment strategy is outweighed by the issues it creates. Consider generating SQL scripts from migrations instead.
> * Don't call `EnsureCreated()` before `Migrate()`. `EnsureCreated()` bypasses Migrations to create the schema, which causes `Migrate()` to fail.
> * Don't call `EnsureCreatedAsync()` before `MigrateAsync()`. `EnsureCreatedAsync()` bypasses Migrations to create the schema, which causes `MigrateAsync()` to fail.
4 changes: 2 additions & 2 deletions entity-framework/core/miscellaneous/connection-resiliency.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

## Execution strategies and transactions

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 `SaveChanges()` will be retried as a unit if a transient failure occurs.
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 `BeginTransaction()` 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 shall a failure occur. 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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ Another strategy is to use non-nullable auto-properties, but to initialize them
When dealing with optional relationships, it's possible to encounter compiler warnings where an actual `null` reference exception would be impossible. When translating and executing your LINQ queries, EF Core guarantees that if an optional related entity does not exist, any navigation to it will simply be ignored, rather than throwing. However, the compiler is unaware of this EF Core guarantee, and produces warnings as if the LINQ query were executed in memory, with LINQ to Objects. As a result, it is necessary to use the null-forgiving operator (!) to inform the compiler that an actual `null` value isn't possible:

```csharp
var order = context.Orders
var order = await context.Orders
.Where(o => o.OptionalInfo!.SomeProperty == "foo")
.ToList();
.ToListAsync();
```

A similar issue occurs when including multiple levels of relationships across optional navigations:
Expand Down
4 changes: 2 additions & 2 deletions entity-framework/core/modeling/data-seeding.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ These methods can be set up in the [options configuration step](/ef/core/dbconte

## Custom initialization logic

A straightforward and powerful way to perform data seeding is to use [`DbContext.SaveChanges()`](xref:core/saving/index) before the main application logic begins execution. It is recommended to use `UseSeeding` and `UseAsyncSeeding` for that purpose, however sometimes using these methods is not a good solution. An example scenario is when seeding requires using two different contexts in one transaction. Below is a code sample performing custom initialization in the application directly:
A straightforward and powerful way to perform data seeding is to use [`DbContext.SaveChangesAsync()`](xref:core/saving/index) before the main application logic begins execution. It is recommended to use `UseSeeding` and `UseAsyncSeeding` for that purpose, however sometimes using these methods is not a good solution. An example scenario is when seeding requires using two different contexts in one transaction. Below is a code sample performing custom initialization in the application directly:

[!code-csharp[Main](../../../samples/core/Modeling/DataSeeding/Program.cs?name=CustomSeeding)]

Expand Down Expand Up @@ -85,7 +85,7 @@ Once the data has been added to the model, [migrations](xref:core/managing-schem
> [!TIP]
> If you need to apply migrations as part of an automated deployment you can [create a SQL script](xref:core/managing-schemas/migrations/applying#sql-scripts) that can be previewed before execution.

Alternatively, you can use `context.Database.EnsureCreated()` to create a new database containing the managed data, for example for a test database or when using the in-memory provider or any non-relational database. Note that if the database already exists, `EnsureCreated()` will neither update the schema nor managed data in the database. For relational databases you shouldn't call `EnsureCreated()` if you plan to use Migrations.
Alternatively, you can use `context.Database.EnsureCreatedAsync()` to create a new database containing the managed data, for example for a test database or when using the in-memory provider or any non-relational database. Note that if the database already exists, `EnsureCreatedAsync()` will neither update the schema nor managed data in the database. For relational databases you shouldn't call `EnsureCreatedAsync()` if you plan to use Migrations.

> [!NOTE]
> Populating the database using the `HasData` method used to be referred to as "data seeding". This naming sets incorrect expectations, as the feature has a number of limitations and is only appropriate for specific types of data. That is why we decided to rename it to "model managed data". `UseSeeding` and `UseAsyncSeeding` methods should be used for general purpose data seeding.
Expand Down
6 changes: 3 additions & 3 deletions entity-framework/core/performance/efficient-updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ foreach (var employee in context.Employees)
{
employee.Salary += 1000;
}
context.SaveChanges();
await context.SaveChangesAsync();
```

While this is perfectly valid code, let's analyze what it does from a performance perspective:
Expand All @@ -39,10 +39,10 @@ While this is perfectly valid code, let's analyze what it does from a performanc
* EF Core's change tracking creates snapshots when loading the entities, and then compares those snapshots to the instances to find out which properties changed.
* Typically, a second database roundtrip is performed to save all the changes (note that some database providers split the changes into multiples roundtrips). Although this batching behavior is far better than doing a roundtrip for each update, EF Core still sends an UPDATE statement per employee, and the database must execute each statement separately.

Starting with EF Core 7.0, you can use the `ExecuteUpdate` and `ExecuteDelete` methods to do the same thing far more efficiently:
Starting with EF Core 7.0, you can use the `ExecuteUpdateAsync` and `ExecuteDeleteAsync` methods to do the same thing far more efficiently:

```c#
context.Employees.ExecuteUpdate(s => s.SetProperty(e => e.Salary, e => e.Salary + 1000));
await context.Employees.ExecuteUpdateAsync(s => s.SetProperty(e => e.Salary, e => e.Salary + 1000));
```

This sends the following SQL statement to the database:
Expand Down
4 changes: 2 additions & 2 deletions entity-framework/core/providers/cosmos/querying.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@ A common way to implement pagination with databases is to use the `Skip` and `Ta

```csharp
var position = 20;
var nextPage = context.Session
var nextPage = await context.Session
.OrderBy(s => s.Id)
.Skip(position)
.Take(10)
.ToList();
.ToListAsync();
```

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_:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ By default, IDENTITY columns start off at 1 (the seed), and increment by 1 each

### Inserting explicit values into IDENTITY columns

By default, SQL Server doesn't allow inserting explicit values into IDENTITY columns. To do so, you must manually enable `IDENTITY_INSERT` before calling `SaveChanges()`, as follows:
By default, SQL Server doesn't allow inserting explicit values into IDENTITY columns. To do so, you must manually enable `IDENTITY_INSERT` before calling `SaveChangesAsync()`, as follows:

[!code-csharp[Main](../../../../samples/core/SqlServer/ValueGeneration/ExplicitIdentityValues.cs?name=ExplicitIdentityValues)]

Expand Down
4 changes: 2 additions & 2 deletions entity-framework/core/querying/related-data/eager.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ Alternatively, identical operations can be applied for each navigation that is i
Example:

```csharp
var orders = context.Orders.Where(o => o.Id > 1000).ToList();
var orders = await context.Orders.Where(o => o.Id > 1000).ToListAsync();

// customer entities will have references to all orders where Id > 1000, rather than > 5000
var filtered = context.Customers.Include(c => c.Orders.Where(o => o.Id > 5000)).ToList();
var filtered = await context.Customers.Include(c => c.Orders.Where(o => o.Id > 5000)).ToListAsync();
```

> [!NOTE]
Expand Down
16 changes: 8 additions & 8 deletions entity-framework/core/querying/single-split-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ When working against relational databases, EF loads related entities by introduc
Let's examine the following LINQ query and its translated SQL equivalent:

```c#
var blogs = ctx.Blogs
var blogs = await ctx.Blogs
.Include(b => b.Posts)
.Include(b => b.Contributors)
.ToList();
.ToListAsync();
```

```sql
Expand All @@ -35,10 +35,10 @@ In this example, since both `Posts` and `Contributors` are collection navigation
Note that cartesian explosion does not occur when the two JOINs aren't at the same level:

```c#
var blogs = ctx.Blogs
var blogs = await ctx.Blogs
.Include(b => b.Posts)
.ThenInclude(p => p.Comments)
.ToList();
.ToListAsync();
```

```sql
Expand All @@ -56,9 +56,9 @@ In this query, `Comments` is a collection navigation of `Post`, unlike `Contribu
JOINs can create another type of performance issue. Let's examine the following query, which only loads a single collection navigation:

```c#
var blogs = ctx.Blogs
var blogs = await ctx.Blogs
.Include(b => b.Posts)
.ToList();
.ToListAsync();
```

```sql
Expand All @@ -73,14 +73,14 @@ Examining at the projected columns, each row returned by this query contains pro
If you don't actually need the huge column, it's easy to simply not query for it:

```c#
var blogs = ctx.Blogs
var blogs = await ctx.Blogs
.Select(b => new
{
b.Id,
b.Name,
b.Posts
})
.ToList();
.ToListAsync();
```

By using a projection to explicitly choose which columns you want, you can omit big columns and improve performance; note that this is a good idea regardless of data duplication, so consider doing it even when not loading a collection navigation. However, since this projects the blog to an anonymous type, the blog isn't tracked by EF and changes to it can't be saved back as usual.
Expand Down
Loading
Loading