2017-12-13

EntityFramework 無法匯入 Oracle View?!

同事反應在使用 EntityFramework EDMX 更新 Model 時一直無法將 View 加入(未看先猜是 primary key 所造成的問題,果不其然真的猜中XD)

DB View 的 priamry key 問題在 EntityFramework 使用上很常遇到,只是以往搭配的 DB 都是 SQL Server,想不到這次改成 Oracle,過去的做法就行不通了,就來看看 Oracle 該如何解決吧


錯誤訊息

  1. edmx 選擇加入 View 但 designer 未出現

    1addview

    2noview

  2. 編譯不會出現錯誤訊息

    3noerror

  3. 使用 xml 編輯器打開 edmx 才會看到錯誤

    Errors Found During Generation:
    warning 6013: The table/view 'TESTIDENTITY.ORGUNIT' does not have a primary key defined and no valid primary key could be inferred. This table/view has been excluded. To use the entity, you will need to review your schema, add the correct keys, and uncomment it.
    

    4error

    • SQL Server 的解決方式可以參考保哥的文章 解決 SQL Server 檢視表 (Views) 無法匯入 EDMX 的問題,大意就是使用 SQL Server 的 isnull 語法調整 View,讓 EntityFramework 可以推斷出 primary key 即可
    • 我嘗試透過使用 Oracle 的 nvlCOALESCE 語法(效果等同 SQL Server 的 isnull 語法)都無法讓 EntityFramework 順利推斷出 primary key

只有特定 View 無法使用?!

  • 同個 db 中其他 View 可以正常匯入
  • 無法匯入的類型:使用 union all 語法

解決方式

手動調整 edmx 內容,以下紀錄調整方式

  1. SSDL
    • 取消 EntityType 註解
       <EntityType Name="ORGUNIT">
        <Property Name="ID" Type="number" Precision="10" Scale="0" />
        <Property Name="PARENTID" Type="number" Precision="10" Scale="0" />
        <Property Name="NAME" Type="varchar2" MaxLength="20" />
        <Property Name="LEVEL1" Type="number" Precision="38" Scale="0" />
      </EntityType>
      
    • 加入 key
       <Key>
        <PropertyRef Name="ID" />
      </Key>
      
    • 將 key 加上 Nullable="false"
      Nullable="false"
      
    • 將 View 加至 EntityContainer 中,並指定 store type 為 Views
      <EntitySet Name="ORGUNIT" EntityType="Self.ORGUNIT" Schema="TESTIDENTITY" store:Type="Views" />
      
    • 完整內容
      <EntityType Name="ORGUNIT">
          <Key>
            <PropertyRef Name="ID" />
          </Key>
          <Property Name="ID" Type="number" Precision="10" Scale="0" Nullable="false" />
          <Property Name="PARENTID" Type="number" Precision="10" Scale="0" />
          <Property Name="NAME" Type="varchar2" MaxLength="20" />
          <Property Name="LEVEL1" Type="number" Precision="38" Scale="0" />
      </EntityType>
      <EntityContainer Name="ModelStoreContainer">
          <EntitySet Name="ORGUNIT" EntityType="Self.ORGUNIT" Schema="TESTIDENTITY" store:Type="Views" />
      </EntityContainer>
      

      5SSDL)

  2. CSDL

    這個可以在 model explorer 中加入,可以透過 xml 加入

    • 使用 xml
      • 將 View 加至 EntityContainer 中
        <EntitySet Name="OrgUnit" EntityType="Model.OrgUnit" />
        
      • 加入 EntityType 及屬性定義
        <EntityType Name="OrgUnit">
          <Key>
            <PropertyRef Name="ID" />
          </Key>
          <Property Name="ID" Type="Int32" Nullable="false" />
          <Property Name="NAME" Type="String" Nullable="false" />
          <Property Name="PARENTID" Type="Int32" Nullable="false" />
          <Property Name="LEVEL1" Type="Int32" Nullable="false" />
        </EntityType>
        

      6CSDL

    • 使用 model explorer
      • Add New Entity Type

        7addtype

      • Add Entity --> 指定程式用的名稱及 primary key

        8addeentity

      • Add New Property --> 新增其他屬性

        9addproperty

  3. C-S mapping content

    將 SSDL 與 CSDL mapping,一樣可以使用 xml 及 designer,建議使用 designer 較方便

    • Table Mapping

      13tablemapping

    • Mapping detail

      名稱相同會自動對應,如果有對錯可以手動調整

      14mappingdetail

心得

EntityFramework 搭配 Oracle,還是不像 SQL Server 那樣方便,需要踩的大大小小雷還不少,另外就是相關資料也不好找,常常找得我都會懷疑是真的不支援還只是沒有人分享做法 @@"

參考資訊

  1. 解決 SQL Server 檢視表 (Views) 無法匯入 EDMX 的問題
  2. Is there a way to explicitely have a not-null column in a view
  3. UNION of non-nullable columns is nullable

沒有留言:

張貼留言