Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
7 changes: 5 additions & 2 deletions entity-framework/core/cli/msbuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: EF Core MSBuild tasks - EF Core
description: Reference guide for the Entity Framework Core .NET MSBuild tasks
author: AndriySvyryd
ms.date: 01/17/2025
ms.date: 03/04/2026
uid: core/cli/msbuild
---

Expand Down Expand Up @@ -30,14 +30,17 @@ If the project specifies `<PublishAot>true</PublishAot>` then by default the MSB

| MSBuild property | Description |
|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| EFOptimizeContext | Set to `true` to enable MSBuild integration. |
| EFOptimizeContext | Set to `true` to enable MSBuild integration. **EF Core 9-10 only; removed in EF Core 11.** |
| 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)`. |

> [!NOTE]
> Starting with EF Core 11, the `EFOptimizeContext` property has been [removed](xref:core/what-is-new/ef-core-11.0/breaking-changes#ef-optimize-context-removed). The `EFScaffoldModelStage` and `EFPrecompileQueriesStage` properties now work independently and don't require an additional enablement flag.

## Limitations

* When using the integration during the `publish` stage also set the rid in the startup project (e.g. \<RuntimeIdentifier\>win-x64\</RuntimeIdentifier\>)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ uid: core/managing-schemas/migrations/projects

# Using a Separate Migrations Project

You may want to store your migrations in a different project than the one containing your `DbContext`. You can also use this strategy to maintain multiple sets of migrations, for example, one for development and another for release-to-release upgrades.
You may want to store your migrations in a different project than the one containing your `DbContext`. This is recommended if your project uses a platform-specific project type, such as WinUI, Xamarin, MAUI, Blazor, or Azure Functions, or if it targets a specific runtime identifier (RID). You can also use this strategy to maintain multiple sets of migrations, for example, one for development and another for release-to-release upgrades.

> [!TIP]
> You can view this article's [sample on GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Schemas/ThreeProjectMigrations).
Expand Down Expand Up @@ -59,3 +59,6 @@ Add-Migration NewMigration -Project WebApplication1.Migrations
```

***

> [!TIP]
> If your application uses dependency injection, consider implementing <xref:Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory`1> in your migrations project. This allows the EF tools to create your `DbContext` without needing to run the startup project. For more information, see [From a design-time factory](xref:core/cli/dbcontext-creation#from-a-design-time-factory).
47 changes: 12 additions & 35 deletions entity-framework/core/managing-schemas/migrations/teams.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,33 @@
title: Migrations in Team Environments - EF Core
description: Best practices for managing migrations and resolving conflicts in team environments with Entity Framework Core
author: SamMonoRT
ms.date: 10/30/2017
ms.date: 02/18/2026
uid: core/managing-schemas/migrations/teams
---
# Migrations in Team Environments

When working with Migrations in team environments, pay extra attention to the model snapshot file. This file can tell you if your teammate's migration merges cleanly with yours or if you need to resolve a conflict by re-creating your
migration before sharing it.
When working with Migrations in team environments, various problems can arise when migrations are added by multiple developers around the same time; note that migrations aren't simply SQL scripts but also include a snapshot of the model at the time of that migration.

## Merging
For example, imagine developer A and B both create work branches at the same time, and generate a migration in their branches. If developer A merges their branch and then developer B does the same, the latest migration (developer B's) will have a context snapshot that does not include the changes from developer A's migration. This can cause various forms of corruption in later migrations.

When you merge migrations from your teammates, you may get conflicts in your model snapshot file. If both changes are unrelated, the merge is trivial and the two migrations can coexist. For example, you may get a merge conflict in the customer entity type configuration that looks like this:
As a result, it is highly recommended to coordinate in advance and to avoid working concurrently on migrations in multiple branches when possible.

```output
<<<<<<< Mine
b.Property<bool>("Deactivated");
=======
b.Property<int>("LoyaltyPoints");
>>>>>>> Theirs
```
## Detecting diverged migration trees

Since both of these properties need to exist in the final model, complete the merge by adding both properties. In many
cases, your version control system may automatically merge such changes for you.
> [!NOTE]
> This feature is being introduced in EF Core 11 from preview-3 onwards.

```csharp
b.Property<bool>("Deactivated");
b.Property<int>("LoyaltyPoints");
```
Starting with EF 11, the model snapshot records the ID of the latest migration. This means that if two developers each create a migration on separate branches, merging those branches will produce a source control conflict in the model snapshot file — since both branches modify the latest migration ID. This conflict is an important signal: it tells you that the migration trees have diverged, and one of them must be discarded before proceeding.

In these cases, your migration and your teammate's migration are independent of each other. Since either of them could be applied first, you don't need to make any additional changes to your migration before sharing it with your team.
To resolve this, follow the steps in [Resolving diverged migration trees](#resolving-diverged-migration-trees) below: abort the merge, remove your migration (keeping your model changes), merge your teammate's changes, and then re-add your migration.

## Resolving conflicts
## Resolving diverged migration trees

Sometimes you encounter a true conflict when merging the model snapshot model. For example, you and your teammate may each have renamed the same property.

```output
<<<<<<< Mine
b.Property<string>("Username");
=======
b.Property<string>("Alias");
>>>>>>> Theirs
```

If you encounter this kind of conflict, resolve it by re-creating your migration. Follow these steps:
If, when merging a branch, a diverged migration tree is detected, resolve it by re-creating your migration. Follow these steps:

1. Abort the merge and rollback to your working directory before the merge
2. Remove your migration (but keep your model changes)
3. Merge your teammate's changes into your working directory
4. Re-add your migration

After doing this, the two migrations can be applied in the correct order. Their migration is applied first, renaming
the column to *Alias*, thereafter your migration renames it to *Username*.

Your migration can safely be shared with the rest of the team.
After doing this, your migration is cleanly based on top of any migrations that have been added in the other branch, and its context snapshot contains all previous changes. Your migration can now be safely shared with the rest of the team.
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,32 @@ This can be changed in the model building API using `HasConstraintName`. For exa
> [!TIP]
> The constraint name is not used by the EF runtime. It is only used when creating a database schema using [EF Core Migrations](xref:core/managing-schemas/migrations/index).

### Excluding foreign key constraints from migrations

> [!NOTE]
> This feature is being introduced in EF Core 11, which is currently in preview.

Sometimes it is useful to have the foreign key relationship represented in the EF model, but without creating the corresponding foreign key constraint in the database. This can happen with legacy databases where constraints don't exist, or in data synchronization scenarios where the order of inserting related entities might temporarily violate referential integrity constraints. In these cases, use `ExcludeForeignKeyFromMigrations` to prevent EF from generating the foreign key constraint in migrations (and `EnsureCreated`):

```csharp
modelBuilder.Entity<Blog>()
.HasMany(e => e.Posts)
.WithOne(e => e.Blog)
.HasForeignKey(e => e.BlogId)
.ExcludeForeignKeyFromMigrations();
```

With this configuration, EF will not create a foreign key constraint in the database, but the relationship is still tracked in the EF model and can be used normally for loading related data, change tracking, etc. EF will still create a database index for the foreign key column, since indexes benefit queries regardless of whether a constraint exists.

To apply this across all foreign keys in the model (e.g. to globally disable all foreign key constraints), you can iterate over all foreign keys in `OnModelCreating`:

```csharp
foreach (var foreignKey in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
foreignKey.SetIsExcludedFromMigrations(true);
}
```

### Indexes for foreign keys

By convention, EF creates a database index for the property or properties of a foreign key. See [_Model building conventions_](xref:core/modeling/relationships/conventions) for more information about the types of indexes created by convention.
Expand Down
24 changes: 12 additions & 12 deletions entity-framework/core/providers/sql-server/full-text-search.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,23 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

modelBuilder.Entity<Article>()
.HasFullTextIndex(a => a.Contents)
.HasKeyIndex("PK_Articles")
.OnCatalog("ftCatalog");
.UseKeyIndex("PK_Articles")
.UseCatalog("ftCatalog");
}
```

