2011年11月20日 星期日

ASP.NET MVC + Oracle 11g XE + Entity Framework. Part 4

 

Oracle Data Access Components (ODAC) for Microsoft Entity Framework and LINQ to Entities

前面花了三篇的篇幅從安裝Oracle XE、使用管理Oracle XE以及將Northwind資料庫安裝到Oracle XE中,這些的動作都是為了在開發.NET專案時去使用Entity Framework對Oracle資料庫進行資料存取的操作,而最重要的關鍵就在於 ODAC for Microsoft Entity Framework and LINQ to Entities。

Oracle總算是推出了對於Entity Framework的Provider,雖然直到現在還是Beta版,但至少也是一項的選擇,不然以往使用Oracle資料庫的專案,無法使用LINQ to Entities來操作,總覺得做Oracle的專案真的很麻煩,雖然說有商業套件有提供Provider讓開發者可以透過Entity Framework去對Oracle做存取,但是商業套件…尤其又是存取Oracle,那麼就是需要花一大筆錢才能夠獲得解決,當公司擺明就是不想花錢買授權的時候,就是我們開發者頭痛的時候了,接下來就看看這個 ODAC for Microsoft Entity Framework and LINQ to Entities…


取得安裝檔案

廢話不多說,馬上先進入到Oracle的下載頁

http://www.oracle.com/technetwork/indexes/downloads/index.html

image

為什麼不直接說到哪一頁去下載安裝檔案呢?

因為軟體版本會更新的關係,一更新就會異動下載的頁面網址,避免公布一個網址而造成往後看到的人去下載到舊版的檔案,所以就說明一下要去哪裡下載,這樣才能一勞永逸。

image

滑鼠游標移到上方的「Downloads」後會顯示下載的選項區塊,接著我們就點選「Developer Tools」的「Developer Tools for Visual Studio」

image

對於有開發過.NET程式去存取Oracle資料庫專案的開發人員對於此頁應該不陌生,因為ODAC都必須要這裡下載安裝檔案,然而要下載For Microsoft Entity Framework with Oracle的檔案就要睜大眼睛,在網頁的上方就有提供下載檔案的連結。

image

點選連結進入之後就可以到我們的目的地,目前Oracle所發佈的版本為Beta 3,Updated 為 2011-10-17(2011-02-10發佈Beta 1)

 

開發一般的32-bit程式,可以以下載以下版本

image

如果是開發64-bit程式,就下載以下的版本

image

這邊建議各位,在下載檔案的過程中也詳閱讀一下README內容

image

 

下載完成後就解開壓縮檔,執行裡面的「setup.exe」安裝程式

image

安裝的過程就不做說明。

 

新增ASP.NET MVC專案並加入Entity Framework實體模型

image

SNAGHTML4ab7e8a

開啟一個新的專案之後,選擇新增項目,新增一個「ADO.NET 實體模型資料

 

SNAGHTML4adf455

進入的這個畫面後,點選「新增連接

 

SNAGHTML4aeeaa4

接著出現這個視窗,如果上方的資料來源不是「Oracle資料庫(Oracle ODP.NET)」時,請記得點選「變更」去做選擇

SNAGHTML4b07547

 

SNAGHTML4b44986

接著輸入資料庫的連接資訊,輸入完畢之後先不要急著點選「確定」,先點選「測試連接」測試一下連接是否正常。

 

image

如果出現了這樣的錯誤訊息「ORA-12154: TNS: 無法解析指定的連線ID」,這是因為我們直接輸入連線電腦的名稱,而Oracle ODP.NET無法解析,如果是輸入連線電腦的IP則有可能可以順利連接。

image

如果說一定要使用連線電腦名稱來連接的話,有兩種解決的方式:

其一. 增加並修改TNSNames.ora

「tnsnames.ora」這個檔案在我們一開始安裝ODAC或是Oracle Client時並不會自動增加,所以我們必須手動去增加這個檔案,而在本機端安裝ODAC後的目錄中其實是有提供一個sample檔案,位置「C:\app\你的使用者名稱\product\11.2.0\client_1\Network\Admin\Sample」目錄位置依據你安裝ODAC的位置而定,

image

1. 進入「/Network/Admin/Sample」目錄

2. 複製「/Network/Admin/Sample」下的「tnsnames.ora」到「/Network/Admin」目錄下

image

接著就使用文字編輯器開啟「tnsnames.ora」

image

我們從第8行到第15行就複製起來,並貼在下面的地方,並且修改HOST以及SERVICE_NAME以及一開始的alias,

這個alias就是我們在設定資料庫連接的「資料來源名稱」,

image

修改並儲存完成後就可以把「tnsnames.ora」給關閉,回到Visual Studio 2010下再一次使用「test」來測試連接,

這一次就顯示「測試連接成功」

image

 

其二. 使用tnsname設定字串

如果覺得設定上面的步驟與方式有些麻煩的話,其實還有另外一個方式,如有做上面的步驟,哪請先把剛才加入的tnsname設定字串給剪下,而原本的tnsnames.ora就儲存,剛剛剪下的連接字串我們就修改為以下的內容樣式,

(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.137.228)(PORT = 1521))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = xe)))

接著就是把這長長一串連接字串給複製起來,回到Visual Studio 2010中,將剛才複製起來的字串給貼到「資料來源名稱」,接著就測試一下資料庫連接是否正常,下圖就是測試結果。

image

 

繼續進行實體資料模型的設定,在設定好所有的連接屬性並且測試連接成功後就按下「確定」後進行下一步,回到一開始的「實體資料模型精靈」,可以看到視窗中間的實體連接字串已經是剛才所設定的連接屬性,

SNAGHTML4d9e28a

記得要點選連接字串包含敏感性資料,不然無法進行下一步,

SNAGHTML4dbbaee

 

下一步,開始分析資料庫的內容

SNAGHTML4dd9dbe

分析完畢後,

SNAGHTML4df2f05

展開「資料表」的項目

SNAGHTML4dfacdb

我們選擇全部的資料表後點選完成

SNAGHTML4ea6c24

 

接著就可以在「Models」目錄下看到新增完成的「Northwind.edmx」並且自動開啟edmx檔案

SNAGHTML4e2c8a4

 

使用DataContext進行資料的操作

接著我們就來實兵操演一下,先在HomeController的Index() Action來進行資料的取得

HomeController – Index

public ActionResult Index()
{
  ViewBag.Message = "ASP.NET MVC + Oracle 11g XE + Northwind";
  using (NorthwindEntities db = new NorthwindEntities())
  {
    var query = from c in db.Customers
          orderby c.CustomerID
          select c;
    ViewBag.Customers = query.ToList();
  }
  return View();
}

Views/Home/Index..aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<%@ Import Namespace="OracleNorthwind.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    首頁
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%: ViewBag.Message %></h2>
  
  <%
    foreach (var item in ViewBag.Customers)
    { 
  %>
    <span><%= item.CustomerID %> - <%= item.ContactName %>  </span><br />
  <%
    }
  %>
</asp:Content>

執行結果:

image

 

因為資料庫已經有拉好各資料表的關連,所以我們就來試試看以下的作法

public ActionResult Index()
{
  ViewBag.Message = "ASP.NET MVC + Oracle 11g XE + Northwind";
  using (NorthwindEntities db = new NorthwindEntities())
  {
    var query = from o in db.Orders
          orderby o.OrderID
          select new HomeIndexViewModel
          {
            OrderID = o.OrderID,
            CustomerID = o.CustomerID,
            OrderDate = o.OrderDate.Value,
            Amount = o.OrderDetails.Sum(x => x.Quantity * x.UnitPrice)
          };
    ViewBag.Orders = query.ToList();
  }
  return View();
}
namespace OracleNorthwind.ViewModels
{
  public class HomeIndexViewModel
  {
    public Int64 OrderID { get; set; }
    public string CustomerID { get; set; }
    public DateTime OrderDate { get; set; }
    public decimal Amount { get; set; }
  }
}

這邊就不顯示ViewPage的內容,

原以為這樣的操作應該可以正常執行的時候,卻丟出一個讓我傻眼的錯誤訊息…

image

追一下EF所產生的SQL Command

SELECT 
"Project2"."C1" AS "C1", 
"Project2"."OrderID" AS "OrderID", 
"Project2"."CustomerID" AS "CustomerID", 
"Project2"."OrderDate" AS "OrderDate", 
"Project2"."C2" AS "C2"
FROM ( SELECT 
  "Project1"."OrderID" AS "OrderID", 
  "Project1"."CustomerID" AS "CustomerID", 
  "Project1"."OrderDate" AS "OrderDate", 
  1 AS "C1", 
  "Project1"."C1" AS "C2"
  FROM ( SELECT 
    "Extent1"."OrderID" AS "OrderID", 
    "Extent1"."CustomerID" AS "CustomerID", 
    "Extent1"."OrderDate" AS "OrderDate", 
    (SELECT 
      SUM("Filter1"."A1") AS "A1"
      FROM ( SELECT 
        ( CAST( "Extent2"."Quantity" AS number(19,0))) * "Extent2"."UnitPrice" AS "A1"
        FROM "NORTHWIND_USER"."OrderDetails" "Extent2"
        WHERE ("Extent1"."OrderID" = "Extent2"."OrderID")
      )  "Filter1") AS "C1"
    FROM "NORTHWIND_USER"."Orders" "Extent1"
  )  "Project1"
 ORDER BY "OrderID" ASC )  "Project2"

而把這一串由EF所產生的SQL Command去放到Navicat中做執行

image

這一段SQL Command會發生錯誤的地方在於「WHERE ("Extent1"."OrderID" = "Extent2"."OrderID")

這是在取得Order的OrderDetails所產生的錯誤……

其實早在之前就已經知道這樣的一個BUG程湘之間 - 使用 Oracle Entity Framework 的問題」2011-05-21

https://forums.oracle.com/forums/thread.jspa?threadID=2226278

原以為這個明顯的BUG應該會在Beta 2的下一個版本會得到解決,但是我都已經用Beta 3了,這樣一個蠻明顯且嚴重的BUG依然存在,而在Oracle的網頁上也有提到這樣一個BUG問題

http://www.oracle.com/technetwork/topics/dotnet/tech-info/default-338300.html#mozTocId870787

image

這邊得到一個答案,哪就是如果是使用Oracle 10 XE或是更早之前的版本是會發生錯誤的,必須是在 10.2.0.2 以上的資料庫版本,因為ODAC for EF目前只有支援 Oracle 10.2.0.2以上的資料庫,但是我用的是 Oracle 11g Express Edition…那很明顯的就是說…使用Oracle Express Edition會無法完全支援使用ODAC for EF。

因為我手邊沒有正式版本的Oracle資料庫來做測試,所以無法有個對照組來證實在Oracle 11g以上正式版的資料庫是可以正常操作關連資料的取得,現階段對於要取得關連資料時,那就使用迂迴的方式來做,直到 Oracle ODAC for EF真正解決問題為止,

 

參考連結:

Oracle TechNetwork Tutorial - 將Entity Framework、LINQ 和Model-First 用於Oracle 數據庫

 

以上

5 則留言:

  1. Oracle ODAC 11.2 Release 4 (11.2.0.3.0) - Includes support for Entity Framework and LINQ

    http://kevintsengtw.blogspot.com/2012/01/odac-112-release-4-112030-includes.html

    回覆刪除
  2. 你的教學很詳盡,謝謝!
    請問有java連接oracleXE的教學嗎?~.~

    回覆刪除
    回覆
    1. 謝謝你的回應,不過 JAVA 就不是我的技術專長了,我主要是 .NET 網站程式應用方面。

      刪除
  3. Kevin你好,請問我在測試連線的時候出現了錯誤『ORA-03111: 在通訊通道上收到中斷訊號』,但使用工具直接連線資料庫是沒有問題的,請問這問題該怎麼辦呢?謝謝

    回覆刪除
    回覆
    1. Hello, 因為你所提供的訊息只有錯誤編號而已,所以很難判定是什麼問題,而 ORA-03111 屬於很少會碰到的錯誤,
      我的判斷是你執行的查詢是否過於複雜而讓 Oracle 產生的逾時,
      因為用一般的資料庫 GUI 查詢工具(ex: Oracle SQL Developer, TOAD for Oracle 等)與程式執行是有所不同的,
      所以用工具連接資料庫是不會有問題產生的。

      如果你是使用 EntityFramework 連接 Oracle 而出現的問題,我會建議你查看 EF 所產生的 SQL Statement 內容,
      然後用這個 SQL Statement 拿到資料庫查詢工具裡執行,看看是否有無問題,
      再來就是將程式裡的 Query Expression 做適度調整,這部份可以利用 LINQPad 來做測試。

      此外 Oracle 的相關錯誤有太多太多了,不見得每一個錯誤是我都可以碰上或能夠解決的,
      我不是 oracle DBA,只是會用程式與工具去對 oracle 做查詢而已,
      可以到 oracle 官網的論壇裡查詢,https://forums.oracle.com/community/developer/english

      其他參考:
      http://blog.csdn.net/woohooli/article/details/6364831
      http://royontechnology.blogspot.tw/2009/06/mysterious-ora-03111-error.html

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。