Remy
Remy

Reputation: 407

SqlDbType.Structured to pass Table-Valued Parameters in NHibernate to select without a :param?

I want to pass a collection of IDs (via table-valued parameter) to an NHibernate IQuery select statement to be used in a join: In native SQL, I can do this (SQLSelectData below). Notice there is no :param in the SqlCommand sql:

public static bool SQLSelectData()
{
    string conACME = System.Configuration.ConfigurationManager
                           .AppSettings["conACME"].ToString();
    DataTable tblBusUnit = new DataTable();
    tblBusUnit.Columns.Add("VALUE", typeof(int));
    DataRow dRow = tblBusUnit.NewRow();
    dRow["Value"] = 1;
    tblBusUnit.Rows.Add(dRow);
    dRow = tblBusUnit.NewRow();
    dRow["Value"] = 6;
    tblBusUnit.Rows.Add(dRow);
    using (SqlConnection con = new SqlConnection(conACME))
    {
        con.Open();

        SqlDataReader rdr;
        SqlCommand cmd = new SqlCommand(
         "select bus_unit_id, BusUnit " +
         "from BusUnit b " + 
         "join @tvpBusUnit s on s.value = b.BUS_UNIT_ID;",
         con);
        cmd.Parameters.Add(
        new SqlParameter()
        {
            ParameterName = "@tvpBusUnit",
            SqlDbType = SqlDbType.Structured,
            TypeName = "dbo.[DLTableTypeInt]",
            Value = tblBusUnit
        });
        rdr = cmd.ExecuteReader();
        while (rdr.Read())
        {
            string stBusUnitId = rdr["bus_unit_id"].ToString();
            string strBusUnit = rdr["BusUnit"].ToString();
            Console.WriteLine("Bus Unit:" + strBusUnit);
        }
    }
    return true;
}

How do I do this in NHibernate? I tried the accepted solution of this question by using the Sql2008Structured and Structured2008Extensions classes.

See code below that calls the SetStructured():

public void SQLSelectTVP<T>()
{
    objNSession = NHibernateHelper.GetCurrentSession(strConn);
    DataTable tblBusUnit = new DataTable();
    tblBusUnit.Columns.Add("VALUE", typeof(int));
    DataRow dRow = tblBusUnit.NewRow();
    dRow["Value"] = 1;
    tblBusUnit.Rows.Add(dRow);
    dRow = tblBusUnit.NewRow();
    dRow["Value"] = 6;
    tblBusUnit.Rows.Add(dRow);
    StringBuilder sbSQL = new StringBuilder();
    sbSQL.Length = 0;
    sbSQL.Append("select bus_unit_id, Business_Unit " +
                 "from tblBUSINESS_UNIT b " +
                 "join @tvpBusUnit s on s.value = b.BUS_UNIT_ID");
    IQuery sqlQuery = objNSession.CreateSQLQuery(sbSQL.ToString());
    sqlQuery.SetStructured("tvpBusUnit", tblBusUnit);
    var lstQR = sqlQuery.List<T>();  

}

However, it errors because there is no :param in the SQL:

Parameter tvpBusUnit does not exist as a named parameter in [select bus_unit_id, Business_Unit from tblBUSINESS_UNIT b join @tvpBusUnit s on s.value = b.BUS_UNIT_ID]

How can I fix this?

Upvotes: 2

Views: 2553

Answers (1)

B Charles H
B Charles H

Reputation: 105

From the link you posted, I think the way you are accessing the structured variable is incorrect.

s.CreateSQLQuery("EXEC some_sp @id = :id, @par1 = :par1")
 .SetStructured("id", dt)

Your code does not use the :id part, that is, :tvpBusUnit.

Also note that the TableType (in TypeName) may have to be created on the DB beforehand. Please check if this is required. From your code:

TypeName = "dbo.[DLTableTypeInt]",

Some discussion on passing table value parameters is provided here but NHibernate has an update without having to create types like this: Passing table valued parameters to NHibernate. But this may need a pull-request. The answer provided in the other post you referred to allows you to create such types, one for each TableType.

Upvotes: 1

Related Questions