程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Linq To Sql進階系列(五)Store Procedure篇

Linq To Sql進階系列(五)Store Procedure篇

編輯:關於.NET

Store Procedure,存儲過程。也是被別人寫過的東西。我習慣性先看別人都寫了點啥,然後才開始 想看看自己還要寫點啥。那就先談談它與udf的區別吧。

在Linq To Sql進階系列(四)User Define Function篇 中,我們提到了兩者的差別。比如Store Procedure支持多個rowset的,而udf不行。他們還有一些其他的差別。Store Procedure只能返回整型, 而udf可以是其他類型,比如char等,除個別類型外,比如imager類型,是不可以做為udf的返回類型的 。Store Procedure支持Out Parameter而udf沒有。

1, SingleResultSet

我們先來看這個sprocs.

CREATE PROCEDURE [dbo].[Customers By City]
    -- Add the parameters for the stored procedure here
    (@param1 NVARCHAR(20))
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    SELECT CustomerID, ContactName, CompanyName, City from Customers as c where c.City=@param1
END

其生成的code如下。

[Function(Name="dbo.[Customers By City]")]
public ISingleResult<Customers_By_CityResult> Customers_By_City([Parameter (DbType="NVarChar(20)")] string param1)
{
  IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo) (MethodInfo.GetCurrentMethod())), param1);
  return ((ISingleResult<Customers_By_CityResult>)(result.ReturnValue));
}

這裡Customers_By_CityResult是這個sprocs的影射類。但你可以在OR Designer裡調整。如圖,

選中該函數後,右擊屬性。就可以使用其他影射類。但是Linq會對返回的rowset做檢查,如果發現返 回結果和影射不匹配它會報錯。而且一旦更改了,當你需要改回去的時候,你只能在Designer中刪掉此 sprocs,然後重新拖過來。

調用它很簡單,就當作一個函數,但是,這裡和普通的linq語句不一樣的地方是,它不是延遲加載的 。

DataClasses1DataContext db = new DataClasses1DataContext();
db.Log = Console.Out;
var q = db.Customers_By_City("London");

正因它不是延遲加載的,所以,linq可以對他進行簡單的內聯操作,比如

DataClasses1DataContext db = new DataClasses1DataContext();
db.Log = Console.Out;

var q = from c in db.Customers_By_City("London")
       orderby c.City
       select c;

注意的時,這裡是Linq To Object而不是Linq To Sql。

2, MultipleResultSets

看下面的例子

CREATE PROCEDURE [dbo].[Get Customer And Orders](@CustomerID nchar(5))
    -- Add the parameters for the stored procedure here
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    SELECT * FROM Customers AS c WHERE c.CustomerID = @CustomerID 
    SELECT * FROM Orders AS o WHERE o.CustomerID = @CustomerID
END

使用OR designer對其影射,其dbml為

  <Function Name="dbo.[Get Customer And Orders]" Method="Get_Customer_And_Orders">
    <Parameter Name="CustomerID" Parameter="customerID" Type="System.String" DbType="NChar (5)" />
    <ElementType Name="Get_Customer_And_OrdersResult">
      <Column Name="CustomerID" Type="System.String" DbType="NChar(5) NOT NULL" CanBeNull="false" />
      <Column Name="CompanyName" Type="System.String" DbType="NVarChar(40) NOT NULL" CanBeNull="false" />
      <Column Name="ContactName" Type="System.String" DbType="NVarChar(30)" CanBeNull="true" />
      <Column Name="ContactTitle" Type="System.String" DbType="NVarChar(30)" CanBeNull="true" />
      <Column Name="Address" Type="System.String" DbType="NVarChar(60)" CanBeNull="true" />
      <Column Name="City" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
      <Column Name="Region" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
      <Column Name="PostalCode" Type="System.String" DbType="NVarChar(10)" CanBeNull="true" />
      <Column Name="Country" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
      <Column Name="Phone" Type="System.String" DbType="NVarChar(24)" CanBeNull="true" />
      <Column Name="Fax" Type="System.String" DbType="NVarChar(24)" CanBeNull="true" />
    </ElementType>
  </Function>

