2015年7月23日 星期四

在MVC 實體資料模型Entity Framework Model加入Oracle 無PK的View的方法




我有個功能,主要參照的TABLE因為一些問題而沒有設定PK,但是又想用MVC EF來開發,
於是我照著MVC課程的做法,建了一個VIEW,裡面包了一個虛擬的PK值,
Oracle View做法:

select ROWNUM as ID,table1.*

from table1


結果跳ERROR2003錯誤,EF無法辨認哪個是PK,
我在虛擬ID的欄位使用了nvl(null,1) as ID、nvl(ROWNUM,1) as ID, ROWNUM as ID、
都還是一樣跳ERROR 2003,

後來有人建議我手動去編輯EDMX的XML,就編修了半天,終於成功帶出資料了

基本上就是複製其他的格式來用
EDMX有三大區塊
1.SSDL content  資料庫的TABLE
2.CSDL content  模型的TABLE
3.C-S mapping content 對照用的區塊

原本正常加入的模型,系統會自動產生這三大區塊的XML碼,
但是現在這個出錯的模型在xml只有加入SSDL區,而且還被註解

<!--錯誤 6013: 資料表/檢視 '' 未定義主索引鍵,也無法推斷有效的主索引鍵。此資料表/檢視已被排除。如果要使用此實體,您必須檢閱您的結構描述,加入正確的索引鍵,並將它取消註解。

<EntityType Name="my_view">

  <Property Name="ID" Type="number" Precision="38" Scale="0" Nullable="false" />

  <Property Name="ORDER_NUMBER" Type="nvarchar2" MaxLength="11" />

  <Property Name="CORRECT_ORDER" Type="number" Precision="38" Scale="0" />

  <Property Name="SEND_DATE" Type="nvarchar2" MaxLength="8" />

  <Property Name="EM_ID" Type="nvarchar2" MaxLength="4" />

  <Property Name="CM_ID" Type="nvarchar2" MaxLength="8" />

  <Property Name="COST" Type="number" Precision="38" Scale="0" />

</EntityType>-->


現在把註解移除,加上KEY值

<EntityType Name="my_view">

  <Key>

    <PropertyRef Name="ID" />

  </Key>

  <Property Name="ID" Type="number" Precision="38" Scale="0" Nullable="false" />

  <Property Name="ORDER_NUMBER" Type="nvarchar2" MaxLength="11" />

  <Property Name="CORRECT_ORDER" Type="number" Precision="38" Scale="0" />

  <Property Name="SEND_DATE" Type="nvarchar2" MaxLength="8" />

  <Property Name="EM_ID" Type="nvarchar2" MaxLength="4" />

  <Property Name="CM_ID" Type="nvarchar2" MaxLength="8" />

  <Property Name="COST" Type="number" Precision="38" Scale="0" />

</EntityType>


EntityType 加上去後,要去SSDL區最後一塊EntityContainer裡面加上一行

<EntityContainer Name="ModelStoreContainer">

  <EntitySet Name="table1" EntityType="Self.table1" Schema="myDB" store:Type="Tables" />

  <EntitySet Name="table2" EntityType="Self.table2" Schema="myDB" store:Type="Tables" />

  <EntitySet Name="table3" EntityType="Self.table3" Schema="myDB" store:Type="Tables" />

  <!--這行-->

  <EntitySet Name="my_view" EntityType="Self.my_view" Schema="myDB" store:Type="Tables" />

</EntityContainer>   

   

 
再來是CSDL的部分,這區系統就完全沒有產生XML了,同樣要填入EntityType 與EntityContainer,
但要注意的是這區的欄位Type是C#的型態,
例如number就是Decimal,nvarchar2就是String,
如果是String欄位,好像還要加上  FixedLength="true/false" Unicode="true/false"屬性
把前面SSDL的架構複製貼上到這區,並且修改TYPE為C#型態

<EntityType Name="my_view">

          <Key>

            <PropertyRef Name="ID" />

          </Key>

          <Property Name="ID" Type="Decimal" Precision="38" Scale="0" Nullable="false" />

          <Property Name="ORDER_NUMBER" Type="String" MaxLength="11" FixedLength="false" Unicode="true" />

          <Property Name="CORRECT_ORDER" Type="Decimal" Precision="38" Scale="0" />

          <Property Name="SEND_DATE" Type="String" MaxLength="8"  FixedLength="false" Unicode="true"/>

          <Property Name="EM_ID" Type="String" MaxLength="4" FixedLength="false" Unicode="true" />

          <Property Name="CM_ID" Type="String" MaxLength="8"  FixedLength="false" Unicode="true"/>

          <Property Name="COST" Type="Decimal" Precision="38" Scale="0" />

</EntityType>


再來同樣在EntityContainer加上一行

<EntityContainer Name="myDBEntities" annotation:LazyLoadingEnabled="true">

          <EntitySet Name="table1" EntityType="Self.AS400_ZDF201" />

          <EntitySet Name="table2" EntityType="Self.AS400_ZDF203" />

          <EntitySet Name="table3" EntityType="Self.AS400_ZDF25A" />

          <!--這行-->

          <EntitySet Name="my_view" EntityType="Self.my_view" />

</EntityContainer>


最後是CS-SS對應區,加上這個view的EntitySetMapping

<EntitySetMapping Name="my_view">

  <EntityTypeMapping TypeName="Model.my_view">

    <MappingFragment StoreEntitySet="my_view">

      <ScalarProperty Name="ID" ColumnName="ID" />

      <ScalarProperty Name="ORDER_NUMBER" ColumnName="ORDER_NUMBER" />

      <ScalarProperty Name="CORRECT_ORDER" ColumnName="CORRECT_ORDER" />

      <ScalarProperty Name="SEND_DATE" ColumnName="SEND_DATE" />

      <ScalarProperty Name="EM_ID" ColumnName="EM_ID" />

      <ScalarProperty Name="CM_ID" ColumnName="CM_ID" />

      <ScalarProperty Name="COST" ColumnName="COST" />

    </MappingFragment>

  </EntityTypeMapping>

</EntitySetMapping>


然後F6編譯,雖然還是會出現ERROR2003,但是建立Controller之後我已經可以撈出資料了!
不過不知道這樣手動增加,之後還會跑出什麼問題...

2015年7月14日 星期二

System.Data.OracleClient與Oracle.DataAccess的變數問題

System.Data.OracleClient跟Oracle.DataAccess.dll 好像對變數的處理不一樣
我有一個查詢語法,日期處理是


DATE between to_date(:DATE || ' 00:00:00','yyyy-mm-dd hh24:mi:ss') and TO_DATE(:DATE || ' 23:59:59','yyyy-mm-dd hh24:mi:ss')

在用前者的時候變數只需要加入一次


Command.Parameters.Add(new OracleParameter("DATE", DATE));

但在用後者的時候,後面那個變數會被認為未給值,
跳出ORA-01008 : Not all variables bound
我要把後面的變數換個名稱,加入兩次變數,才能正常執行


DATE between to_date(:DATE || ' 00:00:00','yyyy-mm-dd hh24:mi:ss') and TO_DATE(:DATE2 || ' 23:59:59','yyyy-mm-dd hh24:mi:ss')

Command.Parameters.Add(new OracleParameter("DATE", DATE));
Command.Parameters.Add(new OracleParameter("DATE2", DATE));

不過同樣的sql在oracle sql developer執行,他也只會要我輸入一次變數值就是了