<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      ORM查詢語言(OQL)簡介--實例篇

         相關文章內容索引:

      [概念回顧]

          我們在前一篇《ORM查詢語言(OQL)簡介--概念篇》中了解到,SQL跟ORM的關系,ORM會自動生成SQL語句并執行,但普通的ORM框架卻不能靈活的生成需要的SQL語句,我們需要一種具有SQL靈活性的的但卻能夠面向對象的ORM查詢語言(ORM Query Language)--OQL。Hibernate的HQL,MS Entity Framework的ESQL都是這樣的一種語言,雖然HQL和ESQL解決了它們框架OO使用方式的不靈活,但卻是字符串類型的查詢語句,使用起來并不便利,好在EF一般都是使用Linq表達式來編寫查詢,但Linq方式跟SQL在語法上還是有很大的差異,特別是Linq的左、右連接查詢,跟SQL差異很大。而PDF.NET框架的OQL,應該是三者跟SQL最為接近的一種查詢語言。

          總結起來,OQL有下面3個顯著特點:

      1. 抽象的SQL,屏蔽了具體數據庫的差異,因此支持所有數據庫;
      2. 對象化的“SQL”,寫OQL代碼能夠獲得IDE的智能提示;
      3. 沒有使用.NET的特性,比如泛型、反射、表達式樹等東西,因此理論上OQL可以跨語言平臺,比如移植到Java,C++,VB等。

          PS:PDF.NET并不僅僅是一個ORM框架,它是一個多模式的開發框架,詳見官網說明 http://www.pwmis.com/sqlmap

          在前一篇中,我們使用了巴科斯范式(NBF)來描述OQL的語法,但不少朋友不太清楚具體該如何使用,本篇我們將使用實例來說明如何使用OQL。

      [OQL原理]

      .表達式的鏈式調用   

          OQL的設計完全基于面向對象的實體查詢,OQL的使用采用對象表達式的方式,內部實現原理是一系列的“鏈式方法調用”。為了完整實現SQL的查詢過程,需要為這些表達式方法進行分級:

      • 根表達式(OQL)、
      • 一級表達式(OQL1)、
      • 二級表達式(OQL2、OQLCompare等)

          每一級表達式會生成是和使用下一級表達式,比如OQL調用返回OQL1對象的方法,而OQL1對象又調用返回OQL2級對象的方法。

          將表達式按照層級劃分,保證了編寫OQL語句的正確性,可以避免因SQL語法不熟悉的開發人員寫出錯誤的SQL語句,另外由于面向對象的方式,還可以避免寫錯數據庫的表和字段名,在程序的編譯階段就發現錯誤而不是等到程序運行時。

       .屬性的實例調用

          使用ORM,涉及到一個繞不開的問題,就是如何獲取表的字段,EF是通過Linq來進行翻譯的,本質上不是直接調用得到字段名稱,在調用的時候,都是通過泛型方式的Lambda表達式來做的,這樣是比較方便,但PDF.NET采用了另外一種方式,就是實體類的屬性調用方式,來得到字段的名稱。

          為什么要使用這種方式?我主要是基于以下幾點問題考慮:

      • 平臺無關性:對象的屬性調用只要是面向對象的語言都可以,比如C++,VB,.NET,Java....,OQL是可以進行其它平臺移植的
      • .NET框架低版本支持:框架僅需.NET 2.0 支持,如果引入Linq方式,那么意味著框架需要.net 3.5及以上版本支持
      • 簡化條件調用:在Where方法中直接調用實體類的屬性,不僅得到了調用的字段名,還得到了要查詢的字段值

       

      [示例說明]


          在PDF.NET的開源項目(http://pwmis.codeplex.com )中,有一個示例項目:《超市管理系統》,該項目演示了OQL的基本使用。下面我們說明下如何具體使用這些功能,詳細的實例代碼大家可以去這個開源網站下載。

      一、OQL 數據查詢:

      [示例1]--查詢所有收銀員:

          收銀員只是雇員的一種類型,因此我們從雇員表中查找工作崗位類型名稱是收銀員的雇員信息,并且以姓名排序:

       Employee emp = new Employee();
       emp.JobName = "收銀員";
      
       OQL q = OQL.From(emp)
                      .Select(emp.WorkNumber,emp.EmployeeName)
                      .Where(emp.JobName)
                      .OrderBy(emp.EmployeeName, "asc")
                  .END;

          下面,我們對這段代碼中的OQL方法進行詳細的說明。

      1.1、OQL根表達式

          --返回OQL對象的方法或者屬性調用

      1.1.1,From 方法:

          是一個靜態方法,它以一個實體類對象為參數,返回值是一個OQL實例對象:

               /// <summary>
              /// 靜態實體對象表達式
               /// </summary>
              /// <param name="e">實體對象實例</param>
              /// <returns>實體對象查詢表達式</returns>
              public static OQL From(EntityBase e)
              {
                 //... ...
              }

      1.1.2,實例方法

          除了使用From靜態方法構造OQL的實例,也可以采取直接調用構造函數的方式,比如本例這樣使用:

      OQL q=new OQL(emp);
      q.Select(emp.WorkNumber,emp.EmployeeName)
       .Where(emp.JobName)
       .OrderBy(emp.EmployeeName, "asc");

         

      1.1.3,End 屬性

      從前面可以知道,可以靜態From方式和直接調用構造函數方式的得到OQL,前者結尾有一個 .End 屬性調用,因為 OrderBy 方法返回的對象是OQL1,而不是OQL,所以需要調用End 屬性,返回本次操作OQL的當前對象實例,下面的方法實現能夠說明這個原理:

             public OQL END
              {
                  get { return this.CurrOQL; }
              }

      當我們需要在一行代碼內進行查詢的時候,調用End屬性非常方便,它可以直接把當前OQL對象返回給EntityQuery查詢對象,比如一行代碼查詢用戶列表:

      var userList=OQL.From<User>().Select().End.ToList<User>();

      注意: 這里用上了PDF.NET框架的OQL擴展,需要項目引用PWMIS.Core.Extensions.dll 以及在你的代碼文件上引入名字空間:
          using PWMIS.Core.Extensions;

         詳細例子請參看《不使用反射,“一行代碼”實現Web、WinForm窗體表單數據的填充、收集、清除,和到數據庫的CRUD

       

      1.2、OQL一級表達式

          --返回OQL1對象的方法或者屬性調用,該級別的方法由OQL根級表達式生成并使用。

      1.2.1,Select 方法:

          選取查詢需要的實體類屬性,下面是方法定義:

             /// <summary>
              /// 選取實體對象的屬性
              /// </summary>
              /// <param name="fields">屬性字段列表</param>
              /// <returns>實體對象查詢基本表達式</returns>
              public OQL1 Select(params object[] fields)
              {
                    //... ...
              }

          比如這里選取了雇員實體類的 工號(WorkNumber)、雇員名稱(EmployeeName)兩個屬性,實際上,雇員表有多個字段:


            "工號", "姓名", "性別","出生日期","入職時間","職務名稱"


          但我們這里不需要這么多,只需要上面2個即可。
          “字段名按需選取”應該是一個成熟的ORM框架具備的功能之一,如果需要選取全部字段,也就是SQL的*:

      Select * From table

          那么OQL1的Select方法不傳入參數即可:

      OQL q=new OQL(emp);
      q.Select();

          選取多個實體屬性(多表字段):

          上面的例子是選取單個實體(表)的方式,選取多個實體類的屬性是類似的,Select方法的參數使用不同的實體類的屬性即可:

      OQL q=OQL.From(entity1)
               .InnerJoin(entity2).On(entity1.PK,entity2.FK)
               .Select(entity1.Field1,entity1.Field2,entity2.Field1,entity2.Field2....)
      .End;

          正是因為PDF.NET的OQL的Select等方法,都是使用“實體類.屬性”調用的方式,使得操作多個實體類方便快捷,試想如果采用泛型,這個Select方法應該有多少個重載呢?

      1.2.2,Where方法:

          設置OQL的查詢條件。

          Where方法有幾種重載,每種方法各有特點,先看看方法聲明:

      1.2.2.1,直接使用多個條件屬性作為并列的Where查詢條件

          適用于直接利用屬性值作為字段“=”值操作的“And”條件方式:

              /// <summary>
              /// 獲取并列查詢條件,如 Where(u.Uid,u.Name);
              /// </summary>
              /// <param name="expression">實體屬性列表</param>
              /// <returns>基本表達式</returns>
              public OQL1 Where(params object[] expression)

          比如本文的例子,查找制定工作職位名的雇員信息:

      q.Select(emp.WorkNumber,emp.EmployeeName)
        .Where(emp.JobName)
        .OrderBy(emp.EmployeeName, "asc");
      1.2.2.2,使用OQL2 條件對象作為參數

          可以按照順序進行條件的Not,And,Or操作,方法定義:

               /// <summary>
              /// 獲取復雜查詢條件
              /// </summary>
              /// <param name="c">多條件表達式</param>
              /// <returns>基本表達式</returns>
              public OQL1 Where(OQL2 c)

          OQL對象實例中已經有一個OQL2對象的屬性Condition,可以直接使用,下面是例子:

      [示例2]--獲取所有的可售商品總數

              /// <summary>
              /// 獲取所有的可售商品總數
              /// </summary>
              /// <returns></returns>
              public int GetGoodsStockCount()
              {
                  GoodsStock stock = new GoodsStock();
                  OQL q = new OQL(stock);
                  q.Select()
                      .Count(stock.Stocks, "庫存數量")
                      .Where(q.Condition.AND(stock.Stocks, ">", 0));
      
                  stock = EntityQuery<GoodsStock>.QueryObject(q);
                  return stock.Stocks;
              }

       

      1.2.2.3,使用OQLCompare對象作為參數

          OQLCompare 對象是一個組合對象,也就是N個OQLComapre可以按照各種條件組合成一個OQLCompare對象,從而構造超級復雜的Where查詢條件,支持帶括號“()”的條件組合,后面會有實例展示。

              /// <summary>
              /// 獲取復雜查詢條件(具有邏輯優先級的復雜比較條件)
               /// </summary>
              /// <param name="compare">實體對象比較類</param>
              /// <returns>基本表達式</returns>
              public OQL1 Where(OQLCompare compare)

          下面是一個使用OQLComapre對象處理非常復雜的條件查詢例子,

      生成OQL查詢
              /// <summary>
              /// 生成查詢數據的OQL對象
              /// </summary>
              /// <param name="qcItem"></param>
              /// <returns></returns>
              private OQL getOQLSelect(QueryConditionModel qcItem)
              {
                  TsCarSource cs = initCarSourceFromQueryCondition(qcItem);
                  PublishInfo ap = new PublishInfo(); // StartTime,EndTime 屬于復雜查詢
                  BidRecord br = new BidRecord();
                  TstOrder tst = new TstOrder();
      
                  OQLCompare cmpResult = getOQLCompare(qcItem, cs, ap, tst);
      
                  OQL q = OQL.From(cs)
                      .InnerJoin(ap).On(cs.CarSourceID, ap.CarSourceId)
                      .LeftJoin(tst).On(cs.CarSourceID, tst.CarSourceID)
                      .Select(
                              cs.CarSourceID,
                              cs.ProducerId, cs.BrandId, cs.CityAreaId, cs.CarSourceOwner,
                              cs.CityId, cs.CarIdentityNumber, cs.TvaID, cs.CarSourceOwner,
                              cs.LicenseNumber, cs.CarUseType, cs.PurchasePrice,
                              ap.PublishId, ap.StartTime, ap.EndTime,
                              ap.ReservationPrice, ap.StartPrice,ap.HighestBidprice,tst.BargainPrice,ap.Status,ap.BidCount,ap.BidListCount,ap.PriceEndTime,ap.StopTime,ap.PriceStopTime,
                              
                              cs.MasterBrandId,cs.CarTypeId,cs.CarBodyColor,cs.Mileage
                      )
                      .Where(cmpResult)
                      .OrderBy(ap.StartTime, "desc") //PublishInfo.StartTime desc
                      .END;
      
                  return q;
              }
      
              /// <summary>
              /// 生成條件比較對象
              /// </summary>
              /// <param name="qcItem"></param>
              /// <param name="cs"></param>
              /// <param name="ap"></param>
              /// <param name="br"></param>
              /// <returns></returns>
              private OQLCompare getOQLCompare(QueryConditionModel qcItem, TsCarSource cs, PublishInfo ap, TstOrder tst)
              {
                  OQLCompare cmp = new OQLCompare(cs, ap, tst);
                  OQLCompare cmpResult = null;
                  if (qcItem.AccountType.Value == 1)
                  {
                      cs.TvaID = qcItem.TvaId.Value;
                      cmpResult = cmp.Comparer(cs.TvaID);
                  }
                  else
                  {
                      string tvaids = GetTvaidList(qcItem.TvaId.Value);//in
                      cmpResult = cmp.Comparer(cs.TvaID, OQLCompare.CompareType.IN, tvaids);//in
                  }
      
                  if (qcItem.TabIndex == 1)//拍賣中
                  {
                      ap.Status = 1;
                      cmpResult = cmpResult&cmp.Comparer(ap.Status);
                  }
                  else //PriceStatus大于1,為拍賣結束的
                  {
                      cmpResult = cmpResult&cmp.Comparer(ap.Status, OQLCompare.CompareType.Greater, 1);
                  }
                  if (qcItem.QueryType == 0)
                  {
                      //默認查詢條件
                      
                  }
                  else if (qcItem.QueryType == 1)
                  {
                      //按照Vin碼或者號牌進行查詢
                      cmpResult = cmpResult & (
                          cmp.Comparer(cs.LicenseNumber, OQLCompare.CompareType.Like,"%"+ qcItem.VinCodeOrPlateNumber+"%")
                          |
                          cmp.Comparer(cs.CarIdentityNumber, OQLCompare.CompareType.Like, "%" + qcItem.VinCodeOrPlateNumber + "%")
                          );
                  }
                  else
                  {
                      //其它復雜查詢條件
                      //處理區域條件
                      if (qcItem.CityId.HasValue && qcItem.CityId.Value > 0)
                      {
                          cmpResult = cmpResult & cmp.Comparer(cs.CityId, "=", qcItem.CityId.Value);
                      }
                      else if (qcItem.ProvinceId.HasValue && qcItem.ProvinceId.Value > 0)
                      {
                          cmpResult = cmpResult & cmp.Comparer(cs.ProvinceId, "=", qcItem.ProvinceId.Value);
                      }
                      else if (qcItem.BigAreaId.HasValue && qcItem.BigAreaId.Value > 0)
                      {
                          var provinces = new CommonDL().GetProvincesByBigAreaID(qcItem.BigAreaId.Value);
                          if (provinces.Count > 0)
                          {
                              var provinceids = string.Join(",", provinces.Select(o => o.ProvinceId));
                              cmpResult = cmpResult & cmp.Comparer(cs.ProvinceId, OQLCompare.CompareType.IN, provinceids);
                          }
                      }
                      //end
      
                      if (!string.IsNullOrEmpty(qcItem.State) && qcItem.State!="0"&&qcItem.TabIndex.Value==2)
                          cmpResult = cmpResult & cmp.Comparer(ap.Status, "=", Convert.ToByte( qcItem.State));
                      //if (cs.CityAreaId > 0)
                      //    cmpResult = cmpResult & cmp.Comparer(cs.CityAreaId);
                      if(qcItem.BrandId.HasValue&&qcItem.BrandId.Value>0)
                          cmpResult = cmpResult & cmp.Comparer(cs.MasterBrandId, "=", qcItem.BrandId.Value);
                      if (qcItem.SerialId.HasValue&&qcItem.SerialId.Value>0)
                          cmpResult = cmpResult & cmp.Comparer(cs.BrandId,"=",qcItem.SerialId.Value);
                      if (qcItem.StartTime.HasValue)
                          cmpResult = cmpResult & cmp.Comparer(ap.PriceStopTime, OQLCompare.CompareType.GreaterThanOrEqual, qcItem.StartTime.Value);
                      if(qcItem.EndTime.HasValue)
                          cmpResult = cmpResult & cmp.Comparer(ap.PriceStopTime, OQLCompare.CompareType.LessThanOrEqual, qcItem.EndTime.Value.AddDays(1));
                      if (!string.IsNullOrEmpty(qcItem.EndTimePoint))
                      {
                         string[] items= qcItem.EndTimePoint.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                         
                         //多個時間點的OR條件組合
                         List<OQLCompare> OrCmp1 = new List<OQLCompare>();
                         foreach (string item in items)
                         {
                             int hour = int.Parse(item);
                             if (hour != 0) 
                             {
                                 //今日3個時段結束的
                                 OQLCompare cmpTemp = cmp.Comparer(ap.PriceEndTime, "=", hour, "DATEPART(hh,{0})");
                                 OrCmp1.Add(cmpTemp);
                             }
                             else
                             {
                                 //明日結束的
                                OQLCompare cmpOther= cmp.Comparer(ap.PriceEndTime, ">=", DateTime.Now.Date.AddDays(1));
                                OrCmp1.Add(cmpOther);
                             }
                         }
                         cmpResult = cmpResult & cmp.Comparer(OrCmp1, OQLCompare.CompareLogic.OR);
                      }
                  }
      
                  return cmpResult;
              }

          PS:由于查詢比較復雜,請先看了下面有關OQL關聯實體查詢之后再看本例。這個示例中的OQLCompare對象使用方式已經過時,請看本文【2.1.1,更新指定范圍的數據】黃色標記的部分,現在OQLCompare對象不支持從實體類實例化,而是必須從OQL對象實例化。。
          執行查詢會生成如下復雜的SQL語句:

      SELECT 
             cs.CarSourceID,
             ap.PublishId,
             cs.ProducerId,cs.BrandId,cs.CityAreaId,
             cs.ProducerId,cs.CityId,cs.CarIdentityNumber,cs.TvaID,cs.CarSourceOwner,
             cs.LicenseNumber,cs.CarUseType,cs.CarStatus,
             ap.StartTime,ap.EndTime,
             ap.AnticipantPrice,ap.StartPrice,
             br.CurrPrice
         FROM dbo.TranstarCarSource AS cs
             INNER JOIN dbo.PublishInfo AS ap ON cs.CarSourceID=ap.CarSourceId
             INNER JOIN dbo.BidRecord AS br ON ap.PublishId=br.PublishId
         WHERE cs.CarStatus=1
      And (/* 這里是動態構造的查詢條件*/ )

       

      1.2.2.4,使用QueryParameter 數組作為并列的查詢參數

          適合于專門的表單查詢界面,比如指定日期字段要大于某天且要小于某天。將表單查詢頁面的控件的值收集到QueryParameter 對象即可完成此查詢。

              /// <summary>
              /// 根據傳入的查詢參數數組,對字段名執行不區分大小寫的比較,生成查詢條件。
               /// </summary>
              /// <param name="queryParas">查詢參數數組</param>
              /// <returns>條件表達式</returns>
              public OQL1 Where(QueryParameter[] queryParas)

      1.2.3,OrderBy方法:

          設置OQL的排序方式,分為2種方式:

      1.2.3.1,直接指定排序屬性和方式:
              /// <summary>
              /// 設定排序條件
                /// </summary>
              /// <param name="field">實體對象屬性</param>
              /// <param name="orderType">排序類型 ASC,DESC</param>
              /// <returns></returns>
              public OQL1 OrderBy(object field, string orderType)

          該方法很簡單,就是傳入一個要排序的實體類屬性和排序的方式(降序、增序),如本例:

      OQL q=new OQL(emp);
      q.Select(emp.WorkNumber,emp.EmployeeName)
       .Where(emp.JobName)
       .OrderBy(emp.EmployeeName, "asc");
      1.2.3.2,使用OQLOrder 排序對象:
      public OQL1 OrderBy(OQLOrder order)
      {
       //... ...
      }

          例如下面的使用方式,對“用戶屬性視圖”進行總成績查詢且以UID方式排序:

      [示例3]--OQLOrder對象排序

       UserPropertyView up = new UserPropertyView();
       OQL q = new OQL(up);
       OQLOrder order = new OQLOrder(up);
       q.Select()
         .Where(q.Condition.AND(up.PropertyName, "=", "總成績").AND(up.PropertyValue,">",1000))
         .OrderBy(order.Asc(up.UID));

       

      二、數據修改


         OQL提供了在表達式級別的數據修改、刪除數據寫入操作,數據的插入不需要使用OQL,直接調用EntityQuery<T> 對象的Inert方法即可。

      2.1,更新數據

              /// <summary>
              /// 更新實體類的某些屬性值,如果未指定條件,則使用主鍵值為條件。
               /// </summary>
              /// <param name="fields">實體屬性列表</param>
              /// <returns>條件表達式</returns>
              public OQL1 Update(params object[] fields)

      2.1.1,更新指定范圍的數據

          由于方法返回的是OQL1對象,意味著OQL的更新表達式可以后續使用Where方法來限定要更新的范圍,
          例如下面的例子,修改雇員“張三”的工號為“123456”:

       Employee emp = new Employee();
       emp.WorkNumber = "123456";
       emp.EmployeeName="張三";
      
       OQL q=OQL.From(emp)
           .Update(emp.WorkNumber)
           .Where(emp.EmployeeName)
       .End;
      
       EntityQuery<Employee>.Instance.ExecuteOql(q);

         上面的例子只會更新一條記錄,指定相應的Where參數,OQL還可以進行復雜條件的更新或者更新多條記錄。

          如果需要更復雜的更新條件,也可以在Where中使用OQLCompare對象,但由于當前版本的OQL處理機制問題,規定在Update操作的是后,OQL跟OQLCompare 不用用同樣一個實體類實例,如下面的寫法是錯誤的:


      LT_Users userCmp = new LT_Users();
                  LT_Users userQ = new LT_Users();
                  //OQLCompare cmp = new OQLCompare(userCmp);//過時
                  OQL q = new OQL(userQ);
      OQLCompare cmp = new OQLCompare(q);
                  OQLCompare  cmpResult = cmp.Comparer(userCmp.ID, "in", "1,2,3")
                      & cmp.Comparer(userCmp.LastLoginIP, "=", "127.0.0.1");
                 
                  q.Update(userQ.Authority).Where(cmpResult);

          正確的方式應該這樣:

       LT_Users user = new LT_Users();
      //OQLCompare cmp = new OQLCompare(userCmp);//過時
      OQL q = new OQL(user);
       OQLCompare cmp = new OQLCompare(q);
      OQLCompare cmpResult = cmp.Comparer(user.ID, "in", "1,2,3")
                      & cmp.Comparer(user.LastLoginIP, "=", "127.0.0.1");
      q.Update(user.Authority).Where(cmpResult);

       

       

          PS:更新單個實體對象,可以直接使用 EntityQuery而不需要使用OQL,但必須指定實體對象的主鍵值,例如上面的例子可以修改成:

       Employee emp = new Employee();
       emp.WorkNumber = "123456";
       emp.UserID=100;//主鍵
      
       EntityQuery<Employee>.Instance.Update(q);

       2.1.2,UpdateSelf 字段自更新

          用于數字型字段的值加、減一個新值得情況,比如更新會員的積分,購買物品后將會員的原有積分加上本次獲得的積分。

      [示例4]--更新會員積分

      AdoHelper db = MyDB.GetDBHelper();
      //... 其它代碼略
       SuperMarketDAL.Entitys.CustomerContactInfo ccInfo = new CustomerContactInfo();
       ccInfo.CustomerID = customer.CustomerID;
       ccInfo.Integral = integral;
       OQL qc = OQL.From(ccInfo)
                   .UpdateSelf('+', ccInfo.Integral )
                   .Where(ccInfo.CustomerID )
                .END;
       EntityQuery<SuperMarketDAL.Entitys.GoodsStock>.ExecuteOql(qc, db);
      
      

          采用這種方式,就不必事先進行一個查詢將積分先查詢出來,修改后再更新到數據庫,節省了一次數據查詢過程。


      2.2,刪除數據

              /// <summary>
              /// 刪除實體類,如果未指定條件,則使用主鍵值為條件。
               /// </summary>
              /// <returns>條件表達式</returns>
              public OQL1 Delete()

          由于方法返回的是OQL1對象,意味著OQL的刪除表達式可以后續使用Where方法來限定要刪除的范圍,
          例如下面的例子,刪除雇員“張三”的記錄:

       Employee emp = new Employee();
       emp.EmployeeName="張三";
      
       OQL q=OQL.From(emp)
           .Delete()
           .Where(emp.EmployeeName)
       .End;
      
       EntityQuery<Employee>.Instance.ExecuteOql(q);


          PS:刪除單個實體對象,可以直接使用 EntityQuery而不需要使用OQL,但必須指定實體對象的主鍵值,例如上面的例子可以修改成:

       Employee emp = new Employee();
       emp.UserID=100;//主鍵
      
       EntityQuery<Employee>.Instance.Delete(q);

       

      三、統計、聚合運算

          在SQL中,統計使用Count 謂詞,而其它的聚合運算還有 求平均AVG,求和SUM,求最大MAX,求最小MIN,這些OQL都支持,且用法一樣,下面看一個統計記錄數的例子:

      [示例5]--獲取聯系人信息記錄數量:

              public int GetContactInfoCount()
              {
                  CustomerContactInfo info = new CustomerContactInfo();
                  OQL q = OQL.From(info)
                      .Select()
                      .Count(info.CustomerID, "tempField")
      .END; CustomerContactInfo infoCount
      = EntityQuery<CustomerContactInfo>.QueryObject(q); return Convert.ToInt32(infoCount.PropertyList("tempField"));
      }

          這里按照客戶號進行統計,將統計結果放到SQL的列別名“tempField”中去,最后可以通過實體類的PropertyList 方法取得該值。

          注:"tempField" 并不是實體類CustomerContactInfo 固有的字段,只是SQL查詢出來的一個別名字段而已,但實體類仍然可以訪問它,這就體現了PDF.NET的實體類其實是一個“數據容器”的概念。

      如果不使用別名,那么隨意選取一個int ,long 類型的實體類屬性,存放結果即可,比如本例仍然使用 CustomerID :

      public int GetContactInfoCount()
      {
           CustomerContactInfo info = new CustomerContactInfo();
           OQL q = OQL.From(info)
                   .Select()
                   .Count(info.CustomerID, "")
           .END;
           CustomerContactInfo infoCount = EntityQuery<CustomerContactInfo>.QueryObject(q);
           return infoCount.CustomerID;
      }

      這樣,查詢記錄總數,使用 infoCount.CustomerID 就好了,這個例子也說明了,PDF.NET SOD 實體類,就是數據的容器。

      PS:類似的,將OQL的Count 方法替換成其它聚合方法,可以完成相應的SQL計算功能,OQL代碼都是類似的。

      如果聚合運算同時合并分組計算,聚合函數使用的時候最好指定別名,方便選取結果,如下示例:

                 Table_User user = new Table_User();
                  OQL q = OQL.From(user)
                      .Select().Avg(user.Height,"AvgHeight")
                      .GroupBy(user.Sex)
                      .END;
                  EntityContainer ec = new EntityContainer(q);
                  var result= ec.MapToList(() => new {
                      //獲取聚合函數的值,用下面一行代碼的方式
                      AvgHeight= ec.GetItemValue<double>("AvgHeight"),
                      Sex = user.Sex ?"":""
                  });

      如上按照性別分組查詢男女的平均身高,平均身高字段指定了別名“AvgHeight”,那么在分組查詢后,用延遲指定查詢字段的方式(在MapToList里面指定,參見5.3,延遲Select指定實體類屬性 ),在方法內使用 ec.GetItemValue<double>("AvgHeight") 方法根據平均身高字段的別名獲取查詢的字段值。

      注意:在MapToList方法中使用 ec.GetItemValue 的方式,需要SOD框架的PWMIS.Core.dll 文件版本是5.6.2.0607 以上。

      也可以不使用EntityContainer,而是直接使用EntityQuery泛型對象進行查詢,然后通過訪問結果列表元素的實體類索引器方法來獲取分組平均的結果,如下示例代碼:

      Table_User user = new Table_User();
      OQL q = OQL.From(user)
                 .Select().Avg(user.Height,"AvgHeight")
                 .GroupBy(user.Sex)
             .END;
      
      var list = EntityQuery<Table_User>.QueryList(q);
      foreach (var item in list)
      {
           Console.WriteLine("Sex={0},AvgHeight={1}", item.Sex ? "" : "", item["AvgHeight"]);
      }

       

      執行上面的查詢,會生成下面的SQL語句:

      SELECT  
           [Sex] ,AVG( [Height]) AS AvgHeight 
      FROM [Table_User]  
                GROUP BY  [Sex] 

       

      四、OQL分頁

          SqlServer 2012之前并沒有直接提供分頁的關鍵詞,需要用戶自己編寫分頁SQL語句,比較麻煩,其它數據庫比如MySQL,SQLite等提供了分頁關鍵詞Limit,OQL借鑒了它的特點進行分頁,下面是例子:

      [示例6]--獲取指定頁的聯系人信息

              /// <summary>
              /// 獲取指定頁的聯系人信息
               /// </summary>
              /// <param name="pageSize">每頁的記錄數大小</param>
              /// <param name="pageNumber">頁碼</param>
              /// <param name="allCount">總記錄數</param>
              /// <returns></returns>
              public List<CustomerContactInfo> GetContactInfoList(int pageSize, int pageNumber, int allCount)
              {
                  CustomerContactInfo info = new CustomerContactInfo();
                  OQL q = new OQL(info);
                  q.Select().OrderBy(info.CustomerName, "asc");
                  q.Limit(pageSize, pageNumber);
                  q.PageWithAllRecordCount = allCount;
      
                  return EntityQuery<CustomerContactInfo>.QueryList(q);
              }

       

          注意:OQL分頁的時候除了調用Limit方法指定頁大小和頁碼之外,還必須告訴它記錄總數量,否則可能分頁不準確。

      五、OQL多實體關聯查詢

          在SQL中多表查詢的時候,表的關聯查詢分為內聯 Inner Join,左連接Left Join,右連接 Right Join,OQL通過對實體類進行關聯查詢實現SQL類似的操作,而且語法非常類似,如果用過Linq做表外聯結操作的朋友就知道,Linq的方式跟SQL差異很大的,這里不多說,感興趣的朋友請去查閱相關資料。

      5.1,OQL實體連接方法定義:

              /// <summary>
              /// 內連接查詢
               /// </summary>
              /// <param name="e">要連接的實體對象</param>
              /// <returns>連接對象</returns>
              public JoinEntity Join(EntityBase e)
              {
                  return Join(e, "INNER JOIN");
              }
      
              /// <summary>
              /// 內連接查詢
              /// </summary>
              /// <param name="e">要連接的實體對象</param>
              /// <returns>連接對象</returns>
              public JoinEntity InnerJoin(EntityBase e)
              {
                  return Join(e, "INNER JOIN");
              }
              /// <summary>
              /// 左連接查詢
              /// </summary>
              /// <param name="e">要連接的實體對象</param>
              /// <returns>連接對象</returns>
              public JoinEntity LeftJoin(EntityBase e)
              {
                  return Join(e, "LEFT JOIN");
              }
              /// <summary>
              /// 右連接查詢
              /// </summary>
              /// <param name="e">要連接的實體對象</param>
              /// <returns>連接對象</returns>
              public JoinEntity RightJoin(EntityBase e)
              {
                  return Join(e, "RIGHT JOIN");
              }

       

      5.2,[示例7]獲取商品銷售單視圖:

          該查詢需要將“商品銷售單實體”GoodsSellNote、“雇員”Employee、“客戶聯系信息”CustomerContactInfo 三個實體類進行關聯查詢得到,其中銷售員編號跟雇員工號關聯,銷售單和客戶信息的客戶編號關聯,下面給出OQL多實體類連接的實例代碼:

              public IEnumerable<GoodsSellNoteVM> GetGoodsSellNote()
              {
                  GoodsSellNote note = new GoodsSellNote();
                  Employee emp = new Employee();
                  CustomerContactInfo cst=new CustomerContactInfo ();
                  OQL joinQ = OQL.From(note)
                      .InnerJoin(emp).On(note.SalesmanID, emp.WorkNumber)
                      .InnerJoin(cst).On(note.CustomerID, cst.CustomerID)
                      .Select(note.NoteID, cst.CustomerName, note.ManchinesNumber, emp.EmployeeName, note.SalesType, note.SellDate)
                      .OrderBy(note.NoteID, "desc")
                      .END;
      
                  PWMIS.DataProvider.Data.AdoHelper db = PWMIS.DataProvider.Adapter.MyDB.GetDBHelper();
                  EntityContainer ec = new EntityContainer(joinQ, db);  
                  ec.Execute();
                  //可以使用下面的方式獲得各個成員元素列表
                  //var noteList = ec.Map<GoodsSellNote>().ToList();
                  //var empList = ec.Map<Employee>().ToList();
                  //var cstList = ec.Map<CustomerContactInfo>().ToList();
                  //直接使用下面的方式獲得新的視圖對象
                  var result = ec.Map<GoodsSellNoteVM>(e =>
                      {
                          e.NoteID = ec.GetItemValue<int>(0);
                          e.CustomerName = ec.GetItemValue<string>(1);
                          e.ManchinesNumber = ec.GetItemValue<string>(2);
                          e.EmployeeName = ec.GetItemValue<string>(3);
                          e.SalesType = ec.GetItemValue<string>(4);
                          e.SellDate = ec.GetItemValue<DateTime>(5);
                          return e;
                      }
                  );
                  return result;
              }

       上面的例子中,先在OQL表達式的Select方法指定要查詢的實體屬性,然后在EntityContainer的Map方法內采用 GetItemValue 方法獲取要查詢的結果,查詢的時候GetItemValue 方法參數可以為Select方法指定的實體類屬性的索引順序,也可以是實體類屬性對應的字段名。

       5.3,延遲Select指定實體類屬性

      上面的例子我們發現在Select方法和Map方法內多次指定了字段/屬性信息,代碼量比較重復,因此在后續版本中,支持將Select方法的實體屬性選擇推遲到Map方法內,所以上面的例子可以改寫成下面這樣子:

      /// <summary>
              /// 獲取商品銷售價格信息
              /// </summary>
              /// <returns></returns>
              public IEnumerable<GoodsSaleInfoVM> GetGoodsSaleInfo()
              {
                  GoodsBaseInfo bInfo = new GoodsBaseInfo();
                  GoodsStock stock = new GoodsStock();
                  /*
                   * Select采用指定詳細實體類屬性的方式:
                  OQL joinQ = OQL.From(bInfo)
                      .Join(stock).On(bInfo.SerialNumber, stock.SerialNumber)
                      .Select(
                              bInfo.GoodsName, 
                              bInfo.Manufacturer, 
                              bInfo.SerialNumber, 
                              stock.GoodsPrice, 
                              stock.MakeOnDate, 
                              bInfo.CanUserMonth, 
                              stock.Stocks, 
                              stock.GoodsID)
                      .OrderBy(bInfo.GoodsName, "asc")
                      .END;
                  */
      
                  //Select 方法不指定具體要選擇的實體類屬性,可以推遲到EntityContainer類的MapToList 方法上指定
                  OQL joinQ = OQL.From(bInfo)
                      .Join(stock).On(bInfo.SerialNumber, stock.SerialNumber)
                      .Select()
                      .OrderBy(bInfo.SerialNumber , "asc").OrderBy(bInfo.GoodsName, "asc")
                      .END;
      
                  joinQ.Limit(3, 3);
      
                  PWMIS.DataProvider.Data.AdoHelper db = PWMIS.DataProvider.Adapter.MyDB.GetDBHelper();
                  EntityContainer ec = new EntityContainer(joinQ, db);
                 
                  /*
                   * 如果OQL的Select方法指定了詳細的實體類屬性,那么映射結果,可以采取下面的方式:
                  var result = ec.Map<GoodsSaleInfoVM>(e =>
                      {
                          e.GoodsName = ec.GetItemValue<string>(0); 
                          e.Manufacturer = ec.GetItemValue<string>(1);
                          e.SerialNumber  = ec.GetItemValue<string>(2);
                          e.GoodsPrice  = ec.GetItemValue<decimal>(3);
                          e.MakeOnDate = ec.GetItemValue<DateTime>(4);
                          e.CanUserMonth = ec.GetItemValue<int>(5);
                          e.Stocks = ec.GetItemValue<int>(6);
                          e.GoodsID = ec.GetItemValue<int>(7);
                          return e;
                      }
                  );
                   */ 
                  var result = ec.MapToList<GoodsSaleInfoVM>(() => new GoodsSaleInfoVM()
                  {
                      GoodsName = bInfo.GoodsName,
                      Manufacturer=bInfo.Manufacturer,
                      SerialNumber=bInfo.SerialNumber,
                      GoodsPrice=stock.GoodsPrice,
                      MakeOnDate=stock.MakeOnDate,
                      CanUserMonth=bInfo.CanUserMonth,
                      Stocks=stock.Stocks,
                      GoodsID=stock.GoodsID,
                      ExpireDate = stock.MakeOnDate.AddMonths(bInfo.CanUserMonth)
                  });
                  return result;
              }

       

      5.4,映射匿名查詢結果

      如果是局部使用多實體類的查詢結果,可以不用定義這個“ViewModel”,在 MapToList方法中,直接使用匿名類型,例如下面的例子:

      OQL q=OQL.From(entity1)
               .Join(entity2).On(entity1.PK,entity2.FK)
               //.Select(entity1.Field1,entity2.Field2) //不再需要指定查詢的屬性
      .Select() .End; EntityContainer ec
      =new EntityContainer(q); var list=ec.MapToList(()=> { return new { Property1=entity1.Field1, Property2=entity2.Field2 }; }); foreache(var item in list) { Console.WriteLine("Property1={0},Property2={1}",item.Property1,item.Property2); }

       

          有關OQL進行多實體類關聯查詢的原理介紹的信息,請參考這篇文章《打造輕量級的實體類數據容器》 

       我們再來看看Linq的左、右連接,比較下哪個跟SQL最為接近:

      左連結
      var LeftJoin = from emp in ListOfEmployees
      join dept in ListOfDepartment
      on emp.DeptID equals dept.ID into JoinedEmpDept
      from dept in JoinedEmpDept.DefaultIfEmpty()
      select new                         
      {
      EmployeeName = emp.Name,
      DepartmentName = dept != null ? dept.Name : null                         
      };
      右連接
      var RightJoin = from dept in ListOfDepartment
      join employee in ListOfEmployees
      on dept.ID equals employee.DeptID into joinDeptEmp
      from employee in joinDeptEmp.DefaultIfEmpty()
      select new                           
      {
      EmployeeName = employee != null ? employee.Name : null,
      DepartmentName = dept.Name
      };

       

       [后記]

           PDF.NET框架的很多用戶朋友都在QQ里面跟我說出一份框架的詳細使用手冊,但框架涵蓋的內容面比較大,功能點很多,框架的每個方法背后都有實際的項目代碼例子,換句話說框架完全是從各個實際的項目中總結、提煉出來的。身為“一線碼農”,框架的每個方法使用都歷歷在目,但廣大PDF.NET的用戶朋友或許并不知道這些方法的原理是什么,怎么使用,各種使用方法有什么區別,這些問題成為了前來咨詢我框架使用的每個框架用戶的問題,而我在QQ里面往往不可能回答得很具體全面,所以也就有了概念篇之后的這篇實例篇。盡管寫這篇文章花了我1個周末,但還是感覺還有很多沒有說仔細的地方,只有大家遇到問題的時候我們一起來討論總結了!

          最后,再一次感謝廣大支持PDF.NET開發框架的朋友們,感謝無私的捐助會員用戶們,是你們的支持讓我們能夠不斷進步!

      --------------分解線-----------------------------------------

      歡迎加入PDF.NET開源項目 開發技術團隊,做最輕最快的數據框架!


       

      posted on 2013-04-01 14:56  深藍醫生  閱讀(26892)  評論(24)    收藏  舉報

      導航

      主站蜘蛛池模板: 一级国产在线观看高清| 在线播放国产女同闺蜜| 欧美另类videossexo高潮| 无遮高潮国产免费观看| 精品一区二区久久久久久久网站| 夜鲁鲁鲁夜夜综合视频| 风流老熟女一区二区三区| 漂亮人妻被强中文字幕久久| 国产极品视频一区二区三区| 亚洲日本va午夜在线影院| 国产福利社区一区二区| brazzers欧美巨大| 久久午夜色播影院| 亚洲国产av无码综合原创国产| 亚洲av激情一区二区三区| 日韩一区二区在线看精品| 精品亚洲AⅤ无码午夜在线| 日本熟妇XXXX潮喷视频| 免费人成在线观看网站| 一区二区传媒有限公司| 日本中文字幕有码在线视频| 少妇被粗大的猛烈xx动态图| 国产丰满乱子伦无码专区| 日韩有码中文字幕国产| 免费特黄夫妻生活片| 精品一区二区三区女性色| 亚洲AV成人无码久久精品四虎| 亚洲日韩中文字幕在线播放| 九九热在线视频免费观看| 欧美日产国产精品日产| 狠狠干| 国产成人精品无码专区| 99e久热只有精品8在线直播| 巨爆乳中文字幕爆乳区| 成人一区二区三区在线午夜| 97久久超碰亚洲视觉盛宴| 亂倫近親相姦中文字幕| 麻豆一区二区三区香蕉视频| 成人看的污污超级黄网站免费 | 成人国产精品日本在线观看| 黄色不卡视频一区二区三区 |