What is InsertFromQuery

InsertFromQuery is a FREE method supported by both EF Core and EF6. It lets you insert database rows directly in SQL:

  • Without reading data or loading entities into memory
  • Without using the Change Tracker
  • Without calling SaveChanges

Think of InsertFromQuery as a SQL INSERT statement generated from LINQ.

InsertFromQuery is a set-based operation executed entirely in SQL.

You should use InsertFromQuery when you want to copy rows or values from one table to another (or the same table). If you want to insert entities, you should instead use BulkInsert.

InsertFromQuery Example

Insert all rows into a backup table

To insert all rows into another table, you need to:

  • Specify the table name
  • Choose the properties to insert
// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

// INSERT all customers into the "bck_Customer" table
await context.Customers
    .InsertFromQueryAsync(
        "bck_Customer",
        x => new { x.CustomerID, x.Name, x.Email }
    );

Online Example

The destination table doesn’t have to be part of your model. You can choose any table name and select which columns (through properties) you want to insert.

Insert rows into another mapped entity type

You can insert into another mapped entity type by providing the type instead of a table name.

Use this approach when the destination entity is already mapped in your model. EF will automatically use the configured table and column mappings.

// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

// INSERT all customers into the "bck_Customer" table
await context.Customers
    .InsertFromQueryAsync(
        typeof(BackupCustomer),
        x => new { x.CustomerID, x.Name, x.Email }
    );

Online Example

Insert rows using a "Where" filter

Like a standard LINQ query, you can filter the rows you want to insert using the Where method.

// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

// INSERT all customers that are active but haven't logged in for more than two years into the "bck_Customer" table
var date = DateTime.Now.AddYears(-2);

await context.Customers
    .Where(x => x.IsActive && x.LastLogin < date)
    .InsertFromQueryAsync(
        "bck_Customer",
        x => new { x.CustomerID, x.Name, x.Email }
    );

Online Example

Insert rows using a "WhereBulkContains" filter

You can also use methods like WhereBulkContains to filter rows to insert, especially when working with large lists of values.

// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

// INSERT only specific customers into the "bck_Customer" table
var ids = new List<int>() { 1, 2 };

await context.Customers
    .WhereBulkContains(ids)
    .InsertFromQueryAsync(
        "bck_Customer",
        x => new { x.CustomerID, x.Name, x.Email }
    );

Online Example

Insert rows using options

You can also use the InsertFromQuery method by passing options. This gives you full control over how the insert is executed.

Use this overload when the standard method is not enough and you need to customize the behavior.

In this example, we:

  • Specify the table name
  • Define the select expression
  • Add an event executed before the command runs to log the SQL command
// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

await context.Customers.InsertFromQueryAsync(options =>
{
    options.TableName = "bck_Customer";
    options.SelectExpression = x => new { x.CustomerID, x.Name, x.Email };

    // Log the generated SQL before execution
    options.Executing = command => Console.WriteLine(command.CommandText);
});

Online Example

InsertFromQuery Options

You can pass the destination table name and the select expression as parameters, but you can also use options to configure them.

Using options gives you more flexibility and allows you to customize how the insert is executed.

We support the following options:

  • DatabaseName: To specify the database name
  • SchemaName: To specify the schema name
  • TableName: To specify the table name
  • SelectExpression: To specify the select expression (properties to insert)
  • TableType: To specify the destination table type
  • Executing: To raise an event just before the command is executed

You can specify one or more options, depending on your requirements.

DatabaseName / SchemaName / TableName

The destination table can have any name and can also be located in another database.

Use these options when you need to fully qualify the destination table.

// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

context.Customers.InsertFromQuery(options =>
{
    options.DatabaseName = "MyDatabaseName";
    options.SchemaName = "MySchemaName";
    options.TableName = "MyTableName";
	
    // Select only the properties you want to insert
    options.SelectExpression = x => new
    {
        x.CustomerID,
        x.Name,
        x.Email
    };
});

TableType

Instead of providing a fully qualified destination table name, you can use TableType when the destination entity type is mapped in your DbContext.

EF will automatically use the configured table and column mappings.

By default, properties are matched automatically between the source and the target. The property names must match.

// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

context.Customers.InsertFromQuery(options =>
{
    options.TableType = typeof(BackupCustomer);
	
    // Select only the properties you want to insert
    options.SelectExpression = x => new
    {
        x.CustomerID,
        x.Name,
        x.Email
    };
});

SelectExpression

Use SelectExpression to specify which columns to insert when using options.

This option lets you choose exactly which properties from the source (e.g., Customers) are included in the insert.

By default, properties are matched automatically with the destination table.

When using the options overload, you must specify a SelectExpression to define the columns being inserted.

// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

context.Customers.InsertFromQuery(options =>
{
    options.TableName = "bck_Customer";

    // Select only the properties you want to insert
    options.SelectExpression = x => new
    {
        x.CustomerID,
        x.Name,
        x.Email
    };
});

Executing

Use Executing to raise an event just before the command is executed.

This option is useful to inspect, log, or even modify the generated SQL before it runs.

// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

context.Customers.InsertFromQuery(options =>
{
    // Log the generated SQL before execution
    options.Executing = command =>
    {
        Console.WriteLine(command.CommandText);

        // You can also modify the command text if needed
        // command.CommandText = command.CommandText + " -- custom comment";
    };
	
    options.TableName = "MyTableName";
	
    // Select only the properties you want to insert
    options.SelectExpression = x => new
    {
        x.CustomerID,
        x.Name,
        x.Email
    };
});

FAQ

How to increase the CommandTimeout?

If a timeout occurs, you can increase the command timeout by setting it on the database context before calling the InsertFromQuery method.

This is useful when inserting a large number of rows or when the query takes more time to execute.

// @nuget: Z.EntityFramework.Extensions.EFCore
using Z.EntityFramework.Extensions;

context.Database.SetCommandTimeout(TimeSpan.FromSeconds(60));

context.Customers
    .InsertFromQuery(
        "bck_Customer",
        x => new { x.CustomerID, x.Name, x.Email }
    );

Is the InsertFromQuery feature FREE?

Yes, you don’t need to buy a commercial license to use it.

InsertFromQuery is completely free, including for commercial use.

You can use it in both personal and professional projects without any restriction.

Is there an EF Core equivalent?

No, InsertFromQuery is a unique feature of Entity Framework Extensions.

There is no built-in equivalent in EF Core to insert data directly from a query without loading entities into memory.

In EF Core, you would typically need to:

  • Load entities into memory and call SaveChanges, or
  • Write raw SQL manually

Why is InsertFromQuery faster than SaveChanges, BulkSaveChanges, and BulkInsert?

InsertFromQuery executes a statement directly in SQL, such as INSERT INTO ... SELECT ... FROM ....

This means everything is done on the database side, without loading data into memory.

Other operations usually:

  • Load data into memory
  • Track entities
  • Then send insert commands

Because InsertFromQuery skips all those steps, it is usually much faster and more efficient, especially for large operations.

Summary

InsertFromQuery lets you insert rows directly from LINQ, without loading entities or using change tracking.

It runs entirely in SQL, scales very well, and keeps memory usage low.

This feature is unique to Entity Framework Extensions and is FREE to use.

If you need to:

Together, these methods provide a complete set of set-based operations executed directly at the database level.


Last updated: 2026-05-05
Author: