1、EF
剛接觸linq那段時(shí)間,感覺這家伙好神奇,語法好優(yōu)美,好厲害。后來經(jīng)歷了EF一些不如意的地方,就想去彌補(bǔ),既然想彌補(bǔ),就必須去了解原理。最開始甚至很長一段時(shí)間都搞不懂IQueryPRovider(小聲說,其實(shí)現(xiàn)在也沒完全搞懂),好不容易把IQueryProvider搞懂了,然后才發(fā)現(xiàn)好戲才剛剛開始,這個時(shí)候嘗試寫了第一個ORM。那個時(shí)候不明白表達(dá)式樹的原理,自然一開始的思路就是走一點(diǎn)算一點(diǎn),走到后面就沒法走了,因?yàn)樗悸诽珌y了。這個時(shí)候就感覺EF太牛了,那么復(fù)雜的linq都能翻譯出來,雖然翻譯的sql的質(zhì)量不行,而且還有坑,不過至少翻譯出來了,感覺自己永遠(yuǎn)都沒辦法做到。
2、Dapper
這框架是大名鼎鼎的,性能是相當(dāng)高的,底層是用EMIT寫的。然而我這人就是有技術(shù)潔癖,如果是我自己一個人開發(fā),那么如果這個工具讓我感覺到了不爽,我就會嘗試自己開發(fā)。所以我也沒用dapper,原因只是它直接操作了Connection,而且要手寫sql代碼。但是我自己寫的在性能上始終是個硬傷,跟dapper比不了。之前我業(yè)余用表達(dá)式樹實(shí)現(xiàn)了DataSet到List的轉(zhuǎn)換,然后拿到公司裝逼,同事來了一句"來來咱跟dapper比比",我說"得得你就別虐我了成不",比的結(jié)果當(dāng)然是比較慘的,那個時(shí)候我覺得我不可能達(dá)到dapper的轉(zhuǎn)換速度。
測試代碼
測試結(jié)果

秒EF是妥妥的,但dapper基本上性能一樣,那點(diǎn)差距就直接忽略吧。
之前也進(jìn)行過一次,被dapper秒,和EF性能一樣,原因是因?yàn)樽值渚彺嬗玫挠袉栴}。
而這次這個最終取數(shù)據(jù)全部用的數(shù)組,一開始其實(shí)把dapper都給秒了,快了dapper接近一半,不過后來發(fā)現(xiàn)情況沒考慮全,考慮全了就差不多了。
應(yīng)該有不少人都認(rèn)為后者比前者快,我一開始也這么認(rèn)為的。
但園子一位大神說,Expression Tree與EMIT最終生成的代碼是一樣的,所以性能是一樣的。說實(shí)在的,我還是不太信。
然后老趙大神又說,Expression Tree最終也是操作的EMIT來實(shí)現(xiàn)的。好吧,其實(shí)我有點(diǎn)信了,但還是不太信。
直到我在寫XLinq的時(shí)候用純Expression Tree超越了用純EMIT的Dapper,我才相信。(不信?可以在評論里要源碼)
之前造輪子的時(shí)候,一直覺得Convert.ChangeType是尚方寶劍,一劍在手,天下我有。
然而在寫XLinq的時(shí)候,被這個方法坑的不輕。
當(dāng)我要long、int、short、int?、long?、short?這幾個類型相互轉(zhuǎn)換的時(shí)候,總會冒出來異常。
然后谷歌一下,園子大神的博文說:"這個方法一遇到Nullable<T>類型的時(shí)候就會掛掉"。
好吧,我認(rèn)了(說錯了的話請指正)。然后不得不自己處理類型轉(zhuǎn)換,同時(shí)也算是知道了這個坑。
一直認(rèn)為只要linq provider寫得足夠好,就能支持無縫切換數(shù)據(jù)庫,注意是切換不是支持。
然而現(xiàn)在看來,想要做到直接改一下配置文件就能切換這是不可能的。
舉一個例子,假如說要將sql server數(shù)據(jù)庫切換到sqlite,這個時(shí)候切換過去之后看起來其實(shí)不會有什么問題,因?yàn)閟qlite即使語法不對也可能不會報(bào)錯。
在sql server中,2015/1/1這是合法的日期型數(shù)據(jù),但這樣的數(shù)據(jù)在sqlite中是無法識別的。
也就是說,如果你之前用的sql server,并且使用了這樣的數(shù)據(jù)格式,那么切換到sqlite后可能所有關(guān)于日期的判斷會全部出錯,并不是指報(bào)異常,而是說計(jì)算結(jié)果不正確。
之前在寫類似于ORM的工具時(shí),總會將先生成每一個屬性的Setter和Getter委托,然后再單獨(dú)調(diào)用這些委托來完成轉(zhuǎn)換。
這樣就幾乎無法避免裝箱拆箱的問題,但裝箱拆箱其實(shí)還是會浪費(fèi)一點(diǎn)性能的。
后來想到了另一種辦法,不再生成Setter和Getter的委托,轉(zhuǎn)而生成包裝了一個循環(huán)的委托。
就是說,我傳給委托一個類型和一個Reader對象,它就直接返回給我一個List,我不用去獲取每一個屬性的委托。
委托中直接生成了訪問該類型的每一個屬性的代碼,這樣就直接避免了裝箱拆箱,最終性能跟dapper差不多了。
不過這樣做可能會占用多一點(diǎn)緩存,不過現(xiàn)在來說內(nèi)存應(yīng)該不是問題

