2016-06-14 51 views
0

我的問題是這樣的。
enter image description here動態類型無法從web api返回始終不同的一組列

由於在表格中的項目列表上旋轉,我有一組不斷變化的列。基本上,您在上圖中看到的每一列都是數據庫表中的一行。我想在前端顯示一行作爲一行。如何從控制器或API返回這種動態類型?

我一直在嘗試使用這樣的代碼。

List<dynamic> items = repository.GetAll(); 
foreach(var item in items){ 
var properties = item.GetType().GetProperties(BindingFlags.Public); 
    foreach (var property in properties) { 
     var PropertyName = property.Name; 
     var PropertyValue = item.GetType().GetProperty(property.Name).GetValue(item, null); 
     model.Add(PropertyName, PropertyValue); 
    } 
} 

但是GetProperties()從動態「item」中不返回任何內容。我也嘗試使用item.GetType()。GetFields()無濟於事。
我怎麼能得到從c#中的動態數據類型的列名和值,當我不知道該列的名稱?或者只是從api返回動態對象?謝謝。

以下是存儲庫代碼。

public IEnumerable<dynamic> GetAll() 
{ 
var items = context.Database.SqlQuery<dynamic>(
        "DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX)" + 

     "SET @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(FormDetails.Name)" + 
       "  from Value" + 
     " left join ValueDetails" + 
     " on Value.Id = ValueDetails.ValueId" + 
     " left" + 
       " join FormDetails" + 


       " on ValueDetails.FormDetailsId = FormDetails.Id" + 
       "   ORDER BY 1" + 
       " FOR XML PATH(''), TYPE" + 
       " ).value('.', 'NVARCHAR(MAX)'), 1, 1, '')" + 

       " SET @sql = 'SELECT Id, FormId, CreatedDateTime, ' + @cols + '" + 
       "  FROM" + 
       " (" + 
        " select Value.Id, Value.FormId, FormDetails.Name, ValueDetails.Value, Value.CreatedDateTime" + 

        "  from Value" + 
        "  left join ValueDetails" + 

        "  on Value.Id = ValueDetails.ValueId" + 

        " left" + 
        "  join FormDetails" + 

       " on ValueDetails.FormDetailsId = FormDetails.Id" + 
        " ) s" + 
       " PIVOT" + 
        "(" + 
         "MAX(Value) FOR Name IN(' + @cols + ')" + 
        ") p order by CreatedDateTime desc '" + 

     " EXECUTE(@sql)").ToList(); 
     return items; 
} 

這裏有一些信息。基本上,我的存儲庫從本頁頂部的第一張圖像中返回數據。但是當我將這些數據返回到前端時,這就是它的樣子。對象是有,但沒有屬性...

enter image description here

enter image description here

回答

1

與您的代碼的問題是不是得到的屬性列表爲空,因爲他們是真正不存在。如果SqlQuery<T>不在類型T上,則不會填充屬性;您正在傳遞dynamic,即轉換爲System.Object

解決此問題的一個訣竅是動態檢索列名稱,並從中構建一個ExpandoObject。該技術描述於here

static IList<dynamic> Read(DbDataReader reader) { 
    var res= new List<Dictionary<string,object>>(); 
    foreach (var item in reader) { 
     IDictionary<string,object> expando = new ExpandoObject(); 
     foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(item)) { 
      var obj = propertyDescriptor.GetValue(item); 
      expando.Add(propertyDescriptor.Name, obj); 
     } 
     res.Add(expando); 
    } 
    return res; 
} 

有了這個方法,調用

using (var cmd = ctx.Database.Connection.CreateCommand()) { 
    ctx.Database.Connection.Open(); 
    cmd.CommandText = ...; // Your big SQL goes here 
    using (var reader = cmd.ExecuteReader()) { 
     return Read(reader).ToList(); 
    } 
} 

一旦你的倉庫開始返回ExpandoObject S,你的檢索性能代碼可以使用代碼查詢IDictionary<string,object>更換,由ExpandoObject實現的接口:

IDictionary<string,object> properties = item as IDictionary<string,object>; 
if (properties != null) { 
    foreach (var p in properties) { 
     model.Add(p.Key, p.Value); 
    } 
} 
+0

我給你一個鏡頭,讓你知道發生了什麼。謝謝。 – joel1618

+0

Omg有效。非常感謝。 2天將我的頭撞在牆上。我想讀者不能解釋動態項目的屬性? – joel1618

+0

@ joel1618在引擎蓋下,沒有像'動態'這樣的東西(這正是Servy想要暗示的)。當你編寫'dynamic' C#代替'object'時,代碼會使用未知的方法和屬性進行編譯,假設你將在運行時提供一個實現。當你調用'SqlQuery '時,它既是'T'的屬性,也是查詢中決定返回列的列名。例如,'SqlQuery '看到查詢返回'FormId',所以它在'T'上查找'FormId',它是'dynamic',即'object'。 'FormId'不在那裏,所以它被跳過。 – dasblinkenlight