CSharp · Console
// Entity Framework Extensions
// Doc: https://entityframework-extensions.net/temporary-table#usepermanenttable
// @nuget: Microsoft.EntityFrameworkCore.SqlServer
// @nuget: Z.EntityFramework.Extensions.EFCore
/*
## 🏷️ UsePermanentTable
Creates a **permanent table** instead of a temporary one.
By default, the library uses temporary tables that are automatically dropped once the operation is finished.
When `UsePermanentTable = true;`, the staging table is created as a regular permanent table.
If you also want to **keep the data after the operation**, combine it with `TemporaryTablePersist = true;`.
In this case, the permanent table will **not be dropped**, allowing you to reuse the data until you decide to remove it manually
### 💡 Why it can be useful
* **Persist data beyond the connection** → Unlike temp tables, permanent tables are not tied to the connection lifecycle.
* **Reuse data across sessions** → Keep the staging table available even if the connection closes or the application restarts.
* **Integration workflows** → Useful when another process, job, or service needs to consume the staged data later.
* **Flexible cleanup** → You decide when to drop the table, instead of SQL Server doing it automatically.
⚠️ **Important note**: Since the table is permanent, you are responsible for eventually **dropping it manually** if you don’t need it anymore, otherwise it will stay in your database.
*/
using System;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
public class Program
{
public static void Main()
{
using (var context = new EntityContext())
{
context.Database.EnsureCreated();
}
using (var context = new EntityContext())
{
// minimum 11 customers to use a temporary table
var customers = GenerateCustomer(11);
string permanentTableName = "";
context.BulkMerge(customers, options =>
{
options.UsePermanentTable = true;
options.TemporaryTablePersist = true;
options.BulkOperationExecuted = op =>
{
// Capture the resolved temporary table name after execution
permanentTableName = op.ResolvedTemporaryTableName;
};
});
Console.WriteLine($"Table: {permanentTableName}");
FiddleHelper.WriteTable(context.Customers.AsNoTracking());
}
}
public static List<Customer> GenerateCustomer(int max)
{
var list = new List<Customer>();
for (int i = 0; i < max; i++)
{
list.Add(new Customer() { Name ="Customer_" + i});
}
return list;
}
public class EntityContext : DbContext
{
public EntityContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(new SqlConnection(FiddleHelper.GetConnectionStringSqlServer()));
base.OnConfiguring(optionsBuilder);
}
public DbSet<Customer> Customers { get; set; }
}
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
public Boolean IsActive { get; set; }
}
}