IIOT-Zero
IIOT-Zero

Reputation: 159

Dapper for Table Valued parameter in generic implementation

Following the post Using Dapper.TVP TableValueParameter with other parameters I have been able to execute table valued parameter but my question is regarding part of its implementation. Procedure seems to be working but how can i make this implementation more generic? Adding parameters in DynamicParameters with 'new {}' is very specialized implementation according requirement. I want to be able to specify my parameter name as well.. for example

public IEnumerable<TCustomEntity> SqlQuery<TCustomEntity>(string query, IDictionary<string, object> parameters,
            CommandType commandType) where TCustomEntity : class
        {
            DataTable dt;
            DynamicParameters dp;
            var sqlConnection = _context.Database.Connection;
            try
            {

                if (sqlConnection.State == ConnectionState.Closed)
                {
                    sqlConnection.Open();
                }


                var dynamicParameters = new DynamicParameters();
                if (parameters != null)
                    foreach (var parameter in parameters)
                    {

                        if (parameter.Value is int)
                            dynamicParameters.Add(parameter.Key, parameter.Value, DbType.Int32);
                        else if (parameter.Value is string)
                            dynamicParameters.Add(parameter.Key, parameter.Value.ToString(), DbType.String);
                        else if (parameter.Value is DateTime)
                            dynamicParameters.Add(parameter.Key, parameter.Value, DbType.DateTime);
                        else if (parameter.Value is Decimal)
                            dynamicParameters.Add(parameter.Key, parameter.Value, DbType.Decimal);
                         else if (parameter.Value is DataTable)
                         {
                             dt = (DataTable)parameter.Value;
                             dt.SetTypeName(dt.TableName);
                             var parameterName = parameter.Key;

                             dp = new DynamicParameters(new { TVPName = dt });
                             // Here i want TVPName replaced with parameterName/parameter.Key but it doesn't seem possible
                             dynamicParameters.AddDynamicParams(dp);



                         }
                        else
                         dynamicParameters.Add(parameter.Key,  parameter.Value);
                    }
                var test = sqlConnection.Query<TCustomEntity>(query, dynamicParameters, commandType: commandType);
                return test;
            }
            finally
            {
                sqlConnection.Close();
            }
        }

Any advice how may i proceed on the issue by making parameter name more generic? If not, it will be specialized implementation each time i use Table value parameter

Upvotes: 3

Views: 7425

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062520

It isn't obvious to me that any of that is necessary, since:

  1. DynamicParameters is perfectly happy with TVPs as direct elements,
  2. all of the data types shown would be handled automatically
  3. dapper works happily with dictionaries
  4. dapper already opens and closed the connection appropriately if it isn't open when invoked

It seems to me that the only interesting step here is the SetTypeName, which could be done:

foreach(object val in parameters.Values)
{
    if(val is DataTable) {
        var dt = (DataTable)val;
        dt.SetTypeName(dt.TableName);
    }
}

And then pass your original parameters object in:

return sqlConnection.Query<TCustomEntity>(query, parameters, commandType: commandType);

That leaves just:

public IEnumerable<TCustomEntity> SqlQuery<TCustomEntity>(string query,
    IDictionary<string, object> parameters, // suggestion: default to null
    CommandType commandType // suggestion: default to CommandType.Text
) where TCustomEntity : class
{
    var sqlConnection = _context.Database.Connection;

    if (parameters != null) {
        foreach (object val in parameters.Values) {
            if (val is DataTable) {
                var dt = (DataTable)val;
                // suggestion: might want to only do if dt.GetTypeName() is null/""
                dt.SetTypeName(dt.TableName);
            }
        }
    }

    return sqlConnection.Query<TCustomEntity>(query, parameters,
        commandType: commandType);
}

Upvotes: 5

Related Questions