.NET 10: Using Entity Framework Core 1o to store Vector Embedding in Azure SQL Database and perform Semantic Search

In this article, we will see new Features of Entity Framework Core 10 with Vector store in Azure SQL Database. EF Core 10 includes built-in support for Azure SQL’s native vector type and vector search, so developers no longer need the separate VectorSearch plugin used in EF Core 8/9. In .NET 10, the SQLVector support was introduced via EF Core 10.0. This added a native support Entity Framework Core 10 (released in November 2025) added native support for the new SQL Server VECTOR data type, allowing developers to use SqlVector properties in their .NET applications.

Advantages of using SqlVector

While building AI applications like Retrival Augmented Generation (RAG) as well as Semantic Search, we need to store data in the form of vector embedding. With a tridditional programming approach with typical database centric applications, storing vectorized data in difficult in database tables. In .NET 10 with EF Core 10, using SqlVector structure we can make it possible. in .NET 10 application we can define class as shown in Listing 1.

 
public class PdfDoc
{
    [Key]
    public int Id {get;set}
    [Required]
    public string Name {get;set;}
    [Column(TypeName = "vector(1536)")]
    public SqlVector<float> Embedding { get; set; }
}
Listing 1: Sample class
As shown in Listing 1, with .NET 10 and EF Core 10, we can embed the document and store it in the SQL Server 2025 as well as in Azure SQL Database. The direct mapping from PdfDoc to SQL Server table will help to store vector embedding so that it can be used in Semantic Search and RAG based applications.

What is vector(1536)


The vector is the new VECTOR data type in SQL Server 2025. It is designed to store numerical arrays (embeddings) used in AI/ML tasks like semantic search. (1536) the number inside the parentheses specifies the dimension i.e. length of the vector. This means the column can store vectors with exactly 1536 floating-point values. The limit is kept to 1536 because many modern embedding models like OpenAI’s text-embedding-ada-002 produce vectors of length 1536. By declaring vector(1536), we ensure the database column matches the embedding size generated by the AI model. If we try to insert a vector of a different length e.g. 768 , 1024, 3072, etc, SQL Server would reject it because the dimension doesn’t match. Since this is mapped with SQL Server we can run similar searchs directly in SQL Server just like Select statement. The advantage of storing embeddings is that SQL Server optimizes storage and indexing for vectors, making searches much faster than storing embeddings as JSON or text.

Pre-requisites

To implement the solution demonstrated in this article, ensure you have the following prerequisites in place:

  • Visual Studio 2022 or later installed on your development machine.
  • .NET 10 SDK installed. You can download it from the official .NET website.
  • An Azure SQL Database instance. You can create one via the Azure Portal.
  • SQL Server Management Studio (SSMS) or Azure Data Studio for database management.
  • Azure SDK for .NET installed. You can add it to your project via NuGet Package Manager.
  • Azure Subscription. If you don't have one, you can create a free account at Azure Free Account.
  • An Azure OpenAI Service resource set up in your Azure subscription. Follow the instructions in the Azure OpenAI documentation to create the resource.

The Implementation

Step 1: Visit to Azure Portal and create a new Azure SQL Database instance. Note down the connection string for later use. Step 2: Create a new Azure OpenAI Service resource in the Azure Portal. Note down the endpoint and API key. Step 3: Once the Azure Open AI Service is created, complete the Deployment for the model you intend to use e.g., gpt-4.1 text-embedding-ada-002. We will be using text-embedding-ada-002 model in this article for generating embeddings and gpt-4.1 for chat based semantic search. Step 4: Open Visual Studio and create a new Console Application targeting .NET 9. Please not that from the project properties, set the d TargetFramework to net10.0 as shown in Listing 2.

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
Listing 2: The Setting the Target Framework to .NET 10

Step 5: Add the following NuGet packages to your project as shown in Listing 3. 