用sqlmetal對它做影射,生成dbml為

<Function Name="dbo.Get Customer And Orders" Method="GetCustomerAndOrders">
    <Parameter Name="CustomerID" Parameter="customerID" Type="System.String" DbType="NChar (5)" />
    <ElementType Name="GetCustomerAndOrdersResult1">
      <Column Name="CustomerID" Type="System.String" DbType="NChar(5)" CanBeNull="true" />
      <Column Name="CompanyName" Type="System.String" DbType="NVarChar(40)" CanBeNull="true" />
      <Column Name="ContactName" Type="System.String" DbType="NVarChar(30)" CanBeNull="true" />
      <Column Name="ContactTitle" Type="System.String" DbType="NVarChar(30)" CanBeNull="true" />
      <Column Name="Address" Type="System.String" DbType="NVarChar(60)" CanBeNull="true" />
      <Column Name="City" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
      <Column Name="Region" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
      <Column Name="PostalCode" Type="System.String" DbType="NVarChar(10)" CanBeNull="true" />
      <Column Name="Country" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
      <Column Name="Phone" Type="System.String" DbType="NVarChar(24)" CanBeNull="true" />
      <Column Name="Fax" Type="System.String" DbType="NVarChar(24)" CanBeNull="true" />
    </ElementType>
    <ElementType Name="GetCustomerAndOrdersResult2">
      <Column Name="OrderID" Type="System.Int32" DbType="Int" CanBeNull="true" />
      <Column Name="CustomerID" Type="System.String" DbType="NChar(5)" CanBeNull="true" />
      <Column Name="EmployeeID" Type="System.Int32" DbType="Int" CanBeNull="true" />
      <Column Name="OrderDate" Type="System.DateTime" DbType="DateTime" CanBeNull="true" />
      <Column Name="RequiredDate" Type="System.DateTime" DbType="DateTime" CanBeNull="true" />
      <Column Name="ShippedDate" Type="System.DateTime" DbType="DateTime" CanBeNull="true" />
      <Column Name="ShipVia" Type="System.Int32" DbType="Int" CanBeNull="true" />
      <Column Name="Freight" Type="System.Decimal" DbType="Money" CanBeNull="true" />
      <Column Name="ShipName" Type="System.String" DbType="NVarChar(40)" CanBeNull="true" />
      <Column Name="ShipAddress" Type="System.String" DbType="NVarChar(60)" CanBeNull="true" />
      <Column Name="ShipCity" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
      <Column Name="ShipRegion" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
      <Column Name="ShipPostalCode" Type="System.String" DbType="NVarChar(10)" CanBeNull="true" />
      <Column Name="ShipCountry" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
    </ElementType>
  </Function>

細比較他們的區別哦。“好像名字不一樣呢”。暈倒。看主要的。第一個只有一個ElementType子項 ,而第二個有2個。這個地方其實可以說是OR designer的一個bug。要想修改這個bug,需要更改一個設 計,而推動更改設計,比較麻煩。但並不是不能改。如果你認為這個真的很需要,而且對你很重要,你 更喜歡用or designer的話,我建議你去下面的社區發帖子。

http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=123&SiteID=1

要求更改此處的問題。因為,我已經無力推動他們修復該bug,ms更樂意聽來自客戶的聲音,說不定 你會成功的哦,還有獎勵的哦。

這個sprocs准確的影射代碼為

[Function(Name="dbo.Get Customer And Orders")]
[ResultType(typeof(GetCustomerAndOrdersResult1))]
[ResultType(typeof(GetCustomerAndOrdersResult2))]
public IMultipleResults GetCustomerAndOrders([Parameter(Name="CustomerID", DbType="NChar (5)")] string customerID)
{
  IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo) (MethodInfo.GetCurrentMethod())), customerID);
  return ((IMultipleResults)(result.ReturnValue));
}

對於MultipleResultSets的sprocs,大家更關注如何取其返回結果。其實很簡單,按順序,一個 rowset,一個rowset的取。這個順序和你sprocs裡的順序是一樣的。

IMultipleResults result = db.GetCustomerAndOrders("SEVES");
IEnumerable<CustomerResultSet> customer = result.GetResult<CustomerResultSet> ();
IEnumerable<OrdersResultSet> orders = result.GetResult<OrdersResultSet> ();

如果,你很貪心,再加一行的話,

IEnumerable<CustomerResultSet> customer = result.GetResult<CustomerResultSet>();

報錯咯,越界了。沒有那麼多,你問要也不給。

3,OutParameters

似乎沒有什麼好講的,很簡單,當作ref 的函數參數輸出的。其也只是在生成的函數裡加了這麼一句

outParameter =  ((System.Nullable<int>)(result.GetParameterValue(1))); 調用 result.GetParameterValue方法,大家要記住這個哦。

4,Return Value

呀,把return value丟那裡了。的確,Linq曾捨棄過return value.後來在qa的堅持下,dev們決定保 留了它。但是,需要你自己去更改code,才能獲得。我們可以從下面這個sprocs上獲得靈感。

CREATE PROCEDURE [dbo].[CustOrderTotal]
@CustomerID nchar(5),
@TotalSales money OUTPUT
AS
SELECT @TotalSales = SUM(OD.UNITPRICE*(1-OD.DISCOUNT) * OD.QUANTITY)
FROM ORDERS O, "ORDER DETAILS" OD
where O.CUSTOMERID = @CustomerID AND O.ORDERID = OD.ORDERID

其影射的code為

[Function(Name="dbo.CustOrderTotal")]
public int CustOrderTotal([Parameter(Name="CustomerID", DbType="NChar(5)")] string customerID, [Parameter(Name="TotalSales", DbType="Money")] ref System.Nullable<decimal> totalSales)
{
  IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo) (MethodInfo.GetCurrentMethod())), customerID, totalSales);
  totalSales = ((System.Nullable<decimal>)(result.GetParameterValue(1)));
  return ((int)(result.ReturnValue));
}

因為該sprocs並沒有rowset返回,其最後只剩返回值了。其是將result.RenturnValue強制轉化為int 型,以得到sprocs的整形返回值。那對於SingleResultSet和MultipleResultSets的,該如何獲取它的返 回值呢?那只有自己動手,修改code了。就是自己強制轉換,而後通過out 參數輸出。比如用第一個 sprocs

[Function(Name = "dbo.[Customers By City]")]
public ISingleResult<Customers_By_CityResult1> Customers_By_City([Parameter (DbType = "NVarChar(20)")] string param1)
{
 IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo) (MethodInfo.GetCurrentMethod())), param1);
 return ((ISingleResult<Customers_By_CityResult1>)(result.ReturnValue));
}
public ISingleResult<Customers_By_CityResult1> Customers_By_City2(string para, out int returnValue)
{
 ISingleResult<Customers_By_CityResult1> result = this.Customers_By_City (para);
 returnValue = (int)result.ReturnValue;
 return ((ISingleResult<Customers_By_CityResult1>)result);
}

測試一下

DataClasses1DataContext db = new DataClasses1DataContext();
db.Log = Console.Out;

int returnValue = -1;
var q = db.Customers_By_City2("London",out returnValue);
Console.WriteLine(returnValue);

也可以使用result.GetParameterValue方法獲取返回值。只是linq會檢查影射函數的參數個數。這個 使用起來比較麻煩。可以這麼使用,比如,有一個sprocs,有2個參數,其中有一個out的參數。這個out 的參數,可以不做任何操作。在影射後,修改其code。這兩個參數的位標是從0開始,依次遞增。其code 本來為outParameter =  ((System.Nullable<int>)(result.GetParameterValue(1))); 將其索 引修改位為2,就是return value了。再大了又該拋了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved