如何从Npgsql和存储过程返回自定义表类型?

时间:2017-02-20 05:27:27

标签: c# postgresql npgsql

我试图根据隐式表类型返回自定义(复合)类型。

我有这个表定义:

CREATE TABLE app_user (id CHAR(36) PRIMARY KEY, name TEXT);

映射到此类定义:

public class ApplicationUser
{
    public string Id { get; set; }
    public string Name { get; set; }
}

通过调用来映射:

NpgsqlConnection.MapCompositeGlobally<ApplicationUser>("app_user");

我尝试使用此存储过程返回记录:

CREATE FUNCTION find_by_id(user_id app_user.id%TYPE) RETURNS app_user AS $$
DECLARE
    found_user app_user;
BEGIN
    SELECT *
    FROM app_user
    WHERE id = user_id
    INTO found_user;

    RETURN found_user;
END
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER;

我从C#调用的是这样的:

ApplicationUser user;
using (NpgsqlConnection db = new NpgsqlConnection(this.connectionString))
{
    db.Open();
    using (NpgsqlCommand cmd = new NpgsqlCommand("find_by_id", db))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("user_id", userId);
        object result = cmd.ExecuteScalar();
        user = result == DBNull.Value ? null : (ApplicationUser)result;
    }
}

但是在将result投射到ApplicationUser时我得到了一个例外:

InvalidCastException: Unable to cast object of type 'System.String' to type 'MyApp.ApplicationUser'.

这显然是因为result只是字符串Id,但为什么不是result我的复合app_user对象?

我还尝试使用out参数返回对象,但遇到了完全相同的异常。我试图用Npgs做什么,或者我是否必须在C#中从各个列手动重新构建ApplicationUser对象?

我使用的是Npgsql v3.2.0和PostgreSQL v9.6。

1 个答案:

答案 0 :(得分:1)

看起来我想通了。结果比我想象的要容易。我需要改变的是从C#调用存储过程的方式。

ApplicationUser user;
using (NpgsqlConnection db = new NpgsqlConnection(this.connectionString))
{
    db.Open();
    using (NpgsqlCommand cmd = new NpgsqlCommand("SELECT find_by_id(@user_id);", db))
    {
        cmd.Parameters.AddWithValue("user_id", userId);
        object result = cmd.ExecuteScalar();
        user = result == DBNull.Value ? null : (ApplicationUser)result;
    }
}

我更喜欢调用存储过程的另一种方式,但至少这有效!