dotnet add package Microsoft.EntityFrameworkCore --version 10.0.0
dotnet add package Microsoft.EntityFrameworkCore.Relational --version 10.0.0
dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 10.0.0
dotnet add package Microsoft.EntityFrameworkCore.Design --version 10.0.0
dotnet add package Microsoft.EntityFrameworkCore.Tools --version 10.0.0
dotnet add package Azure.AI.OpenAI --version 2.1.0

Listing 3: NuGet Packages to be added

Step 5: In the project add a new class file named Document.cs and define the class as shown in Listing 4.


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

namespace CS_Net10_Vector
{
    public class Document
    {
        [Key]
        public int Id { get; set; }

        [Required, MaxLength(256)]
        public string Title { get; set; } = string.Empty;

        [Required]
        public string Content { get; set; } = string.Empty;

        [Column(TypeName = "vector(1536)")]
        public SqlVector<float> Embedding { get; set; }
    }
}
Listing 4: Document class with SqlVector property

As shown in Listing 4, the Document class contains properties for Id, Title, Content, and Embedding. The Embedding property is of type SqlVector and is mapped to a SQL Server vector column with a dimension of 1536. Step 6: Add a new class file named VectorDbContext.cs and define the DbContext as shown in Listing 5.


using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;

namespace CS_Net10_Vector
{
    public class VectorDbContext : DbContext
    {
        public VectorDbContext()
        {

        }
        public DbSet<Document> Documents { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseSqlServer(
                    "Server=tcp:[YOUR-AZURE-SQL-DATABASE-INSTANCE-NAME].database.windows.net,1433;" +
                    "Initial Catalog=[YOUR-AZURE-DATABASE-NAME];" +
                    "Persist Security Info=False;" +
                    "User ID=[DATABASE-ADMIN-USER];" +
                    "Password=[DATABASE-ADMIN-PASSWORD];" +
                    "MultipleActiveResultSets=False;" +
                    "Encrypt=True;" +
                    "TrustServerCertificate=False;" +
                    "Connection Timeout=30;"
                );
            }
        }


        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Optional: explicit dimension mapping via Fluent API
            modelBuilder.Entity<Document>()
                .Property(d => d.Embedding)
                .HasColumnType("vector(1536)");
        }
    }
}

Listing 5: VectorDbContext with DbSet for Document

Since we are using Azure SQL Database, in the OnConfiguring method, replace the placeholders in the connection string with your actual database details. To generate the database and tables, run the following commands in the Package Manager Console:

dotnet ef migrations add InitialCreate -c  CS_Net10_Vector.VectorDbContext

dotnet ef database update -c  CS_Net10_Vector.VectorDbContext

Once the commands are executed successfully, the database and Document table with vector column will be created in your Azure SQL Database as shown in Figure 1.



Figure 1: Document table with vector column in Azure SQL Database

Step 7: Now, open the Program.cs file and implement the logic to generate embeddings using Azure OpenAI Service and store them in the database as shown in .


using Azure;
using Azure.AI.OpenAI;
using CS_Net10_Vector;
using Microsoft.Data.SqlTypes;
using Microsoft.EntityFrameworkCore;
using OpenAI.Chat;

Console.WriteLine("Usign Azure SQL Vector with .NET 10 and EF Core 10");

// 1. Initialize the Azure OpenAI client

var endpoint = new Uri("https://[THE-AZURE-OPEN-AI-ENDPOINT-HERE].openai.azure.com/");
var apiKey = new AzureKeyCredential("[THE-AZURE-OPEN-AI-KEY-HERE]");
var client = new AzureOpenAIClient(endpoint, apiKey);
// 2. Sample text data (James Bond movie summaries)
string[] titles = new string []{
    "Dr. No",
    "From Russia with Love",
    "Goldfinger",
    "Thunderball",
    "You Only Live Twice",
    "Diamonds Are Forever",
    "On Her Majesty’s Secret Service",
    "Live and Let Die",
    "The The Man with the Golden Gun",
    "The Spy Who Loved Me",
    "Moonraker",
    "For Your Eyes Only",
    "Octopussy",
    "A View to a Kill",
    "The Living Daylights",
    "Licence to Kill",
    "GoldenEye",
    "Tomorrow Never Dies",
    "The World Is Not Enough",
    "Die Another Day",
    "Casino Royale",
    "Quantum of Solace",
    "Skyfall",
    "Spectre",
    "No Time to Die"
};
// 3. Corresponding movie summaries
string[] text = {
  "Sean Connery Era, Dr. No (1962) introduces James Bond as he investigates the disappearance of a British agent in Jamaica. He uncovers Dr. No’s plot to disrupt U.S. rocket launches, and meets Honey Ryder in one of cinema’s most iconic entrances.",
  "Sean Connery Era, From Russia with Love (1963) follows Bond as he races to secure a Soviet decoding machine, the Lektor. He faces SPECTRE assassins Rosa Klebb and Red Grant, while falling for Tatiana Romanova amid Cold War intrigue.",
  "Sean Connery Era, Goldfinger (1964) pits Bond against Auric Goldfinger, who plans to irradiate the U.S. gold supply at Fort Knox. With Pussy Galore’s help, Bond thwarts the scheme, cementing the Aston Martin DB5 as a franchise legend.",
  "Sean Connery Era, Thunderball (1965) sees Bond battling Emilio Largo, who has stolen nuclear warheads for SPECTRE. The film features spectacular underwater battles and Bond’s romance with Domino.",
  "Sean Connery Era, You Only Live Twice (1967) takes Bond to Japan, where Blofeld hijacks spacecraft to provoke war. Bond infiltrates his volcano lair with the help of Kissy Suzuki, leading to a dramatic showdown.",
  "Sean Connery Era, Diamonds Are Forever (1971) brings Bond to Las Vegas to stop Blofeld’s diamond‑powered satellite weapon. Tiffany Case joins him in a campy adventure full of glitz and eccentric villains.",
  "George Lazenby, On Her Majesty’s Secret Service (1969) presents Bond infiltrating Blofeld’s Alpine clinic. He falls in love with Tracy di Vicenzo, marries her, but tragedy strikes when Blofeld kills her in the finale.",
  "Roger Moore Era, Live and Let Die (1973) introduces Moore’s Bond against drug lord Dr. Kananga, who uses voodoo mystique to mask his empire. Solitaire, a psychic, becomes Bond’s ally in a Caribbean adventure.",
  "Roger Moore Era The Man with the Golden Gun (1974) pits Bond against master assassin Scaramanga, who wields a golden pistol. Their duel over a solar energy device ends in a tense one‑on‑one showdown.",
  "Roger Moore Era The Spy Who Loved Me (1977) pairs Bond with Russian agent Anya Amasova to stop Karl Stromberg’s plan to create an underwater world. The Lotus Esprit car steals the show by transforming into a submarine.",
  "Roger Moore Era, Moonraker (1979) launches Bond into space as he uncovers Hugo Drax’s plan to repopulate Earth with a master race. Astronaut Holly Goodhead helps him foil the scheme in orbit.",
  "Roger Moore Era, For Your Eyes Only (1981) returns to grounded espionage as Bond seeks a stolen ATAC device. He partners with Melina Havelock, whose parents were murdered, and faces betrayal from Kristatos.",
  "Roger Moore Era, Octopussy (1983) sees Bond disguised as a circus performer to stop a nuclear bomb plot in Germany. He allies with Octopussy, a smuggler, against Kamal Khan and General Orlov.",
  "Roger Moore Era, A View to a Kill (1985) has Bond battling Max Zorin, who plans to destroy Silicon Valley. Stacey Sutton aids him, and the climax unfolds atop the Golden Gate Bridge.",
  "Timothy Dalton Era, The Living Daylights (1987) features Bond protecting a Soviet defector while uncovering Koskov’s double‑cross. Kara Milovy, a cellist, becomes his partner in a Cold War thriller.",
  "Timothy Dalton Era, Licence to Kill (1989) takes Bond rogue after his friend Felix Leiter is attacked. He infiltrates drug lord Franz Sanchez’s empire, delivering one of the darkest Bond stories.",
  "Pierce Brosnan Era, GoldenEye (1995) revives the franchise with Bond facing Alec Trevelyan, a former MI6 agent turned traitor. Natalya Simonova helps him stop the GoldenEye satellite weapon.",
  "Pierce Brosnan Era, Tomorrow Never Dies (1997) sees Bond against media mogul Elliot Carver, who manipulates global conflict for ratings. Chinese agent Wai Lin joins him in a high‑tech adventure.",
  "Pierce Brosnan Era, The World Is Not Enough (1999) explores betrayal as oil heiress Elektra King manipulates Bond. With physicist Christmas Jones, he confronts Renard, a villain who feels no pain.",
  "Pierce Brosnan Era, Die Another Day (2002) sends Bond against Gustav Graves, a North Korean colonel using a satellite weapon. Jinx, an American agent, partners with him in a gadget‑heavy spectacle.",
  "Pierce Brosnan Era, Die Another Day (2002) sends Bond against Gustav Graves, a North Korean colonel using a satellite weapon. Jinx, an American agent, partners with him in a gadget‑heavy spectacle.",
  "Daniel Craig Era, Casino Royale (2006) reboots Bond with his first mission: defeating terrorist banker Le Chiffre in a high‑stakes poker game. His love for Vesper Lynd ends in heartbreak.",
  "Daniel Craig Era, Quantum of Solace (2008) continues Bond’s grief as he uncovers Quantum’s plot to control Bolivia’s water supply. Camille Montes aids him in a revenge‑driven story.",
  "Daniel Craig Era, Skyfall (2012) explores Bond’s past as he protects M from former agent Silva. The film ends with M’s death, reshaping Bond’s world.",
  "Daniel Craig Era, Spectre (2015) reveals Blofeld as the mastermind behind Bond’s suffering. Madeleine Swann becomes his partner as he uncovers SPECTRE’s surveillance empire.",
  "Daniel Craig Era, No Time to Die (2021) concludes Craig’s era with Bond sacrificing himself to save Madeleine and their daughter. He stops Safin’s bioweapon, ending his journey with emotional finality."

};
 
string canContinue = "y";
do
{
    Console.Clear();
    Console.WriteLine("1. Vectorize the text");
    Console.WriteLine("2. Ask question for Performing SemanticSearch");
    Console.WriteLine("Select your chice");
    string choice = Console.ReadLine();
    switch (choice)
    {
        case "1":
            await StoreVectorToDb( client, text, titles);
            Console.WriteLine("Text vectorized and stored to Azure SQL");
            break;
        case "2":
            await PerformSemanticSearch(client);
            break;
        default:
            Console.WriteLine("Invalid choice");
            break;
    }
    Console.WriteLine("Enter y or Y to continue");
    canContinue = Console.ReadLine();

} while (canContinue == "y" || canContinue == "Y");


Console.ReadLine();


/// <summary>
/// 4. Method to get the embedding from Azure OpenAI
/// </summary>
static async Task<float[]> MakeEmbeddingAsync(AzureOpenAIClient client, string text)
{
    // Get the embedding client for your deployment
    // Replace "text-embedding-3-large" with your actual deployment name in Azure OpenAI
    var embeddingClient = client.GetEmbeddingClient("text-embedding-ada-002");

    var embedding = await embeddingClient.GenerateEmbeddingsAsync(
                           new List<string>() { text }
                        );
    return embedding.Value[0].ToFloats().ToArray();
}



/// <summary>
/// 5. Method to store the text and its embedding to Azure SQL Database
/// </summary>
static async Task StoreVectorToDb(AzureOpenAIClient client, string[] text, string[] titles)
{
    VectorDbContext db = new VectorDbContext();
    int i = 0;

    foreach (var str in text)
    {
        var embedding = await MakeEmbeddingAsync(client, str);

        var doc = new Document
        {
            Title = titles[i],
            Content = str,
            Embedding = new SqlVector<float>(embedding)
        };
        await db.Documents.AddAsync(doc);
        await db.SaveChangesAsync();
        i++;
    }
}


 
/*
 6. This method computes the cosine similarity between two vectors a and b. Cosine similarity is widely used in machine learning, NLP, and vector search (like embeddings in Azure SQL) to measure how similar two vectors are, based on the angle between them.
 */
static float ComputeCosineSimilarity(float[] a, float[] b)
{
    float dot = 0, norm_a = 0, norm_b = 0;
    for (int i = 0; i < a.Length; i++)
    { 
        dot += a[i] * b[i];  // accumulate dot product, sum of element-wise products (a[i] * b[i]).
        norm_a += a[i] * a[i]; // accumulate squared magnitude of a, sum of squares of elements in a (used to compute magnitude).
        norm_b += b[i] * b[i]; // accumulate squared magnitude of b, sum of squares of elements in b.
    }
    // square root to get actual magnitudes. normalizes the dot product by the lengths of the vectors.
    return dot / (MathF.Sqrt(norm_a) * MathF.Sqrt(norm_b));
}

/// <summary>
/// 7. Method to perform semantic search
/// </summary>  
static async Task PerformSemanticSearch(AzureOpenAIClient client)
{
    Console.WriteLine("Enter your question");
      string userQuestion = Console.ReadLine();
    // Step 7.1 : Similarity search in Azure SQL
    VectorDbContext db = new VectorDbContext();
    
    // 7.2 Get embedding for the user query
    float[] queryEmbedding = await MakeEmbeddingAsync(client, userQuestion);


    // Run similarity search using cosine distance
    // Step 7.3: Pull documents and compute similarity in C#
    var documents = await db.Documents.Take(100).ToListAsync();

    // 7.4 Compute cosine similarity for each document
    // convert the document’s embedding (probably stored as a Memory<float> or ReadOnlyMemory<float>) into a float[] so it can be passed into ComputeCosineSimilarity.
    // and select top 5 most similar documents
    // Using LINQ to project documents with their similarity scores
    // Order by score descending and take top 5

    var results = documents
        .Select(c => new { Doc = c, Score = ComputeCosineSimilarity(queryEmbedding, c.Embedding.Memory.ToArray()) })
        .OrderByDescending(x => x.Score)
        .Take(5)
        .Select(x => x.Doc)
        .ToList();
    // Step 7.5 : Build the augmented prompt
    var context = string.Join("\n\n", results.Select(r => $"{r.Title}\n{r.Content}"));
  

    // 7.6. Construct the augmented prompt
    var systemPrompt = $@"
        You are a helpful assistant. Use the following context to answer the question.
        You have to answer based on the context only, otheriwise just response as 'This question is out of my context.'.
        Context:
        {context}
        ";

    // Step 7.7: Call the LLM
    var chatResponse =   client.GetChatClient("gpt-4.1");
    var requestOptions = new ChatCompletionOptions
    {
        MaxOutputTokenCount = 16384,
        Temperature = 1.0f,
        TopP = 1.0f,
    };
    // 7.8:   Create the messages
    List<ChatMessage> messages = new List<ChatMessage>(){ 
     new SystemChatMessage(systemPrompt),
     new UserChatMessage(userQuestion)
    };

    // 7.9 Get the completion from the LLM
    var response = chatResponse.CompleteChat(messages, requestOptions);

    Console.WriteLine("Response from LLM:");
    Console.WriteLine(response.Value.Content[0].Text);

}

Listing 6: Program.cs with logic to vectorize text and perform semantic search

The code in Listing 6 is explained as below:

  1. Initialize the Azure OpenAI client with your endpoint and API key.
  2. Define sample text data (James Bond movie summaries) to be vectorized.
  3. Defines the movie summaries corresponding to the titles. This text will be embedded and stored in database. This will be used for the semantic search.
  4. The MakeEmbeddingAsync() method is used to generate the embedding from Azure Open AI based on the text passed to it. This method uses the GetEmbeddingClient() method of the AzureOpenAIClient class to create an instance of the EmbeddingClient class. The GenerateEmbeddingsAsync() method of the EmbeddingClient class accepts the text-embedding-ada-002 model as input parameter to generate embeddings from the text passed. We have aleady deployed the text-embedding-ada-002 model in Step 3.
  5. The StoreVectorToDb() method invokes the MakeEmbeddingAsync() and using the VectorDbContext class it stored movies data along with embeddings in Documents table created in EComm database in Azure SQL.
  6. Since we will be performing Semantic Search on the Vectorized data we need a helper method to computes the cosine similarity between two vectors. Cosine similarity is widely used in machine learning, NLP, and vector search like embeddings in Azure SQL to measure how similar two vectors are, based on the angle between them. In the code, we have added ComputeCosineSimilarity() method to compute the Cosine similarity between tow vectors. Thie method uses statactical approach like dot product, squared magnitude, square root to get actual magnitudes, and normalizes the dot product by the lengths of the vectors. This is an important set of calculations to that we can run simple Select SQL statement to perform semantic search.
  7. The PerformSemanticSearch() method is the concluding method where it uses the AzureOpenAIClient class to perform semantic srarch. This method has the following specifications.
    • 7.1: It creates an instance of VectorDbContext class to interact with SQL Server database so that queries can be executed.
    • 7.2: The MakeEmbeddingAsync() method is invoked to embed the userQuestion entered by the end-user so that it can be used in Semantic Search.
    • 7.3: The first 100 records are retrieved from the table.
    • 7.4: The LINQ query is executed on these 100 records and cosine similarity is computed on it. by selecting top 5 similar documents.
    • 7.5: On the selected results from the LINQ query the context is generated that will be used n a system prompt so that Semantic Search can be performed.
    • 7.6: The System Prompt is generated here that has the context to retrieve most relevant searches.
    • 7.7: An instance of the ChatClient class is created based on the GPT model deployed in Step 3.
    • 7.8: The chat message List is creaed based on the use question and system prompt.
    • 7.9: The LLM is invokes using the CompleteChat method of the ChatClient class and the chat messages are passed to it as input parameter along with the ChatCompletioOptions like MaxOutputTokenCount, Temperature and TopP. This provides the Semantic Search result that is printed on Console (UI).
Run the application, the Console will show output as shown in Figure 2:



Figure 2: Selecting Options from the Console Result

Select option 1, here the embeddings will be generated for the sample text data and stored in Azure SQL Database. Once the process is completed, you will see the message "Text vectorized and stored to Azure SQL" as shown in Figure 3.



Figure 3: Text Vectorized and Stored to Azure SQL
Now, select option 2 to perform Semantic Search. Enter your question related to James Bond movies as shown in Figure 4.



Figure 4: Performing Semantic Search

Conclusion: The SqlVector support in .NET 10 and EF Core 10 makes it easier for developers to build AI-powered applications that leverage vector embeddings. By following the steps outlined in this article, you can create a .NET 10 application that stores and retrieves vector data from Azure SQL Database, enabling advanced features like semantic search and retrieval-augmented generation. This integration simplifies the development process and enhances the capabilities of your applications in the AI era.

The code for this article can be downloaded from this link.

Popular posts from this blog

ASP.NET Core 8: Creating Custom Authentication Handler for Authenticating Users for the Minimal APIs

Uploading Excel File to ASP.NET Core 6 application to save data from Excel to SQL Server Database

ASP.NET Core 7: Using PostgreSQL to store Identity Information