参数对象的Dapper自定义映射

时间:2019-09-11 15:17:22

标签: c# .net dapper

我在PostgreSQL中有下表:

CREATE TABLE "user" (
    id     UUID          NOT NULL,
    name   VARCHAR (50)  NULL,
    email  VARCHAR (50)  NOT NULL,
    CONSTRAINT pk_user PRIMARY KEY (id)
);

此数据库中的所有函数在参数名称上均使用下划线(_)前缀。示例:

CREATE OR REPLACE FUNCTION user_read_by_id
(
    _id uuid
)
RETURNS SETOF "user"
LANGUAGE 'plpgsql'
AS 
$BODY$
BEGIN
    RETURN QUERY
    SELECT
        *
    FROM
        "user"
    WHERE
        "id" = _id;
END
$BODY$;

CREATE OR REPLACE FUNCTION user_create
(
    _id     uuid,
    _name   varchar(50),
    _email  varchar(50)
)
RETURNS VOID
LANGUAGE 'plpgsql'
AS
$$
BEGIN
    INSERT INTO "user"
    (
        id,
        name,
        email
    )
    VALUES
    (
        _id,
        _name,
        _email
    );
END
$$

在使用Dapper的C#代码中,我需要能够使用此下划线前缀映射User对象参数,但也要使其也映射回没有下划线前缀的结果集。

public class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}


DefaultTypeMap.MatchNamesWithUnderscores = true;

// This works because I am manually setting the `_id` parameter.
// Ideally, it would match the User object and just use `Id`.

using(var connection = new NpgsqlConnection(ConnectionString))
{
    var results = await connection.QueryAsync<User>(
        "user_read_by_id",
        new { _id = new Guid("38745b2e-436c-4593-827e-6ae123f12db5") },
        commandType: CommandType.StoredProcedure);

    var user = results.SingleOrDefault();
}

// This breaks because the User object doesn't map correctly
// to the parameters of the PgSQL function.

using(var connection = new NpgsqlConnection(ConnectionString))
{
    var results = await connection.ExecuteAsync(
        "user_create",
        new User
        {
            Id = new Guid("38745b2e-436c-4593-827e-6ae123f12db5"),
            Name = "John",
            Email = "j.smith@example.com"
        },
        commandType: CommandType.StoredProcedure);
}

是否可以通过某种方式创建仅自动在param对象上加下划线前缀的映射器?

1 个答案:

答案 0 :(得分:0)

也许有更好的方法可以解决此问题,但是我创建了一种通过反射param对象来处理此问题的方法,并创建了一个新的DynamicParameters参数。

using(var connection = new NpgsqlConnection(ConnectionString))
{
    var results = await connection.ExecuteAsync(
        "user_create",
        ToParam(new User
        {
            Id = new Guid("38745b2e-436c-4593-827e-6ae123f12db5"),
            Name = "John",
            Email = "j.smith@example.com"
        }),
        commandType: CommandType.StoredProcedure);
}

private DynamicParameters ToParam<T>(T obj)
{
    var dp = new DynamicParameters();
    var properties = typeof(T).GetProperties();
    foreach(var property in properties)
    {
        dp.Add($"_{SnakeCase(property.Name)}", property.GetValue(obj));
    }
    return dp;
}

private string SnakeCase(string input)
{
    if(string.IsNullOrWhiteSpace(input))
    {
        return input;
    }
    var startUnderscores = Regex.Match(input, @"^_+");
    return startUnderscores + Regex.Replace(input, @"([a-z0-9])([A-Z])", "$1_$2").ToLowerInvariant();
}