The `HasKeyIndex()` method specifies the unique, non-nullable, single-column index used as the full-text key for the table (typically the primary key index). `OnCatalog()` assigns the full-text index to a specific catalog.
The `UseKeyIndex()` method specifies the unique, non-nullable, single-column index used as the full-text key for the table (typically the primary key index). `UseCatalog()` assigns the full-text index to a specific catalog.

You can also configure multiple columns and additional options such as per-column languages and change tracking:

```csharp
modelBuilder.Entity<Article>()
.HasFullTextIndex(a => new { a.Title, a.Contents })
.HasKeyIndex("PK_Articles")
.OnCatalog("ftCatalog")
.WithChangeTracking(FullTextChangeTracking.Manual)
.HasLanguage("Title", "English")
.HasLanguage("Contents", "French");
.UseKeyIndex("PK_Articles")
.UseCatalog("ftCatalog")
.HasChangeTracking(FullTextChangeTracking.Manual)
.UseLanguage("Title", "English")
.UseLanguage("Contents", "French");
```

The full-text catalog can also be configured as the default catalog, and with accent sensitivity:
Expand Down Expand Up @@ -185,7 +185,7 @@ The above automatically searches across all columns registered for full-text sea
```csharp
var results = await context.Articles
.Join(
context.Articles.FreeTextTable<Article, int>(a => a.Contents, "veggies"),
context.Articles.FreeTextTable<Article, int>("veggies", a => a.Contents),
a => a.Id,
ftt => ftt.Key,
(a, ftt) => new { Article = a, ftt.Rank })
Expand All @@ -197,7 +197,7 @@ var results = await context.Articles

```csharp
var results = await context.Articles
.FreeTextTable(a => new { a.Title, a.Contents }, "veggies")
.FreeTextTable("veggies", a => new { a.Title, a.Contents })
.Select(r => new { Article = r.Value, Rank = r.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
Expand All @@ -224,7 +224,7 @@ Both table-valued functions support a `topN` parameter to limit the number of re

```csharp
var results = await context.Articles
.FreeTextTable(a => a.Contents, "veggies", topN: 10)
.FreeTextTable("veggies", a => a.Contents, topN: 10)
.Select(r => new { Article = r.Value, Rank = r.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
Expand All @@ -236,7 +236,7 @@ Both table-valued functions support specifying a language term for linguistic ma

```csharp
var results = await context.Articles
.FreeTextTable(a => a.Contents, "veggies", languageTerm: "English")
.FreeTextTable("veggies", a => a.Contents, languageTerm: "English")
.Select(r => new { Article = r.Value, Rank = r.Rank })
.ToListAsync();
```
Expand Down
7 changes: 7 additions & 0 deletions entity-framework/core/providers/sql-server/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,13 @@ stringValue.Trim() | LTRIM(
stringValue.TrimEnd() | RTRIM(@stringValue)
stringValue.TrimStart() | LTRIM(@stringValue)

## JSON functions

.NET | SQL | Added in
----------------------------------------------------------------- | --------------------------------------------------------- | --------
EF.Functions.JsonContains(json, searchValue, path?, searchMode?) | JSON_CONTAINS(@json, @searchValue, @path?, @searchMode?) | EF 11.0
EF.Functions.JsonPathExists(json, path) | JSON_PATH_EXISTS(@json, @path) | EF 11.0

## Miscellaneous functions

.NET | SQL | Added in
Expand Down
49 changes: 34 additions & 15 deletions entity-framework/core/providers/sql-server/vector-search.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ await context.SaveChangesAsync();

Once you have embeddings saved to your database, you're ready to perform vector similarity search over them.

> [!NOTE]
> Starting with EF Core 11, vector properties are not loaded by default when querying entities, since vectors are typically large and are rarely needed to be read back. Prior to EF Core 11, vector properties were always loaded like any other property.

## Exact search with VECTOR_DISTANCE()

The [`EF.Functions.VectorDistance()`](/sql/t-sql/functions/vector-distance-transact-sql) function computes the *exact* distance between two vectors. Use it to perform similarity search for a given user query:
Expand Down Expand Up @@ -126,7 +129,9 @@ Once you have a vector index, use the `VectorSearch()` extension method on your

```csharp
var blogs = await context.Blogs
.VectorSearch(b => b.Embedding, "cosine", embedding, topN: 5)
.VectorSearch(b => b.Embedding, embedding, "cosine")
.OrderBy(r => r.Distance)
.Take(5)
.ToListAsync();

foreach (var (blog, score) in blogs)
Expand All @@ -138,18 +143,26 @@ foreach (var (blog, score) in blogs)
This translates to the following SQL:

```sql
SELECT [v].[Id], [v].[Embedding], [v].[Name]
FROM VECTOR_SEARCH([Blogs], 'Embedding', @__embedding, 'metric = cosine', @__topN)
SELECT TOP(@p) WITH APPROXIMATE [b].[Id], [b].[Name], [v].[Distance]
FROM VECTOR_SEARCH(
TABLE = [Blogs] AS [b],
COLUMN = [Embedding],
SIMILAR_TO = @p1,
METRIC = 'cosine'
) AS [v]
ORDER BY [v].[Distance]
```

The `topN` parameter specifies the maximum number of results to return.
Compose `VectorSearch()` with `OrderBy(r => r.Distance)` and `Take(...)` to limit the number of results returned as required for approximate vector search.

`VectorSearch()` returns `VectorSearchResult<TEntity>`, which allows you to access both the entity and the computed distance:

```csharp
var searchResults = await context.Blogs
.VectorSearch(b => b.Embedding, "cosine", embedding, topN: 5)
.VectorSearch(b => b.Embedding, embedding, "cosine")
.Where(r => r.Distance < 0.05)
.OrderBy(r => r.Distance)
.Take(5)
.Select(r => new { Blog = r.Value, Distance = r.Distance })
.ToListAsync();
```
Expand All @@ -172,7 +185,10 @@ var results = await context.Articles
.FreeTextTable<Article, int>(textualQuery, topN: k)
// Perform vector (semantic) search, joining the results of both searches together
.LeftJoin(
context.Articles.VectorSearch(b => b.Embedding, queryEmbedding, "cosine", topN: k),
context.Articles
.VectorSearch(b => b.Embedding, queryEmbedding, "cosine")
.OrderBy(r => r.Distance)
.Take(k),
fts => fts.Key,
vs => vs.Value.Id,
(fts, vs) => new
Expand Down Expand Up @@ -206,14 +222,17 @@ This query:
The query produces the following SQL:

```sql
SELECT TOP(@p3) [a0].[Id], [a0].[Content], [a0].[Embedding], [a0].[Title]
SELECT TOP(@p3) [a0].[Id], [a0].[Content], [a0].[Title]
FROM FREETEXTTABLE([Articles], *, @p, @p1) AS [f]
LEFT JOIN VECTOR_SEARCH(
TABLE = [Articles] AS [a0],
COLUMN = [Embedding],
SIMILAR_TO = @p2,
METRIC = 'cosine',
TOP_N = @p3
) AS [v] ON [f].[KEY] = [a0].[Id]
ORDER BY 1.0E0 / CAST(10 + [f].[RANK] AS float) + ISNULL(1.0E0 / (10.0E0 + [v].[Distance]), 0.0E0) DESC
LEFT JOIN (
SELECT TOP(@p4) WITH APPROXIMATE [a0].[Id], [a0].[Content], [a0].[Title], [v].[Distance]
FROM VECTOR_SEARCH(
TABLE = [Articles] AS [a0],
COLUMN = [Embedding],
SIMILAR_TO = @p2,
METRIC = 'cosine'
) AS [v]
ORDER BY [v].[Distance]
) AS [v0] ON [f].[KEY] = [v0].[Id]
ORDER BY 1.0E0 / CAST(10 + [f].[RANK] AS float) + ISNULL(1.0E0 / (10.0E0 + [v0].[Distance]), 0.0E0) DESC
```
Loading