1 public static Func<IDataReader, IList> GetDataReaderMapeer(Type type,IDataReader reader) 2 { 3 Func<IDataReader, IList> func = null; 4 if (!_dataReader2ListCahce.TryGetValue(type, out func)) 5 { 6 lock (_dataReader2ListCahce) 7 { 8 if (!_dataReader2ListCahce.TryGetValue(type, out func)) 9 { 10 var readerExp = Expression.Parameter(ReflectorConsts.IDataReaderType, "reader"); 11 var properties = ExpressionReflector.GetProperties(type); 12 var fieldCount = reader.FieldCount; 13 var expressions = new List<Expression>(); 14 var objVar = Expression.Variable(type, "entity"); 15 var fieldCountVar = Expression.Variable(ReflectorConsts.Int32Type, "fieldCount"); 16 var readerVar = Expression.Variable(ReflectorConsts.IDataReaderType, "readerVar"); 17 var propertyNameArr = Expression.Variable(ReflectorConsts.StringArrayType, "pis"); 18 var indexArrVar = Expression.Variable(ReflectorConsts.Int32ArrayType, "indexes"); 19 var readIndexVar = Expression.Variable(ReflectorConsts.Int32Type, "readIndex"); 20 var indexVar = Expression.Variable(ReflectorConsts.Int32Type, "index"); 21 var forBreakLabel = Expression.Label("forBreak"); 22 var assignIndexVar = Expression.Assign(indexVar, Expression.Constant(0)); 23 var listType = ReflectorConsts.ListType.MakeGenericType(type); 24 var listVar = Expression.Variable(listType, "list"); 25 expressions.Add(Expression.Assign(listVar, Expression.New(listType))); 26 expressions.Add(Expression.Assign(readerVar, readerExp)); 27 expressions.Add(assignIndexVar); 28 var assignFieldCountVar = Expression.Assign(fieldCountVar, 29 Expression.MakeMemberaccess(readerVar, ReflectorConsts.FieldCountOfIDataReader) 30 ); 31 expressions.Add(assignFieldCountVar); 32 var readNameExp = Expression.Call(readerVar, ReflectorConsts.GetOrdinalOfIDataReader, Expression.ArrayIndex(propertyNameArr, indexVar)); 33 var initIndexArray = Expression.Assign(indexArrVar, Expression.NewArrayBounds(ReflectorConsts.Int32Type, Expression.Constant(fieldCount))); 34 var initPropertyArrayExpressions = new List<Expression>(); 35 for (int i = 0; i < fieldCount; i++) 36 { 37 initPropertyArrayExpressions.Add(Expression.Constant(reader.GetName(i))); 38 } 39 var initPropertyArray = Expression.Assign(propertyNameArr, Expression.NewArrayInit(ReflectorConsts.StringType, initPropertyArrayExpressions)); 40 var assignIndexArrayVar = Expression.Assign(Expression.ArrayAccess(indexArrVar, indexVar), readNameExp); 41 expressions.Add(initPropertyArray); 42 expressions.Add(initIndexArray); 43 expressions.Add(Expression.Loop( 44 Expression.IfThenElse( 45 Expression.LessThan(indexVar, fieldCountVar), 46
新聞熱點(diǎn)
疑難解答
圖片精選