Microsoft Agent Framework ef-core Created: 10 May 2026 Updated: 10 May 2026

Vector Search with EF Core and SQL Server 2025: A Practical Guide

Author's note: SQL Server 2025 introduces a first-class vector data type and a family of vector functions. EF Core 10 added native LINQ translation for these features; EF Core 11 extends support to approximate search using vector indexes. This article walks through both, with runnable C# examples.

Table of contents

  1. Why vector search matters
  2. What's new in SQL Server 2025
  3. Prerequisites
  4. Defining a vector property in your EF model
  5. Generating embeddings and inserting them
  6. Exact search with VECTOR_DISTANCE()
  7. Creating a vector index
  8. Approximate search with VECTOR_SEARCH()
  9. Hybrid search (vector + full-text)
  10. Pure T-SQL reference
  11. Performance and design tips

1. Why vector search matters

Modern AI workloads — semantic search, recommendation systems, retrieval-augmented generation (RAG) — depend on representing text, images, or audio as dense numeric arrays called embeddings. Two embeddings that are close in vector space represent similar meaning. Until recently, storing those embeddings in SQL Server required JSON columns, custom UDFs, or a separate vector database. SQL Server 2025 removes that friction: vectors are now a first-class column type, with built-in distance functions and (in preview) approximate indexes.

2. What's new in SQL Server 2025

FeatureDescriptionStatus
VECTOR(n) data typeStores a fixed-dimension array of float32 (or float16 for half-precision). Up to 1998 dimensions for float32, up to 3996 for float16.GA
VECTOR_DISTANCEComputes the exact distance between two vectors using cosine, euclidean, or dot metrics.GA
VECTOR_NORMReturns the magnitude (length) of a vector.GA
VECTOR_NORMALIZEReturns a unit-length vector.GA
VECTORPROPERTYReturns metadata for a vector (e.g. dimensions, base type).GA
CREATE VECTOR INDEXBuilds an approximate nearest-neighbor index on a vector column.Preview
VECTOR_SEARCHTable-valued function that performs approximate nearest-neighbor search using a vector index.Preview
Preview features. CREATE VECTOR INDEX and VECTOR_SEARCH are in preview and require enabling PREVIEW_FEATURES at the database scope. APIs may change.

3. Prerequisites

  1. SQL Server 2025 (17.x) or Azure SQL Database
  2. .NET 10 (or later)
  3. EF Core 10 for exact search; EF Core 11 for vector indexes & approximate search
  4. An embedding generator — for example Microsoft.Extensions.AI wrapping Azure OpenAI, OpenAI, or a local model

NuGet packages

dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 11.*
dotnet add package Microsoft.Extensions.AI
dotnet add package Microsoft.Extensions.AI.OpenAI

4. Defining a vector property in your EF model

Add a property of type SqlVector<float> to your entity. The dimension count must match what your embedding model produces (for example, 1536 for text-embedding-ada-002, 3072 for text-embedding-3-large).

Using Data Annotations

using Microsoft.Data.SqlTypes;
using System.ComponentModel.DataAnnotations.Schema;

public class Blog
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Content { get; set; } = "";

[Column(TypeName = "vector(1536)")]
public SqlVector<float> Embedding { get; set; }
}

Using the Fluent API

public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs => Set<Blog>();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Embedding)
.HasColumnType("vector(1536)");
}
}
EF Core 11 behavior change. Vector columns are no longer materialized by default when loading entities, because they are large and rarely needed when reading. They are only fetched when explicitly projected or used in a query expression.

5. Generating embeddings and inserting them

Embedding generation happens outside the database. The Microsoft.Extensions.AI abstractions hide provider-specific details behind IEmbeddingGenerator<string, Embedding<float>>.

using Microsoft.Extensions.AI;
using Microsoft.Data.SqlTypes;

IEmbeddingGenerator<string, Embedding<float>> generator = /* configure your provider */;

await using var context = new BloggingContext();

string text = "Entity Framework Core 11 ships with first-class vector search.";
ReadOnlyMemory<float> embedding = await generator.GenerateVectorAsync(text);

context.Blogs.Add(new Blog
{
Name = "EF 11 highlights",
Content = text,
Embedding = new SqlVector<float>(embedding)
});

await context.SaveChangesAsync();

6. Exact search with VECTOR_DISTANCE()

For small and mid-sized datasets (a rule of thumb is < 50,000 candidate rows after filtering), an exact k-nearest-neighbors scan is simple and accurate. EF Core translates EF.Functions.VectorDistance(...) to the T-SQL VECTOR_DISTANCE function.

using Microsoft.EntityFrameworkCore;
using Microsoft.Data.SqlTypes;

string userQuery = "How does approximate vector search work?";
ReadOnlyMemory<float> queryEmbedding = await generator.GenerateVectorAsync(userQuery);
var queryVector = new SqlVector<float>(queryEmbedding);

var topMatches = await context.Blogs
.OrderBy(b => EF.Functions.VectorDistance("cosine", b.Embedding, queryVector))
.Take(5)
.Select(b => new { b.Id, b.Name, b.Content })
.ToListAsync();

The supported metrics are cosine, euclidean, and dot. Pick the metric that matches how your embedding model was trained — most text models (OpenAI, Azure OpenAI, MiniLM, BGE) are tuned for cosine similarity.

7. Creating a vector index

For larger tables, an exact scan becomes too slow. SQL Server 2025 introduces an approximate nearest-neighbor index. EF Core 11 exposes HasVectorIndex():

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasVectorIndex(b => b.Embedding, "cosine");
}

This generates a migration containing:

CREATE VECTOR INDEX [IX_Blogs_Embedding]
ON [Blogs] ([Embedding])
WITH (METRIC = COSINE);
Enable preview features first. Before applying the migration, run ALTER DATABASE SCOPED CONFIGURATION SET PREVIEW_FEATURES = ON; against the target database.

8. Approximate search with VECTOR_SEARCH()

Once the index exists, use the VectorSearch() extension on your DbSet. The result is a VectorSearchResult<TEntity> exposing both the entity and its computed distance.

var results = await context.Blogs
.VectorSearch(b => b.Embedding, queryVector, "cosine", topN: 10)
.Where(r => r.Distance < 0.25)
.Select(r => new
{
Blog = r.Value,
Distance = r.Distance
})
.ToListAsync();

foreach (var hit in results)
{
Console.WriteLine($"[{hit.Distance:F4}] {hit.Blog.Name}");
}

EF Core translates this to the table-valued function:

SELECT [v].[Id], [v].[Name], [v].[Distance]
FROM VECTOR_SEARCH([Blogs], 'Embedding', @__embedding, 'metric = cosine', @__topN);

9. Hybrid search (vector + full-text)

Vector search excels at semantic matches; full-text search excels at exact keyword matches. Combining both with Reciprocal Rank Fusion (RRF) gives more relevant results than either alone.

// Conceptual outline — full RRF query is large
var k = 60;
var ftsResults = context.Articles
.Where(a => EF.Functions.FreeText(a.Title + " " + a.Body, userQuery))
.Select((a, i) => new { a.Id, FtsRank = 1.0 / (k + i + 1) });

var vectorResults = context.Articles
.VectorSearch(a => a.Embedding, queryVector, "cosine", topN: 50)
.Select((r, i) => new { Id = r.Value.Id, VecRank = 1.0 / (k + i + 1) });

// Merge by Id and order by (FtsRank + VecRank) descending
Tip. A FULL OUTER JOIN between the two ranked sets is the most accurate fusion strategy because it includes documents that score highly on either side. EF Core does not yet support FULL OUTER JOIN in LINQ; today, a LEFT JOIN from the full-text side or raw SQL is the practical workaround.

10. Pure T-SQL reference

If you prefer working directly in T-SQL — for instance, from a stored procedure that EF Core then calls via FromSqlRaw() — the same building blocks look like this.

Declaring and casting vectors

DECLARE @v1 VECTOR(3) = '[1.0, -0.2, 30]';
DECLARE @v2 VECTOR(3) = JSON_ARRAY(1.0, -0.2, 30);
SELECT @v1 AS v1, @v2 AS v2;

Exact kNN with VECTOR_DISTANCE

DECLARE @qv VECTOR(1536) =
AI_GENERATE_EMBEDDINGS(N'Pink Floyd music style' USE MODEL Ada2Embeddings);

SELECT TOP (10)
id,
title,
VECTOR_DISTANCE('cosine', @qv, content_vector) AS distance
FROM dbo.wikipedia_articles_embeddings
ORDER BY distance;

Approximate kNN with VECTOR_SEARCH

SELECT TOP (10) WITH APPROXIMATE
t.id,
t.title,
r.distance
FROM VECTOR_SEARCH(
TABLE = dbo.wikipedia_articles_embeddings,
COLUMN = content_vector,
SIMILAR_TO = @qv,
METRIC = 'cosine'
) AS r
INNER JOIN dbo.wikipedia_articles_embeddings t ON t.id = r.id
ORDER BY r.distance;
ORDER BY rules for VECTOR_SEARCH. When using SELECT TOP (N) WITH APPROXIMATE, the query must include an ORDER BY referencing only the distance column, in ascending order.

11. Performance and design tips

  1. Match dimensions exactly. The column dimension and the embedding produced by your generator must agree, or inserts will fail.
  2. Pick the right metric. Cosine for normalized text embeddings; Euclidean often works for image embeddings; dot product when you control normalization yourself.
  3. Don't read vectors back unless you need them. EF Core 11 already excludes them from SELECT * materialization — keep it that way.
  4. Use exact search up to roughly 50,000 candidate rows after applying business filters; switch to a vector index above that scale.
  5. Half-precision saves 50% of storage. Declare vector(1536, float16) when bytes matter and a small accuracy loss is acceptable.
  6. Combine with relational filters. SQL Server 2025 applies predicates iteratively during vector search, so WHERE clauses and VECTOR_SEARCH compose without you having to oversample.
  7. Cache embeddings. Embedding generation is the slowest and most expensive part of the pipeline; cache outputs by content hash.

Wrap-up

SQL Server 2025 plus EF Core 10/11 lets you keep your operational data and your AI search index in the same database, with a familiar LINQ surface and migrations support. Start with EF.Functions.VectorDistance() to validate the approach against your data, then add a vector index and switch to VectorSearch() as you scale.

References (Microsoft Learn)

  1. What's New in EF Core 10 — Vector search support
  2. What's New in EF Core 11 — VECTOR_SEARCH() and vector indexes
  3. Vector search in the SQL Server EF Core Provider
  4. VECTOR_DISTANCE (Transact-SQL)
  5. VECTOR_SEARCH (Transact-SQL) (Preview)
  6. Vector data type
  7. Vector search and vector indexes in the SQL Database Engine
  8. Vector datatype support in SqlClient
  9. What's new in SQL Server 2025


Share this lesson: