[原创].NET 业务框架开发实战之十 第一阶段总结,深入浅出,水到渠成(前篇)...
.NET 業(yè)務(wù)框架開(kāi)發(fā)實(shí)戰(zhàn)之十 第一階段總結(jié),深入淺出,水到渠成(前篇)
前言:這個(gè)系列有段時(shí)間沒(méi)有動(dòng)了。主要是針對(duì)大家的反饋在修改代碼。在修改的過(guò)程中,也有了一些新的體會(huì),這里和大家分享一下,同時(shí)也發(fā)布一下業(yè)務(wù)框架的第一個(gè)版本。在本篇文章中,學(xué)習(xí)到的不是僅僅只是代碼,而是設(shè)計(jì)的思想和實(shí)現(xiàn)這種思想的方法。在寫(xiě)本篇時(shí)有個(gè)感觸:把一個(gè)東西徹底的講清楚,不容易。希望大家
多提意見(jiàn)。而且在寫(xiě)本篇的時(shí)候,我個(gè)人也是很興奮的,至于原因相信大家在看完之后就知道了。J
本篇的議題如下:
1.????? 打通業(yè)務(wù)層和數(shù)據(jù)層
2.????? 打通方法的選擇和實(shí)現(xiàn)
3.????? 再次借鑒.NET Framework設(shè)計(jì)思想
4.????? 水到渠成
5.????? 代碼的版本說(shuō)明
?
系列文章鏈接:
?[原創(chuàng)].NET 分布式架構(gòu)開(kāi)發(fā)實(shí)戰(zhàn)之一 故事起源
[原創(chuàng)].NET 分布式架構(gòu)開(kāi)發(fā)實(shí)戰(zhàn)之二 草稿設(shè)計(jì)
[原創(chuàng)].NET 分布式架構(gòu)開(kāi)發(fā)實(shí)戰(zhàn)之三 數(shù)據(jù)訪問(wèn)深入一點(diǎn)的思考
[原創(chuàng)].NET 分布式架構(gòu)開(kāi)發(fā)實(shí)戰(zhàn)之四 構(gòu)建從理想和實(shí)現(xiàn)之間的橋梁(前篇)
[原創(chuàng)].NET 分布式架構(gòu)開(kāi)發(fā)實(shí)戰(zhàn)五 Framework改進(jìn)篇
[原創(chuàng)].NET 業(yè)務(wù)框架開(kāi)發(fā)實(shí)戰(zhàn)之六 DAL的重構(gòu)
[原創(chuàng)].NET 業(yè)務(wù)框架開(kāi)發(fā)實(shí)戰(zhàn)之七 業(yè)務(wù)層初步構(gòu)想
[原創(chuàng)].NET 業(yè)務(wù)框架開(kāi)發(fā)實(shí)戰(zhàn)之八 業(yè)務(wù)層Mapping的選擇策略
[原創(chuàng)].NET 業(yè)務(wù)框架開(kāi)發(fā)實(shí)戰(zhàn)之九 Mapping屬性原理和驗(yàn)證規(guī)則的實(shí)現(xiàn)策略
[原創(chuàng)].NET 業(yè)務(wù)框架開(kāi)發(fā)實(shí)戰(zhàn)之十 第一階段總結(jié),深入淺出,水到渠成(前篇)
[原創(chuàng)].NET 業(yè)務(wù)框架開(kāi)發(fā)實(shí)戰(zhàn)之十 第一階段總結(jié),深入淺出,水到渠成(后篇)
1.??? 打通業(yè)務(wù)層和數(shù)據(jù)層
首先,回顧之前的文章一直討論的問(wèn)題:
1. 如何使得數(shù)據(jù)層”以不變應(yīng)萬(wàn)變”。
2. 條件對(duì)象如何實(shí)現(xiàn)
3. 如何在業(yè)務(wù)層和數(shù)據(jù)層之間mapping數(shù)據(jù)
本篇就告訴大家,如何切切實(shí)實(shí)的解決上面三個(gè)問(wèn)題。
?
首先,從一個(gè)圖示開(kāi)始講述。
?
?
從上面的圖中可以看出,架起在BLL和DAL之前的橋梁的就是中間的那個(gè)條件對(duì)象。正是因?yàn)橛辛诉@個(gè),所以上面的提出的問(wèn)題才得以解決。
下面先從操作上總體來(lái)講述一下這個(gè)圖的具體流程:
a.?????? 在業(yè)務(wù)類(lèi)中創(chuàng)建一個(gè)方法。例如在業(yè)務(wù)類(lèi)User中,定義如下:
現(xiàn)在只看GetUserByAge這個(gè)方法:在方法中構(gòu)造出一個(gè)條件對(duì)象,大家第一眼能看出來(lái):是Linq的實(shí)現(xiàn)。其實(shí)最后的實(shí)現(xiàn)只是借用了Linq的思想,僅此而已。
b.?????? 解析條件對(duì)象。在上面的構(gòu)造的條件對(duì)象中,Age,Name等,都是業(yè)務(wù)類(lèi)User的字段,這些字段的值肯定最終是從數(shù)據(jù)庫(kù)中的表字段中獲取的(或者是通過(guò)數(shù)據(jù)庫(kù)中的值算出來(lái)的),所以在解析條件對(duì)象的時(shí)候,就要知道這些業(yè)務(wù)屬性對(duì)應(yīng)數(shù)據(jù)庫(kù)中哪個(gè)表的哪個(gè)字段。因此在業(yè)務(wù)類(lèi)中聲明每個(gè)屬性的時(shí)候就要同時(shí)保留它所對(duì)應(yīng)的數(shù)據(jù)庫(kù)字段的信息。一旦業(yè)務(wù)類(lèi)的屬性中保存了這些信息
c.?????? 數(shù)據(jù)層操作SQL語(yǔ)句。在解析條件對(duì)象的時(shí)候,就會(huì)最終得到相對(duì)應(yīng)的SQL語(yǔ)句,然后在數(shù)據(jù)層中執(zhí)行這些SQL語(yǔ)句。
可能上面講的比較的抽象,因?yàn)楸酒囊v述的東西確實(shí)比較的多(Word中寫(xiě)了超過(guò)了10頁(yè)),上面講述的三個(gè)步驟也是先按大家有個(gè)印象。不是很懂也沒(méi)有關(guān)系。
?
?2.?打通方法的選擇和實(shí)現(xiàn)
?????? 接下來(lái)就是方法的探索和思考,以及實(shí)現(xiàn)的過(guò)程。我是想帶著個(gè)大家跟著一起看看,為什么最后會(huì)采用這個(gè)解決方案的。
首先,就從條件對(duì)象開(kāi)始看起。
在實(shí)現(xiàn)條件對(duì)象(條件對(duì)象和查詢(xún)對(duì)象的區(qū)別之前講過(guò),這里重述一下:查詢(xún)對(duì)象只是條件對(duì)象的一個(gè)子集,查詢(xún)對(duì)象用來(lái)在查詢(xún)的使用構(gòu)造查詢(xún)條件;條件對(duì)象不僅僅在查詢(xún)時(shí)構(gòu)造條件,而且在增加,刪除,,修改時(shí)候也使用,例如:只修改Name=”admin”的數(shù)據(jù),在修改數(shù)據(jù)庫(kù)的時(shí)候也用了一定的條件。所以條件對(duì)象>查詢(xún)對(duì)象)的時(shí)候,也是參看了其他開(kāi)源框架的一些實(shí)現(xiàn)(Nhibernate中查詢(xún)對(duì)象的,CSLA)。
同時(shí)要明白一點(diǎn):設(shè)計(jì)出來(lái)的框架是給開(kāi)發(fā)人員使用的,所以要考慮如何使得開(kāi)發(fā)人員最快最好的使用框架,所以要從開(kāi)發(fā)人員的角度看(這一點(diǎn)也是很重要的)。例如在Nhibernate中查詢(xún)對(duì)象,使用的方法如下(僅僅是簡(jiǎn)單的舉例而已):
代碼 ?IListCustomer>?customers?=?_session.CreateCriteria(typeof(Customer))????????.Add(Restrictions.Like("Firstname",?"Xiaoyang%"))
????????.Add(Restrictions.Between("Lastname",?"A%",?"Y%"))
????????.ListCustomer>(); ? 其實(shí)本系列中的業(yè)務(wù)框架之前的條件對(duì)象的構(gòu)造也是參看了Nhibernate中查詢(xún)對(duì)象的方法來(lái)實(shí)現(xiàn)和使用的,如下:
?
ICriteria?condition=CriteriaFactory.Create(typeof(ProductBL).Where("ProductName",?Operation.Equal,"book");?因?yàn)楝F(xiàn)在.NET中的開(kāi)發(fā)人員對(duì)Linq的一些操作比較的熟悉,而且如果把條件對(duì)象的使用方式改為下面的方式:
ICriteria<ProductBL>?condition=CriteriaFactory.Create<ProductBL>(o?=>?o.ProductName?==?"book");?
那么開(kāi)發(fā)人員的學(xué)習(xí)成本就幾乎為零(因?yàn)樗麄兪煜inq,如果條件對(duì)象也采用這種比較統(tǒng)一的方法實(shí)現(xiàn),他們就可以采用”以此類(lèi)推”的思想來(lái)使用框架),更多的好處我就不說(shuō)了,大家可以自己體會(huì)或者參看本系列之前的文章。
?
接下來(lái)就探索實(shí)現(xiàn)條件對(duì)象的方法(Linq to XXX篇)。
熟悉Linq的朋友可以看出:可以使條件對(duì)象實(shí)現(xiàn)IQueryable接口,然后采用實(shí)現(xiàn)linq to XXX的方法,實(shí)現(xiàn)自己的Linq Provider。這個(gè)方法是否可行,下面,我們就深入linq to XXX的來(lái)看一看,看完之后,結(jié)果就很清楚了。
首先來(lái)看下面兩個(gè)接口:?
代碼 ??public?interface?IQueryable?:?IEnumerable?{????????????????Type?ElementType?{?get;?}
????????Expression?Expression?{?get;?}
????????IQueryProvider?Provider?{?get;?}
????}
????public?interface?IQueryable<T>?:?IEnumerable<T>,?IQueryable,?IEnumerable?{} ? ?public interface IQueryProvider {
??????? IQueryable CreateQuery(Expression expression);
??????? IQueryable<TElement> CreateQuery<TElement>(Expression expression);
??????? object Execute(Expression expression);
??????? TResult Execute<TResult>(Expression expression);
??? }
??
Linq的出現(xiàn),使得很多東西都和linq扯上了關(guān)系:Linq to sql, Linq to Google, Linq to javascript, Linq to Nhibernate...... 所列出來(lái)的這些,我們統(tǒng)稱(chēng)為linq to XXX。這些Linq to XXX都是實(shí)現(xiàn)了上面兩個(gè)接口。
下面就通過(guò)自己實(shí)現(xiàn)linq to sql來(lái)舉例分析。
從總體來(lái)看:linq to sql的本質(zhì)就是:把操作轉(zhuǎn)換為sql語(yǔ)句,然后用ADO.NET執(zhí)行,最后把結(jié)果轉(zhuǎn)換為實(shí)體返回。
其實(shí)下面列出了這么多的代碼,其中最關(guān)鍵的其實(shí)就是QueryProvider中的Execute方法:這個(gè)方法負(fù)責(zé)把你的操作進(jìn)行解析,其實(shí)真正負(fù)責(zé)解析的QueryTranslator。
?
代碼 ?public?class?Query<T>?:?IQueryable<T>,?IQueryable,?IEnumerable<T>,?IEnumerable,?IOrderedQueryable<T>,?IOrderedQueryable?{
????????QueryProvider?provider;
????????Expression?expression;
?
????????public?Query(QueryProvider?provider)?{
????????????if?(provider?==?null)?{
????????????????throw?new?ArgumentNullException("provider");
????????????}
????????????this.provider?=?provider;
????????????this.expression?=?Expression.Constant(this);
????????}
?
????????public?Query(QueryProvider?provider,?Expression?expression)?{
????????????if?(provider?==?null)?{
????????????????throw?new?ArgumentNullException("provider");
????????????}
????????????if?(expression?==?null)?{
????????????????throw?new?ArgumentNullException("expression");
????????????}
????????????if?(!typeof(IQueryable<T>).IsAssignableFrom(expression.Type))?{
????????????????throw?new?ArgumentOutOfRangeException("expression");
????????????}
????????????this.provider?=?provider;?
????????????this.expression?=?expression;
????????}
?
????????Expression?IQueryable.Expression?{
????????????get?{?return?this.expression;?}
????????}
?
????????Type?IQueryable.ElementType?{
????????????get?{?return?typeof(T);?}
????????}
?
????????IQueryProvider?IQueryable.Provider?{
????????????get?{?return?this.provider;?}
????????}
?
????????public?IEnumerator<T>?GetEnumerator()?{
????????????return?((IEnumerable<T>)this.provider.Execute(this.expression)).GetEnumerator();
????????}
?
????????IEnumerator?IEnumerable.GetEnumerator()?{
????????????return?((IEnumerable)this.provider.Execute(this.expression)).GetEnumerator();
????????}
?
????????public?override?string?ToString()?{
????????????return?this.provider.GetQueryText(this.expression);
????????}
????}
?
?
代碼 public?abstract?class?QueryProvider?:?IQueryProvider?{????????protected?QueryProvider()?{
????????}
?
????????IQueryable<S>?IQueryProvider.CreateQuery<S>(Expression?expression)?{
????????????return?new?Query<S>(this,?expression);
????????}
?
????????IQueryable?IQueryProvider.CreateQuery(Expression?expression)?{
????????????Type?elementType?=?TypeSystem.GetElementType(expression.Type);
????????????try?{
????????????????return?(IQueryable)Activator.CreateInstance(typeof(Query<>).MakeGenericType(elementType),?new?object[]?{?this,?expression?});
????????????}
????????????catch?(TargetInvocationException?tie)?{
????????????????throw?tie.InnerException;
????????????}
????????}
?
????????S?IQueryProvider.Execute<S>(Expression?expression)?{
????????????return?(S)this.Execute(expression);
????????}
?
????????object?IQueryProvider.Execute(Expression?expression)?{
????????????return?this.Execute(expression);
????????}
?
????????public?abstract?string?GetQueryText(Expression?expression);
????????public?abstract?object?Execute(Expression?expression);
????}
?
?
?
代碼 internal?class?QueryTranslator?:?ExpressionVisitor?{????StringBuilder?sb;
?
????internal?QueryTranslator()?{
????}
?
????internal?string?Translate(Expression?expression)?{
????????this.sb?=?new?StringBuilder();
????????this.Visit(expression);
????????return?this.sb.ToString();
????}
?
????private?static?Expression?StripQuotes(Expression?e)?{
????????while?(e.NodeType?==?ExpressionType.Quote)?{
????????????e?=?((UnaryExpression)e).Operand;
????????}
????????return?e;
????}
?
????protected?override?Expression?VisitMethodCall(MethodCallExpression?m)?{
????????if?(m.Method.DeclaringType?==?typeof(Queryable)?&&?m.Method.Name?==?"Where")?{
????????????sb.Append("SELECT?*?FROM?(");
????????????this.Visit(m.Arguments[0]);
????????????sb.Append(")?AS?T?WHERE?");
????????????LambdaExpression?lambda?=?(LambdaExpression)StripQuotes(m.Arguments[1]);
????????????this.Visit(lambda.Body);
????????????return?m;
????????}
????????throw?new?NotSupportedException(string.Format("The?method?'{0}'?is?not?supported",?m.Method.Name));
????}
?
????protected?override?Expression?VisitUnary(UnaryExpression?u)?{
????????switch?(u.NodeType)?{
????????????case?ExpressionType.Not:
????????????????sb.Append("?NOT?");
????????????????this.Visit(u.Operand);
????????????????break;
????????????default:
????????????????throw?new?NotSupportedException(string.Format("The?unary?operator?'{0}'?is?not?supported",?u.NodeType));
????????}
????????return?u;
????}
?
????protected?override?Expression?VisitBinary(BinaryExpression?b)?{
????????sb.Append("(");
????????this.Visit(b.Left);
????????switch?(b.NodeType)?{
????????????case?ExpressionType.And:
????????????????sb.Append("?AND?");
????????????????break;
????????????case?ExpressionType.Or:
????????????????sb.Append("?OR");
????????????????break;
????????????case?ExpressionType.Equal:
????????????????sb.Append("?=?");
????????????????break;
????????????case?ExpressionType.NotEqual:
????????????????sb.Append("?<>?");
????????????????break;
????????????case?ExpressionType.LessThan:
????????????????sb.Append("?<?");
????????????????break;
????????????case?ExpressionType.LessThanOrEqual:
????????????????sb.Append("?<=?");
????????????????break;
????????????case?ExpressionType.GreaterThan:
????????????????sb.Append("?>?");
????????????????break;
????????????case?ExpressionType.GreaterThanOrEqual:
????????????????sb.Append("?>=?");
????????????????break;
????????????default:
????????????????throw?new?NotSupportedException(string.Format("The?binary?operator?'{0}'?is?not?supported",?b.NodeType));
????????}
????????this.Visit(b.Right);
????????sb.Append(")");
????????return?b;
????}
?
????protected?override?Expression?VisitConstant(ConstantExpression?c)?{
????????IQueryable?q?=?c.Value?as?IQueryable;
????????if?(q?!=?null)?{
????????????//?assume?constant?nodes?w/?IQueryables?are?table?references
????????????sb.Append("SELECT?*?FROM?");
????????????sb.Append(q.ElementType.Name);
????????}
????????else?if?(c.Value?==?null)?{
????????????sb.Append("NULL");
????????}
????????else?{
????????????switch?(Type.GetTypeCode(c.Value.GetType()))?{
????????????????case?TypeCode.Boolean:
????????????????????sb.Append(((bool)c.Value)???1?:?0);
????????????????????break;
????????????????case?TypeCode.String:
????????????????????sb.Append("'");
????????????????????sb.Append(c.Value);
????????????????????sb.Append("'");
????????????????????break;
????????????????case?TypeCode.Object:
????????????????????throw?new?NotSupportedException(string.Format("The?constant?for?'{0}'?is?not?supported",?c.Value));
????????????????default:
????????????????????sb.Append(c.Value);
????????????????????break;
????????????}
????????}
????????return?c;
????}
?
????protected?override?Expression?VisitMemberAccess(MemberExpression?m)?{
????????if?(m.Expression?!=?null?&&?m.Expression.NodeType?==?ExpressionType.Parameter)?{
????????????sb.Append(m.Member.Name);
????????????return?m;
????????}
????????throw?new?NotSupportedException(string.Format("The?member?'{0}'?is?not?supported",?m.Member.Name));
????}
}
?
??
對(duì)于實(shí)現(xiàn)了IQueryable的對(duì)象,在他們進(jìn)行的每一個(gè)操作(也就是調(diào)用實(shí)現(xiàn)這個(gè)接口的類(lèi)上的方法)其實(shí)都沒(méi)有立刻去執(zhí)行,而且把進(jìn)行的操作記錄下來(lái)了,放在一個(gè)稱(chēng)為Expression Tree表達(dá)式數(shù)的數(shù)據(jù)結(jié)構(gòu)中,然后再真正執(zhí)行的時(shí)候(就是調(diào)用Execute來(lái)執(zhí)行), QueryTranslator對(duì)象就遍歷表達(dá)式樹(shù),對(duì)操作進(jìn)行解析,例如linq to sql就是把表達(dá)式樹(shù)中操作解析為對(duì)數(shù)據(jù)庫(kù)進(jìn)行的操作,以sql語(yǔ)句的形式體現(xiàn)出來(lái).
?
?????? 當(dāng)把操作解析為了sql語(yǔ)句之后,就是用ADO.NET的方法來(lái)執(zhí)行SQL操作,然后通過(guò)反射,把ADO.NET執(zhí)行的結(jié)果轉(zhuǎn)換為數(shù)據(jù)實(shí)體。如下:???????
代碼 internal?class?ObjectReader<T>?:?IEnumerable<T>,?IEnumerable?where?T?:?class,?new()?{
????Enumerator?enumerator;
?
????internal?ObjectReader(DbDataReader?reader)?{
????????this.enumerator?=?new?Enumerator(reader);
????}
?
????public?IEnumerator<T>?GetEnumerator()?{
????????Enumerator?e?=?this.enumerator;
????????if?(e?==?null)?{
????????????throw?new?InvalidOperationException("Cannot?enumerate?more?than?once");
????????}
????????this.enumerator?=?null;
????????return?e;
????}
?
????IEnumerator?IEnumerable.GetEnumerator()?{
????????return?this.GetEnumerator();
????}
?
????class?Enumerator?:?IEnumerator<T>,?IEnumerator,?IDisposable?{
????????DbDataReader?reader;
????????FieldInfo[]?fields;
????????int[]?fieldLookup;
????????T?current;
?
????????internal?Enumerator(DbDataReader?reader)?{
????????????this.reader?=?reader;
????????????this.fields?=?typeof(T).GetFields();
????????}
?
????????public?T?Current?{
????????????get?{?return?this.current;?}
????????}
?
????????object?IEnumerator.Current?{
????????????get?{?return?this.current;?}
????????}
?
????????public?bool?MoveNext()?{
????????????if?(this.reader.Read())?{
????????????????if?(this.fieldLookup?==?null)?{
????????????????????this.InitFieldLookup();
????????????????}
????????????????T?instance?=?new?T();
????????????????for?(int?i?=?0,?n?=?this.fields.Length;?i?<?n;?i++)?{
????????????????????int?index?=?this.fieldLookup[i];
????????????????????if?(index?>=?0)?{
????????????????????????FieldInfo?fi?=?this.fields[i];
????????????????????????if?(this.reader.IsDBNull(index))?{
????????????????????????????fi.SetValue(instance,?null);
????????????????????????}
????????????????????????else?{
????????????????????????????fi.SetValue(instance,?this.reader.GetValue(index));
????????????????????????}
????????????????????}
????????????????}
????????????????this.current?=?instance;
????????????????return?true;
????????????}
????????????return?false;
????????}
?
????????public?void?Reset()?{
????????}
?
????????public?void?Dispose()?{
????????????this.reader.Dispose();
????????}
?
????????private?void?InitFieldLookup()?{
????????????Dictionary<string,?int>?map?=?new?Dictionary<string,?int>(StringComparer.InvariantCultureIgnoreCase);
????????????for?(int?i?=?0,?n?=?this.reader.FieldCount;?i?<?n;?i++)?{
????????????????map.Add(this.reader.GetName(i),?i);
????????????}
????????????this.fieldLookup?=?new?int[this.fields.Length];
????????????for?(int?i?=?0,?n?=?this.fields.Length;?i?<?n;?i++)?{
????????????????int?index;
????????????????if?(map.TryGetValue(this.fields[i].Name,?out?index))?{
????????????????????this.fieldLookup[i]?=?index;
????????????????}
????????????????else?{
????????????????????this.fieldLookup[i]?=?-1;
????????????????}
????????????}
????????}
????}
}
?
?
?????? 上面簡(jiǎn)單的介紹了如何實(shí)現(xiàn)linq to sql具體的實(shí)現(xiàn)代碼,大家可以自己過(guò)后慢慢的看或者參看我的另外的一個(gè)linq系列,現(xiàn)在我們繼續(xù)后面的話(huà)題。?
?????? 現(xiàn)在我們回到之前的話(huà)題:條件對(duì)象是否可以采用這種方式實(shí)現(xiàn)???????
?????? 大家看到上面的代碼Query<T>其中的T,和Execute方法的返回值。在上面的代碼中,如果T是User類(lèi),即,Query<User>,那么最后的Execute方法返回的一定會(huì)是User的集合。也就是說(shuō):Execute方法已經(jīng)對(duì)數(shù)據(jù)源(這里是數(shù)據(jù)庫(kù))進(jìn)行了操作,并且把結(jié)果以數(shù)據(jù)實(shí)體的形式已經(jīng)返回了,并且返回的數(shù)據(jù)實(shí)體的類(lèi)型就是T,例如User。
?????? 但是我們這里的要實(shí)現(xiàn)的條件對(duì)象只是想把條件構(gòu)造出來(lái),不是立刻去執(zhí)行。至于具體的執(zhí)行數(shù)據(jù)操作者(DataProvider)可以任意選擇的:使用ADO.NET方法,還是EF的方法,還是Nhibernate,都是可以配置的。如下:??????
代碼 ????public?List<User>?GetUserByAge()
????????{
????????????ICriteria<User>?conditionPerson?=
???????????????CriteriaFactory.Create<User>().Where(u?=>?u.Age?<?this.Age).OrderBy<string>(u?=>?u.Name).Skip(8).Take(8);
????????????return?DataPortal.Query(conditionPerson);
????????}
???????
上面的代碼中,Create方法就是實(shí)例化一個(gè)ICriteria<User>,此時(shí)我們想做的僅僅只是一件事:把在 ICriteria<User>上的操作記錄下來(lái)而已。然后把記錄下來(lái)的結(jié)果解析,解析的最終結(jié)果就是一條sql命令,然后再給不同的DataProvider去執(zhí)行。也就是說(shuō),在DataPortal內(nèi)部可以配置用什么方法來(lái)執(zhí)行數(shù)據(jù)操作:是直接使用ADO.NET執(zhí)行sql命令,還是把sql命令給Entity Framework...通過(guò)配置決定。如果ICriteria<T>是從IQueryable接口進(jìn)行了繼承,那么在ICriteria實(shí)現(xiàn)這個(gè)結(jié)果的過(guò)程中就必須要去數(shù)據(jù)庫(kù)中進(jìn)行執(zhí)行,因?yàn)镋xecute方法返回的是T的集合,而不是sql命令(字符串)。?
?????? 大家可能想到:那就在Execute方法中去實(shí)現(xiàn)不同的DataProvider,例如之前的例子在ObjectReader用ADO.NET實(shí)現(xiàn)了,那么也可以在ObjectReader中用EF實(shí)現(xiàn)數(shù)據(jù)操作。這個(gè)方法確實(shí)可以,也很不錯(cuò)。但是這個(gè)方法在分布式開(kāi)發(fā)中(特別是在WCF中)有一點(diǎn)的局限性。例如你有一個(gè)界面,上面可以有很多的選項(xiàng),如下:
?
?
在服務(wù)接口那邊,你肯定不想定義N多差不多的接口方法:如
GetUserByName(string?username);GetUserByEmail(string?email);
?
或者
GetUserByCondition(string?username,string?password,string?email?.....);?
? 這樣都是很不靈活的,如果User的屬性減少了或者增多了,那么如果要在服務(wù)器那邊暴露的接口的方法也要修改,這樣終究是不好。如下采用下面的方法:?
GetUserByCondition(Critera?condition);??
其中,Critera是條件對(duì)象。那么我們?cè)诳蛻?hù)端就可以任意構(gòu)造條件對(duì)象,這個(gè)條件對(duì)象就把在它上面進(jìn)行的操作記錄下來(lái),然后統(tǒng)一的交給GetUserByCondition方法去服務(wù)器解釋并執(zhí)行。此時(shí),這個(gè)條件對(duì)象就是在客戶(hù)端生成的,而且這個(gè)條件對(duì)象此時(shí)是不用去數(shù)據(jù)庫(kù)中去執(zhí)行的。如果條件對(duì)象是從IQueryable接口繼承的,那么在客戶(hù)端構(gòu)造完條件對(duì)象之后,就要去數(shù)據(jù)庫(kù)中執(zhí)行了,如果再在ObjectReader搞個(gè)分布式調(diào)用,難度不說(shuō),也很別扭,這不是我們所要的。
?????? 所以,綜合上面的一些考慮,那么可以確定:條件對(duì)象不繼承IQueryable接口。但是我們又希望采用類(lèi)似linq的操作,那么只有自己實(shí)現(xiàn)了。?
本篇就暫時(shí)寫(xiě)到這里,因?yàn)樘L(zhǎng)了,所以分為前篇和后篇發(fā)布,因?yàn)椴┛蛨@不能在一小時(shí)內(nèi)發(fā)兩篇,所以后篇將會(huì)在9點(diǎn)左右發(fā)布。希望大家見(jiàn)諒。
版權(quán)為小洋和博客園所有,,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)標(biāo)明出處給作者。
? http://www.cnblogs.com/yanyangtian
?
總結(jié)
以上是生活随笔為你收集整理的[原创].NET 业务框架开发实战之十 第一阶段总结,深入浅出,水到渠成(前篇)...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 教你轻松恢复Linux口令
- 下一篇: 常用命令示例