Skip to main content

đŸŽ€ Questions techniques pour entretiens/missions

Q1 : Quelle est la diffĂ©rence entre Dapper et Entity Framework Core ?​

Réponse attendue :

  • Dapper : Micro-ORM, vous Ă©crivez le SQL, mapping automatique uniquement

    • Avantages : Performance maximale, contrĂŽle total du SQL
    • InconvĂ©nients : Plus de code Ă  Ă©crire, pas de migrations automatiques
  • EF Core : ORM complet, gĂ©nĂšre le SQL pour vous

    • Avantages : DĂ©veloppement rapide, migrations automatiques, change tracking
    • InconvĂ©nients : SQL gĂ©nĂ©rĂ© parfois non optimal, courbe d'apprentissage

Réponse courte : "Dapper pour la performance et le contrÎle, EF Core pour la productivité"


Q2 : Pourquoi utiliser Dapper plutît qu'ADO.NET pur ?​

Réponse attendue :

ADO.NET pur :

// Beaucoup de code boilerplate
var command = new SqlCommand(sql, connection);
var reader = command.ExecuteReader();
var products = new List<Product>();
while (reader.Read())
{
products.Add(new Product
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Price = reader.GetDecimal(2)
});
}

Dapper :

// Mapping automatique, moins de code
var products = await connection.QueryAsync<Product>(sql);

Réponse courte : "Dapper = performance d'ADO.NET + productivité du mapping automatique"


Q3 : Comment Ă©vitez-vous les injections SQL avec Dapper ?​

Réponse attendue :

// ❌ Mauvais - injection SQL
var sql = $"SELECT * FROM Users WHERE Username = '{username}'";

// ✅ Bon - paramĂštres sĂ©curisĂ©s
var sql = "SELECT * FROM Users WHERE Username = @Username";
var user = await connection.QueryFirstOrDefaultAsync<User>(sql, new { Username = username });

Réponse courte : "Toujours utiliser des paramÚtres avec @, jamais de concaténation de strings"


Q4 : Comment gĂ©rer les transactions avec Dapper ?​

Réponse attendue :

using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync();
using var transaction = await connection.BeginTransactionAsync();

try
{
await connection.ExecuteAsync(sql1, param1, transaction);
await connection.ExecuteAsync(sql2, param2, transaction);
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}

RĂ©ponse courte : "BeginTransaction, passer la transaction Ă  chaque requĂȘte, Commit/Rollback"


Q5 : Qu'est-ce que le problĂšme N+1 et comment l'Ă©viter ?​

Réponse attendue :

ProblĂšme :

// 1 requĂȘte pour les produits + N requĂȘtes pour les catĂ©gories
var products = await GetAllProductsAsync(); // 1 requĂȘte
foreach (var product in products)
{
product.Category = await GetCategoryAsync(product.CategoryId); // N requĂȘtes
}

Solution :

// 1 seule requĂȘte avec JOIN
var sql = @"
SELECT p.*, c.Id, c.Name
FROM Products p
INNER JOIN Categories c ON p.CategoryId = c.Id";

var products = await connection.QueryAsync<Product, Category, Product>(
sql, (product, category) => { product.Category = category; return product; });

RĂ©ponse courte : "Éviter les requĂȘtes en boucle, utiliser des JOIN pour tout rĂ©cupĂ©rer en une fois"


Q6 : Comment faire du multi-mapping avec Dapper ?​

Réponse attendue :

var sql = @"
SELECT p.Id, p.Name, p.Price, c.Id, c.Name
FROM Products p
INNER JOIN Categories c ON p.CategoryId = c.Id";

var products = await connection.QueryAsync<Product, Category, Product>(
sql,
(product, category) =>
{
product.Category = category;
return product;
},
splitOn: "Id"); // Dapper split ici pour séparer Product et Category

Point clĂ© : Le splitOn indique oĂč Dapper doit "couper" pour crĂ©er le second objet.


Q7 : Le projet utilise dĂ©jĂ  EF Core, pourquoi ajouter Dapper ?​

Réponse pragmatique :

"On peut combiner les deux ! EF Core pour le CRUD standard, Dapper pour les requĂȘtes complexes ou critiques en performance."

Exemple :

public class ProductService
{
private readonly AppDbContext _context; // EF Core
private readonly IDbConnection _connection; // Dapper

// CRUD simple avec EF Core
public async Task<Product> GetByIdAsync(int id)
=> await _context.Products.FindAsync(id);

// Rapport complexe avec Dapper
public async Task<List<SalesReport>> GetMonthlySalesAsync()
=> (await _connection.QueryAsync<SalesReport>(
"sp_GetMonthlySales",
commandType: CommandType.StoredProcedure)).ToList();
}

Q8 : Comment testez-vous du code utilisant Dapper ?​

Réponse attendue :

Approche 1 : Base de test réelle (recommandé)

[TestInitialize]
public async Task Setup()
{
// Utiliser une vraie DB de test (SQLite en mémoire par exemple)
_connection = new SqliteConnection("Data Source=:memory:");
await _connection.OpenAsync();
await _connection.ExecuteAsync("CREATE TABLE Products (...)");
}

Approche 2 : Abstraction avec interface

public interface IProductRepository
{
Task<List<Product>> GetAllAsync();
}

// Tests avec mock du repository
var mockRepo = new Mock<IProductRepository>();

Réponse courte : "Préférer une vraie DB de test, ou abstraire avec des interfaces pour mocker"


Q9 : La requĂȘte Dapper est lente, comment diagnostiquer ?​

Réponse pratique :

  1. Activer le profiling SQL
// Utiliser un outil comme MiniProfiler
var stopwatch = Stopwatch.StartNew();
var products = await connection.QueryAsync<Product>(sql);
stopwatch.Stop();
_logger.LogInformation("Query took {Ms}ms", stopwatch.ElapsedMilliseconds);
  1. Vérifier le SQL généré

    • Copier le SQL avec les paramĂštres dans SSMS/Azure Data Studio
    • VĂ©rifier le plan d'exĂ©cution
    • Ajouter des index si nĂ©cessaire
  2. ProblÚmes fréquents :

    • Pas d'index sur les colonnes du WHERE/JOIN
    • SELECT * au lieu de colonnes spĂ©cifiques
    • ProblĂšme N+1

Q10 : Comment gĂ©rer les connexions avec Dapper ?​

Réponse attendue :

✅ Bon : using + pool automatique

public async Task<List<Product>> GetAllAsync()
{
using var connection = new SqlConnection(_connectionString);
// Pas besoin d'OpenAsync, Dapper le fait automatiquement
return (await connection.QueryAsync<Product>(sql)).ToList();
}
// Connection retournée au pool automatiquement

❌ Mauvais : rĂ©utiliser la mĂȘme connection

private SqlConnection _connection; // NON ! ProblĂšme de threading

public async Task<List<Product>> GetAllAsync()
{
return (await _connection.QueryAsync<Product>(sql)).ToList();
}

Réponse courte : "Toujours utiliser using pour les connexions, le pool ADO.NET gÚre la réutilisation"


📋 Checklist de prĂ©paration​

Avant un entretien/mission sur Dapper, assurez-vous de pouvoir :

  • Expliquer la diffĂ©rence Dapper vs EF Core
  • Écrire une requĂȘte avec paramĂštres sĂ©curisĂ©s
  • Faire un multi-mapping avec JOIN
  • Expliquer le problĂšme N+1
  • GĂ©rer une transaction
  • Appeler une stored procedure
  • Expliquer comment tester du code Dapper
  • Diagnostiquer une requĂȘte lente