June 02 2025
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
public bool InStock { get; set; }
}
Install-Package Z.Dapper.Plus
Install-Package CsvHelper
DapperPlusManager.Entity<Product>()
.Table("Products") // Table name in SQL Server
.Map(p => p.ProductId)
.Map(p => p.Name)
.Map(p => p.Category)
.Map(p => p.Price)
.Map(p => p.InStock);
using CsvHelper;
using System.Globalization;
public static List<Product> ParseCsv(string filePath)
{
using var reader = new StreamReader(filePath);
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
return csv.GetRecords<Product>().ToList();
}
public void ImportProducts(string csvFilePath, IDbConnection dbConnection)
{
var products = ParseCsv(csvFilePath);
try
{
dbConnection.BulkInsert(products);
Console.WriteLine($"{products.Count} products imported successfully.");
}
catch (Exception ex)
{
Console.WriteLine("Something went wrong during bulk insert: " + ex.Message);
// Optional: log or retry
}
}
public async Task ImportProductsAsync(
string csvFilePath,
IDbConnection dbConnection,
CancellationToken cancellationToken)
{
var products = ParseCsv(csvFilePath);
try
{
cancellationToken.ThrowIfCancellationRequested();
await dbConnection.BulkInsertAsync(products, cancellationToken);
Console.WriteLine($"{products.Count} products imported successfully (async).");
}
catch (OperationCanceledException)
{
Console.WriteLine("Import was canceled.");
}
catch (Exception ex)
{
Console.WriteLine("Bulk insert failed: " + ex.Message);
}
}
products = products
.Where(p => !string.IsNullOrWhiteSpace(p.Name) && p.Price >= 0)
.ToList();
var invalidProducts = products.Where(p => p.Price < 0).ToList();
if (invalidProducts.Any())
{
// show warning or log it
}
public class ProductService
{
private readonly IDbConnection _connection;
private readonly Random _random = new();
private static readonly string[] SampleNames = new[]
{
"Mouse", "Keyboard", "Monitor", "Speaker", "Tablet",
"Webcam", "Laptop", "Headphones", "Microphone", "SSD"
};
public ProductService(IDbConnection connection)
{
_connection = connection;
}
public List<Product> GenerateProducts(int count)
{
var list = new List<Product>();
for (int i = 0; i < count; i++)
{
list.Add(new Product
{
Name = SampleNames[_random.Next(SampleNames.Length)],
Price = Math.Round((decimal)(_random.NextDouble() * 500), 2)
});
}
return list;
}
public async Task InsertWithDapperAsync(List<Product> products)
{
const string sql = "INSERT INTO Products (Name, Price) VALUES (@Name, @Price)";
foreach (var product in products)
{
await _connection.ExecuteAsync(sql, product);
}
}
public async Task InsertWithDapperPlusAsync(List<Product> products)
{
await _connection.BulkInsertAsync(products);
}
}
DapperPlusManager.Entity<Product>()
.Table("Products")
.Map(p => p.Name)
.Map(p => p.Price);
// Register services
builder.Services.AddSingleton<IDbConnection>(_ =>
{
var conn = new SqliteConnection("Data Source=products.db");
Batteries.Init();
conn.Open();
EnsureDatabaseSchema(conn);
return conn;
});
app.MapPost("/seed/dapper", async (int count, ProductService service) =>
{
var products = service.GenerateProducts(count);
var sw = System.Diagnostics.Stopwatch.StartNew();
await service.InsertWithDapperAsync(products);
sw.Stop();
return Results.Ok($"Inserted {count} records with Dapper in {sw.ElapsedMilliseconds}ms");
});
app.MapPost("/seed/dapperplus", async (int count, ProductService service) =>
{
var products = service.GenerateProducts(count);
var sw = System.Diagnostics.Stopwatch.StartNew();
await service.InsertWithDapperPlusAsync(products);
sw.Stop();
return Results.Ok($"Inserted {count} records with Dapper Plus in {sw.ElapsedMilliseconds}ms");
});
1. Design Patterns that Deliver
This isn’t just another design patterns book. Dive into real-world examples and practical solutions to real problems in real applications.Check out it here.
Go-to resource for understanding the core concepts of design patterns without the overwhelming complexity. In this concise and affordable ebook, I've distilled the essence of design patterns into an easy-to-digest format. It is a Beginner level. Check out it here.
Every Monday morning, I share 1 actionable tip on C#, .NET & Arcitecture topic, that you can use right away.
Join 15,250+ subscribers to improve your .NET Knowledge.
Subscribe to the TheCodeMan.net and be among the 15,250+ subscribers gaining practical tips and resources to enhance your .NET expertise.