Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert List<Dapper.SqlMapper.FastExpando> to runtime type (List<IDictionary<string,object>>)

I'm using a method that has a return signatur of IEnumerable<dynamic>. At runtime for a particular call it is returning List<Dapper.SqlMapper.FastExpando>.

var x0 = repo.Find(proc, param); 
//x0 runtime type is {List<Dapper.SqlMapper.FastExpando>}

LINQPad.Extensions.Dump indicates the runtime type of x0 is: List<IDictionary<String, Object>> but I can't seem to cast/convert to List<IDictionary<String, Object>>. Here is a screenshot of the Linqpad Dump: enter image description here

Ultimately I need to join all the Values from each Dictionary to a single IEnumerable<DateTime>.

IEnumerable<DateTime> GetDates(int productId) 
{
    const string proc = "[dbo].[myproc]";
    dynamic param = new { Id = "asdf" };
    var x0 = repo.Find(proc, param); 
    //...
    //linq conversion from x0 to IEnumerable<DateTime> here.
}

Error I'm getting

List<IDictionary<String, Object>> x5 = repo.Find(proc, param);

results in:

RuntimeBinderException: Cannot implicitly convert type 'object' to
 'System.Collections.Generic
     .List<System.Collections.Generic.IDictionary<string,object>>'.
An explicit conversion exists (are you missing a cast?)

BACKGROUND: I am using a Dapper wrapper and can't change the database table/stored procedure which returns denormalized results. Instead of 100 rows of 1 data element, the sproc returns 1 row of 100 columns. I wanted to avoid creating a class to represent the 100 columns and want to take advantage of Dapper's automagical ability to transpose the column data to rows via an IDictionary of columnName, columnValue.

UPDATE This appears to be an issue with the dynamic param. When specified inline, it works. If specified locally and then passes as a parameter, it fails.

IEnumerable<DateTime> GetDates(int productId) 
{
    const string proc = "[dbo].[myproc]";
    dynamic param = new { Id = "asdf" };

    //next line throws RuntimeBinderException: 'object' does not 
    //contain a definition for 'First'.
    //IDictionary<String, object> x0 = repo.Find(proc, param).First();

    //this succeeds:
    IDictionary<String, object> x0 = repo.Find(proc, new { Id = "asdf" }).First();

    IEnumerable<DateTime> qry2
       = x0.Values.AsQueryable()
           .Where(x => x != null)
           .Select(x => (DateTime) x);
    return qry2;
}

Here are the signatures for Find and Query:

//Repository::Find
public IEnumerable<dynamic> Find(string procName, object param = null)

//Dapper SqlMapper::Query
public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
like image 991
Jay Walker Avatar asked Jul 04 '26 10:07

Jay Walker


2 Answers

You can use the LINQ Cast method to cast each item in the sequence.

List<IDictionary<String, Object>> data = repo.Find(proc, param)
    .AsEnumerable()
    .Cast<IDictionary<String, Object>>()
    .ToList();
like image 98
Servy Avatar answered Jul 06 '26 05:07

Servy


Repo.Find does not return an IEnumerable<dynamic>. It returns object. If you are sure it will always return a List<IDictionary<String, Object>> just do this:

List<IDictionary<String, Object>> x5 = (List<IDictionary<String, Object>>)repo.Find(proc, param);
like image 33
It'sNotALie. Avatar answered Jul 06 '26 04:07

It'sNotALie.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!