一般我們寫class常常都會用到return,不管是傳回string int array datatable等等這些行型態的物件,想當然爾這些class改過後當然還是會傳回來"某"些東西,這是問題就大啦,聽我徐徐道來,首先就是 Anonymous Type這東東
話說..linq這技術已經跑了一陣子了,我還沒有跟上這好用的新技術(是人家說的),這好像給它真的有點遜,所以就著手把手上自己的class去把一些關於資料庫的部份由ado轉成linq去跑,不過也是至這樣,一開始"馬上"就遇上問題(阿不是說"馬上就"好..騙人)..
一般我們寫class常常都會用到return,不管是傳回string int array datatable等等這些行型態的物件,想當然爾這些class改過後當然還是會傳回來"某"些東西,這是問題就大啦,聽我徐徐道來,首先就是Anonymous Type這東東,先看原始碼
public class test1 { public var getObj() { linqToSqlDataContext db = new linqToSqlDataContext(); var tb = from a in db.Product select a; return tb; } }
上面原始碼一定會過不去,因為AnonymousType只能用在"區域"不能隨便亂跑,您可以參考這裡
http://msdn.microsoft.com/en-us/library/bb384061.aspx
所以當然要解決問題,解決的方法還蠻多種的,我就拿我這例子在直接繼續下去
public class test1 { public IQueryable<Product> getObj() { linqToSqlDataContext db = new linqToSqlDataContext(); IQueryable<Product> tb = from a in Products select a; return tb; } }
感謝天阿,可以用了ㄟ,一切都是這麼自然這麼簡單..爽..
不過台語俗諺說得好:搖擺沒有落魄得久,攏是相遇得到的,我馬上就給它遇到..一﹏一||.. 馬上看這例子..
不過台語俗諺說得好:搖擺沒有落魄得久,攏是相遇得到的,我馬上就給它遇到..一﹏一||.. 馬上看這例子..
var tb = from a in Products select new { a.ProductName, a.UnitPrice, a.UnitsInStock };
這裡因為我們用new的方法去改變原本的結構,所以傳回來會Anonymous Type,所以所以呢..要準備投降ㄇ,當然沒有,goolge永遠是我們最好的老師,查了一下網路上也是有人遇到相同的問題..
方法1
public class test1 { public IQueryable getObj() { linqToSqlDataContext db = new linqToSqlDataContext(); var tb = from a in Products select new { a.ProductName, a.UnitPrice, a.UnitsInStock }; return tb.AsQueryable(); } }
這方法是用AsQueryable()去把它轉型成IQueryable然後就可以傳來給它傳去,不過缺點是轉了以後很多事情都不能做,就像Kobe Bryant不會切入拉杆Steve Nash不會傳球助一樣,一整個很冏..
所以如果你傳回去後沒有要在做啥事情,例如直接bind()這類的話,用這就行啦..
方法2
public class test1 { public IQueryable<newTb> getObj() { linqToSqlDataContext db = new linqToSqlDataContext(); IQueryable<newTb> tb = from a in Products select new newTb { ProductName = a.ProductName, UnitPrice = a.UnitPrice, UnitsInStock = a.UnitsInStock }; return tb; } } public class newTb { public string ProductName { get; set; } public decimal? UnitPrice { get; set; } public short? UnitsInStock { get; set; } }
我們多建立一組class然後去滿足它輸出的格式,這種作法就像O/R Designer幫我們做class一樣的道理,所以才有很方便的intellisense..
不過也是有缺點的,因為很麻煩,要自己再去建立class,對於我這懶人如果欄位一多,我看我還是去睡覺算了,真是俗語說的"有一好沒兩好"..冏..
方法3
這是一個想法,如果我能把回傳值變成datatable那是不是可以用linq to AOD.NET這些方法去處理,這是個好想法(老王賣瓜自賣自誇..哈哈),馬上就想到CopyToDataTable()東東,不過看到msdn裡的定義,心又涼了一半
public static DataTable CopyToDataTable<T>( this IEnumerable<T> source ) where T : DataRow
哇勒..機車鬼只能用在datarow裡,那這裡不就啥鬼都不能用了..冏..
話說"山窮水盡疑無路柳暗花明又一村",我又找到我的"村"啦,msdn線上有解決方案,它又擴充了CopyToDataTable()的方法,不在只有datarow可以用其他的型別也照吃,只要照他的方法把擴充的class放到專案中就行了,class在這邊http://msdn.microsoft.com/en-us/library/bb669096.aspx自行下載服用,不過這extension還有一個問題就是遇上nullable types就會死,所以改掉這一段就行了..
話說"山窮水盡疑無路柳暗花明又一村",我又找到我的"村"啦,msdn線上有解決方案,它又擴充了CopyToDataTable()的方法,不在只有datarow可以用其他的型別也照吃,只要照他的方法把擴充的class放到專案中就行了,class在這邊http://msdn.microsoft.com/en-us/library/bb669096.aspx自行下載服用,不過這extension還有一個問題就是遇上nullable types就會死,所以改掉這一段就行了..
if (!_ordinalMap.ContainsKey(p.Name)) { // Add the property as a column in the table if it doesn't exist // already. DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name] : table.Columns.Add(p.Name, p.PropertyType); // Add the property to the ordinal map. _ordinalMap.Add(p.Name, dc.Ordinal); }
換成..
if (!_ordinalMap.ContainsKey(p.Name)) { Type colType = p.PropertyType; if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>))) { colType = colType.GetGenericArguments()[0]; } DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name] : table.Columns.Add(p.Name, colType); _ordinalMap.Add(p.Name, dc.Ordinal); }
所以這樣大致就解決我們遇到的問題..看原始碼ㄅ..
public class test1 { public DataTable getObj() { linqToSqlDataContext db = new linqToSqlDataContext(); var tb = from a in db.Products select new { a.ProductName, a.UnitPrice, a.UnitsInStock }; return tb.CopyToDataTable(); } }
輸出引用
DataTable aa = new test1().getObj(); foreach (DataRow a in aa.Rows) { Response.Write(a.Field<string>("ProductName")); Response.Write(a.Field<decimal?>("UnitPrice").Value); Response.Write(a.Field<short?>("UnitsInStock").Value); }
呼呼~繞了一圈轉了一圈,終於得到了我們想要的結果,上面的三種方法任君挑選,喜歡用哪個就用哪個,以彈性來說當然首推第二種跟第三種,沒有哪一種方法比較好,就"順手"就好,framework 3.5提供了Anonymous Type這個很方便的東西,不過帶來的後遺症就是你根本不知道現在型別是啥ㄇ,然後傻傻的用遇到問題就傻住愣住不知道該怎麼辦,微軟想給你方便你也別隨便給它用下去,用下去之前最好知道在幹啥麼這樣以後遇到問題還好解決
ps:呼呼~終於寫完..好累喔..
參考: