Insertar una entidad si aún no existe

c# dapper dapper-contrib

Pregunta

Hemos estado usando Dapper y Dapper.Contrib por la facilidad con la que podemos realizar operaciones regulares de bases de datos, que ha sido excelente. Sin embargo, desde la presentación de Polly para agregar políticas de reintento para algunas de nuestras operaciones, no he podido encontrar la manera de mantener la misma simplicidad debido a la necesidad de verificar la existencia de un registro antes de ejecutar un reintento.

Aquí hay un ejemplo simplificado de cómo estamos realizando insertos actualmente:

public async Task Insert(Payment payment)
{
    var retryPolicy = // Create using Polly.
    using (var connection = new SqlConnection(_connectionString))
    {
        var dao = MapToDao(payment);
        await retryPolicy.ExecuteAsync(() => connection.InsertAsync(dao));
    }
}

[Table("Payment")]
public class PaymentDao
{
    [ExplicitKey]
    public Guid PaymentId { get; set; }
    // A whole bunch of properties omitted for brevity
}

donde Payment es nuestro modelo de dominio, y PaymentDao es nuestro objeto de acceso a datos.

Realmente tenemos lógica en el servicio que llama Insert que verifica explícitamente si hay duplicados, pero esto es negado por la política de reintento. Esto significa que desde la presentación de Polly , estamos viendo una pequeña cantidad de pagos duplicados que se insertan.

Puedo solucionar esto haciendo lo siguiente:

public async Task Insert(Payment payment)
{
    var retryPolicy = // Create using Polly.
    using (var connection = new SqlConnection(_connectionString))
    {
        var dao = MapToDao(payment);

        await retryPolicy.ExecuteAsync(() => connection.ExecuteAsync(
            @"IF ((SELECT COUNT(*) FROM dbo.Payment WHERE SubscriptionId = @subscriptionId) = 0)
            BEGIN
                INSERT INTO Payment
                (
                    PaymentId,
                    SubscriptionId,
                    // Lots of columns omitted for brevity.
                )
                VALUES
                (
                    @PaymentId,
                    @SubscriptionId,
                    // Lots of values omitted for brevity.
                )
            END",
            new
            {
                dao.PaymentId,
                dao.SubscriptionId,
                // Lots of properties omitted for brevity.
            }));
    }
}

Sin embargo, como puede ver, se vuelve bastante largo. ¿Hay una manera más simple de hacer esto?

Respuesta aceptada

Puede considerar la alternativa de verificar primero usando el modelo y luego realizar la inserción dado que la búsqueda usa menos parámetros

using (var connection = new SqlConnection(_connectionString)) {
    var dao = MapToDao(payment);
    var sql = "SELECT COUNT(1) FROM dbo.Payment WHERE SubscriptionId = @subscriptionId";
    await retryPolicy.ExecuteAsync(async () => { 
        var exists = await connection.ExecuteScalarAsync<bool>(sql, new {dao.SubscriptionId});
        if(!exists) {
            await connection.InsertAsync(dao);
        }
    });
}


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué