簡體   English   中英

如何轉換清單 <Dapper.SqlMapper.FastExpando> 到運行時類型(列表 <IDictionary<string,object> &gt;)

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

我正在使用具有IEnumerable<dynamic>的返回符號的方法。 在運行特定調用時,它將返回List<Dapper.SqlMapper.FastExpando>

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

LINQPad.Extensions.Dump指示x0的運行時類型為: List<IDictionary<String, Object>>但我似乎無法LINQPad.Extensions.Dump轉換/轉換為List<IDictionary<String, Object>> 這是Linqpad轉儲的屏幕截圖: 在此處輸入圖片說明

最終,我需要將每個字典中的所有值連接到單個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.
}

我收到錯誤

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

結果是:

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?)

背景:我使用的是Dapper包裝程序,無法更改返回非規范化結果的數據庫表/存儲過程。 sproc返回100列的1行,而不是100行的1個數據元素。 我想避免創建一個代表100列的類,並想利用Dapper的自動能力通過columnName,columnValue的IDictionary將列數據轉置為行。

更新這似乎是動態參數的問題。 內聯指定時,它可以工作。 如果在本地指定,然后作為參數傳遞,則失敗。

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

這是“ FindQuery的簽名:

//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)

您可以使用LINQ Cast方法Cast轉換序列中的每個項目。

List<IDictionary<String, Object>> data = repo.Find(proc, param)
    .AsEnumerable()
    .Cast<IDictionary<String, Object>>()
    .ToList();

Repo.Find不返回IEnumerable<dynamic> 它返回object 如果您確定它將始終返回List<IDictionary<String, Object>> ,請執行以下操作:

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

因此,問題在於,通過將param指定為dynamic會導致方法被動態調用,並且擴展方法無法再被鏈接。

因此,您可以只使用var而不使用dynamic

 var param = new { Id = "asdf" };
 var data = repo.Find(proc, param)
.Cast<IDictionary<String, Object>>()
.ToList();

或者只是在調用之前將dynamic參數投射到object

 var data = repo.Find(proc, (object)param)
.Cast<IDictionary<String, Object>>()
.ToList();

或者,如果Find確實返回了System.Collections.Generic.List<Dapper.SqlMapper.FastExpando>的運行時類型,只需將結果System.Collections.Generic.List<Dapper.SqlMapper.FastExpando>dynamic ,以確保在分配它之前使用它的運行時類型,將其分配給它很重要IEnumerable<>特別是因為它是協變量類型( IList<>List<>將失敗)。

IEnumerable<IDictionary<String, Object>> data = (dynamic) repo.Find(proc, param);

不要從您的方法中動態傳遞回去。 Dapper具有ToList <T>擴展方法,因此您可以轉換為任何受支持的類型。 在這種情況下,如果您確實需要低級別的關聯數組,請傳回List <字典<字符串<對象,>>。

同樣值得注意的是,C#dynamic不會跨程序集邊界封送,因此這可能是您遇到的一個問題。 如果要在程序集之間進行封送處理,則需要使用Expando,List <Dictionary <字串,對象>>或兩個程序集都引用的其他類型。

說明

這是Dapper SQLMapper源的舊版本,其中包括FastExpando(第941行)。 注意FastExpando的類定義。

私有類FastExpando:System.Dynamic.DynamicObject,IDictionary <字符串,對象>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM