QA@IT

【ASP.NET(MVC)】ODP.NET Entityデータモデルからのテーブル作成・操作について

9382 PV

・クライアント環境
Windows7 Pro
Visual Studio 2013(C#)
ODP.NET(EF6)

・サーバー環境
Windows Server 2012
ORACLE 11g

現在、上記の環境でASP.NETによるWEBアプリケーションの作成を試みております。
参考書やWEBサイトを参考にEntityデータモデルによるテーブルの作成・操作を行おうとしているのですが、
対象DBがOracleの場合の資料が少ないため、下記についてご教示いただけると幸いです。

<データモデル構成>
...中略...

    [Table("スキーマ.MEMBER")]
    public partial class MEMBER
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public DateTime Birth { get; set; }
        public bool Married { get; set; }
        public string Memo { get; set; }
    }

<コンテキスト>
    public partial class TestContext : DbContext
    {

  ...中略...

        public TestContext()
            : base("name=CN_TEST")
        {
        }
        public virtual DbSet<MEMBER> MEMBER { get; set; }

    }

View
@model IEnumerable<TEST.Models.MEMBER>

...中略...

    @foreach (var item in Model) ← ★印エラーとなる
    {
        <tr>
            <td>@item.Name</td>
            <td>@item.Email</td>
            <td>@item.Birth</td>
            <td>@item.Married</td>
            <td>@item.Memo</td>
        </tr>
    }

</table>

実行すると★印の箇所でエラーとなります。
エラー内容:[OracleException (0x80004005): ORA-00955: すでに使用されているオブジェクト名です。]
また、テーブルは正常に作成されるため二度目以降は正常に表示されます。

[Table("スキーマ.MEMBER")]を削除後に実行すると、下記のエラーが出力され、テーブルは作成されません。
エラー内容:「[OracleException (0x80004005): ORA-01918: ユーザー'dbo'は存在しません]」
SQLServerを利用した場合は、[Table("スキーマ.MEMBER")]無しの状態で問題なくできるのですが、Oracleでは
記述方法が異なるのでしょうか。

ご指摘事項がありましたらご教示いただけると幸いです。

よろしくお願いいたします。

-

-

解決しました----------------------------------------------->>>

接続するDB(ドライバ)にかかわらずデフォルトのユーザーは「dbo」となるため、スキーマを指定することで解決。
簡単ですが、Oracle(SQLServer以外?)を使用した場合のコードファーストによるテーブル作成について下記にまとめておきます。

◆コンテキスト作成クラス内でスキーマを指定
using System.Data.Entity;

namespace TEST.Models
{
    public class TESTContext : DbContext
    {
        public TESTContext()
            : base("name=TESTContext")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema("スキーマ名");   // ← スキーマを指定(デフォルトではdbo)。スキーマを指定しないと「__MigrationHistory」もdboで作成しようとするため、エラーとなる。
        }

        public DbSet<Member> Members { get; set; } // ← 規約によりエンティティクラスの複数形(Members)とする。
    }
}

◆エンティティクラス
namespace TEST.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.Spatial;

    [Table("Member")]
    //[Table("Member", Schema = "スキーマ名")] // ← 任意のテーブル名、エンティティクラスに紐付くテーブルのみのスキーマ指定も可能。
    public partial class Member
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public DateTime Birth { get; set; }
        public bool Married { get; set; }
        public string Memo { get; set; }
    }
}

ご回答くださった方々、ありがとうございました。

回答

Oracle で EF Code First は検証できる環境を持っておらず、想像の域を出ませんが・・・

SQLServerを利用した場合は、[Table("スキーマ.MEMBER")]無しの状態で問題なくできるのですが、Oracleでは記述方法が異なるのでしょうか。

Oracle の ODT とか ODP などが EF Code First 規約に従って作られているのであれば(そこは自分は検証できないので分かりませんが)、SQL Server の場合と同様に TableAttribiute 属性無しでも、規約に従って動くはずなので問題ないと思うのですが。

SQL Server の場合、TableAttribiute 属性無しでは、規約に従ってエンティティ・クラス名の複数形がテーブル名にマッピングされます。質問者さんのケースではエンティティ・クラス名は MEMBER なので、それを複数形にした名前で DB にテーブルが生成されているはずです。多分 dbo.MEMBERs となっているのでは? 調べてみてください。

TableAttribiute 属性をつけるのは、エンティティ・クラス名と DB のテーブル名を別にしたいとか、エンティティ・クラス名とは別名の既存の DB のテーブルを利用する場合だそうです。

Code First Data Annotations
https://msdn.microsoft.com/en-us/data/jj591583.aspx

実践 Entity Framework ~ テーブルとフィールド名を変更する
http://increment-i.hateblo.jp/entry/entityframework/tableattribute

Oracle も規約に従えば、TableAttribiute 属性無しでは、エンティティ・クラス名の複数形がテーブル名にマッピングされるはずです。TableAttribiute 属性無しで実際にどのようなテーブルが生成されるか調べてください。規約どおりに作られるなら、エンティティ・クラス名を複数形にした名前で DB にテーブルが生成されるはずです。(SQL Server の dbo というスキーマ名は違うものになるはずですが)

Oracle でエンティティ・クラスの定義に [Table("スキーマ.MEMBER")] を付与した理由は何でしょう?

そこが間違っていて、そもそも TableAttribiute 属性無しでも規約に従って問題なく動くものを、わざわざ間違った属性(MEMBERs と複数になっていないとか、スキーマの設定方法が間違っているとか)を付与して問題になっているような気がします。

始めに書きましたが想像の域を出ていませんので、上記が見当ハズレでしたらすみません。

編集 履歴 (0)
  • ありがとうございます。解決の際の大きな手掛かりとなりました。
    「TableAttribiute 」属性追加時に、スキーマを別の方法で指定することで正常に動作しました。解決方法については「質問事項」に記載します。

    また、SQLServerで正常に動作した際には「Members」を指定していたため正常に動作していたようです。申し訳ございません。
    -

とりあえず質問を読んで気になるのは、Oracleなのに「dbo」というキーワードがでてきていることです。

全くの勘ですが、接続はOracleだが、Entity Frameworkの SQL Serverのドライバが使われているんじゃないかと思います(SQLサーバー用のSQLが発行されている雰囲気がする)。

アプリケーション構成ファイル(.config)などをみて、SQL Server用のドライバが使われていないか確認されると良いのではないでしょうか。

編集 履歴 (0)
  • ご指摘ありがとうございます。
    使用するDBにかかわらず、デフォルトのスキーマは「dbo」となるのが仕様のようで、別にスキーマを指定することで解決しました。

    どうもありがとうございました。
    -
  • > デフォルトのスキーマは「dbo」となるのが仕様
    そうでしたか。こちらこそ調査不足ですみません。

    教えていただきありがとうございます。
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。