0

I have a common dapper function to get list<model> using QueryAsync of dapper

the function looks like below

public async Task<object> QueryAsync(string spName, DynamicParameters p)
{
    return await Task.Run(async () =>
    {
        object obj = new object();
        IList objectList = obj as IList;
        using (SqlConnection conn = new SqlConnection(_connStr))
        {
            try
            {
                conn.Open();
                obj = (List<object>)await conn.QueryAsync<object>(sql: spName, param: p, commandType: CommandType.StoredProcedure);
            }
            catch (Exception ex)
            {
                Utils.Logger.Instance.LogException(ex);
            }
            conn.Close();
        }
        return obj;
    });
}

now I am calling this method from my businessLogic Layer like below

public async Task<List<GetTemplates>> GetDocTemplates(string TemplateName, int AccountId)
{
    _Parameters.Add("@SP_TemplateName", TemplateName, dbType: DbType.String, direction: ParameterDirection.Input);
    _Parameters.Add("@SP_AccountId", AccountId, dbType: DbType.Int32, direction: ParameterDirection.Input);
    return (List<GetTemplates>)await _Dapper.QueryAsync("[dbo].[GetDocTemplates]", _Parameters);
}

but I am getting the following error.

Unable to cast object of type 'System.Collections.Generic.List1[System.Object]' to type 'System.Collections.Generic.List1[DocPro.DMS.BusinessEntities.Admin.GetTemplates]'.

I don't know what is wrong with the above code.

Ibrahim shaikh
  • 235
  • 2
  • 15
  • Does this answer your question? [Convert List to List](https://stackoverflow.com/questions/1817300/convert-listderivedclass-to-listbaseclass) – GSerg Jan 20 '23 at 09:35
  • Does this answer your question? [Cannot convert from List to List](https://stackoverflow.com/q/16966961/11683) – GSerg Jan 20 '23 at 09:36
  • No it does not answered as I have an object. – Ibrahim shaikh Jan 20 '23 at 09:41
  • How does that make it different? – GSerg Jan 20 '23 at 09:41
  • 2
    @TWMTV what you have here is a `List` where each object is a `DapperRow`; now, `List` isn't variant in the first place, so even if the objects were `GetTemplates` instances, you can't cast a `List` to a `List` - but again, to emphasize: **there are no `GetTemplates` objects here**, so it *certainly* can't magic them into that shape. If you want a `List`: *tell Dapper that* – Marc Gravell Jan 20 '23 at 10:00

1 Answers1

1

Dapper creates the list here. If you want it to be a list of GetTemplates, then you're going to have to tell dapper about that, presumably by making the method generic and calling _Dapper.QueryAsync<GetTemplates>(...). That said... honestly, this method isn't really adding anything except connection setup and logging - the Task.Run is unnecessary, the blind catch that swallows failure is actively dangerous, and DynamicParameters is the least preferred way of passing parameters to dapper. Suggestion:

public async Task<List<T>> QueryListAsync<T>(string spName, object parameters)
{
    using var conn = new SqlConnection(_connStr);
    try
    {
        return (await conn.QueryAsync<T>(sql: spName, param: parameters, commandType: CommandType.StoredProcedure)).AsList();
    }
    catch (Exception ex)
    {
        Utils.Logger.Instance.LogException(ex);
        throw;
    }
}
...
public Task<List<GetTemplates>> GetDocTemplates(string TemplateName, int AccountId)
{
    return _Dapper.QueryListAsync<GetTemplates>("[dbo].[GetDocTemplates]", new {
        SP_TemplateName = TemplateName,
        SP_AccountId = AccountId
    });
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks it worked for me, but I have few questions it might sound stupid. – Ibrahim shaikh Jan 20 '23 at 10:14
  • 1) Why DynamicParameters is least preferred? – Ibrahim shaikh Jan 20 '23 at 10:15
  • I have few scenrio where I have a parameter with `ParameterDirection.Output` and `ParameterDirection.ReturnValue` – Ibrahim shaikh Jan 20 '23 at 10:18
  • how can I use this? – Ibrahim shaikh Jan 20 '23 at 10:18
  • help would be appreciated as I will do changes in my whole application as per your suggestion – Ibrahim shaikh Jan 20 '23 at 10:19
  • 1
    @TWMTV for simple scenarios, the simple anon type option is simply more efficient; `DynamicParameters` is required for output / return-value scenarios, but you can still use that in the above by passing a `DynamicParameters` object as the `object parameters` arg - it'll still work; so here we allow more flexibility; use `DynamicParameters` when needed, and allow simple anon-types when not needed – Marc Gravell Jan 20 '23 at 10:25