How to return custom table types from Npgsql and s

2019-02-19 16:25发布

I'm trying to return a custom (composite) type based on an implicit table type.

I have this table definition:

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

Which is mapped to this class definition:

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

Which is mapped by calling:

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

And I'm trying to return a record with this stored procedure:

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;

Which I'm calling from C# like this:

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;
    }
}

But I get an exception when casting result to ApplicationUser:

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

This is clearly because result is just the string Id, but why isn't result my composite app_user object?

I've also tried to return the object with an out parameter, but ran into the exact same exception. Is what I'm trying to do possible with Npgsql, or do I have to re-build the ApplicationUser object manually in C# from the individual columns?

I'm using Npgsql v3.2.0 and PostgreSQL v9.6.

1条回答
时光不老,我们不散
2楼-- · 2019-02-19 16:37

Looks like I figured it out. Turned out to be easier than I thought. All I needed to change was the way the stored procedure was called from 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;
    }
}

I preferred the other way of invoking the stored procedure, but at least this works!

查看更多
登录 后发表回答