C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

EFのPOCOでテーブルを作ってほしくない

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■90438 / inTopicNo.1)  EFのPOCOでテーブルを作ってほしくない
  
□投稿者/ あみい (2回)-(2019/03/11(Mon) 16:38:47)

分類:[ASP.NET (C#)] 

EntityFramework6+PostgreSQLでデータファーストを実現したく格闘しております。

とりあえずポトリペタンで訳のわからないコードが自動生成されるのが嫌なので、コードファーストの方法でやってみようと考えています。

テーブルが先にあれば、コードファーストのやり方でもテーブルを作りにいかないはず、と考えてのことです。

おおむねうまく行くのですが、なぜかDbContextのDbSetにToArray()を打つと、以下のようなエラーが出て困っています。(Where()でも同様のエラーが出ます)

-----------------------------------------------------------------------------
System.Data.SqlClient.SqlException
  HResult=0x80131904
  Message=データベースに 'public' という名前のオブジェクトが既に存在します。
直前のエラーにより CREATE SCHEMA に失敗しました。
  Source=.Net SqlClient Data Provider
  スタック トレース:
<例外のスタック トレースを評価できません>
-----------------------------------------------------------------------------

CREATE SCHEMAに失敗したと言っているので、テーブルを作りに行っているっぽいのですが、テーブルは既に存在します。

どなたか、コードファーストの書き方で、既存のテーブルを作りに行く動きを抑止する方法をご存知のかたはいらっしゃいませんか?

ちなみにC#+VisualStudio2017で、下記のようなモデルで試しています。

----------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Test02.Models
{
    public class コードテーブル
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Column(Order =0)]
        public int コード種類 { get; set; }
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Column(Order = 1)]
        public int コード { get; set; }
        public string コード名称 { get; set; }
    }

    public class コードテーブルContext : DbContext
    {
        public DbSet<コードテーブル> コードテーブルs { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema("public");
        }
    }

    public class 性別
    {
        public string コード { get; set; }
        public string コード名称 { get; set; }
    }

    public class 性別リスト
    {
        [Display(Name = "性別")]
        public List<性別> Items { get; set; }
        public 性別リスト()
        {
            var db = new コードテーブルContext();
            var data = db.コードテーブルs.ToArray();    ←ここでエラー
            var gender = data.Where(r => r.コード種類 == 1);
            var edited = gender.Select(s => new 性別() { コード = s.コード.ToString(), コード名称 = s.コード名称 });

            Items = (List<性別>)edited;
        }
    }

}
----------------------------------------------------------------------------------------------------

引用返信 編集キー/
■90453 / inTopicNo.2)  Re[1]: EFのPOCOでテーブルを作ってほしくない
□投稿者/ WebSurfer (1784回)-(2019/03/12(Tue) 14:06:49)
No90438 (あみい さん) に返信

> とりあえずポトリペタンで訳のわからないコードが自動生成されるのが嫌なので、コードファースト
> の方法でやってみようと考えています。

「訳のわからないコード」とは何でしょう? T4 テンプレート(.tt ファイル)のことですか?

であれば、それらは分からなくても支障はなくそのまま置いとけばいいので、DB ファーストの正攻法で
行った方が良いと思うのですが・・・

PostgreSQL のデザイナがどこまでサポートしているか分かりませんが、SQL Server であれば、以下の
記事に書いてあるように、既存のデータベースから Entity Data Model (EDM) を作り、スキャフォール
ディング機能を使って Create, Read, Update, Delete (CRUD) 操作を行うための ASP.NET MVC アプリ
を自力では一行もコードを書かずにデザイナ任せで作成できます。。

スキャフォールディング機能
http://surferonwww.info/BlogEngine/post/2017/07/23/creating-controller-and-view-in-mvc-using-scaffolding-function.aspx

そのほうが自力でコードを書いて訳の分からないエラーで悩むよりよさそうに思うのですが。

どうしてもということでしたら、以下の記事にある「3. Reverse Engineer Model」の方法でコードを
自動生成することを試してみてはいかがですか?

Code First to an Existing Database
https://docs.microsoft.com/ja-jp/ef/ef6/modeling/code-first/workflows/existing-database

引用返信 編集キー/
■90525 / inTopicNo.3)  Re[2]: EFのPOCOでテーブルを作ってほしくない
□投稿者/ あみい (3回)-(2019/03/18(Mon) 11:06:41)
WebSurferさん、まずは返信ありがとうございます。

> 「訳のわからないコード」とは何でしょう? T4 テンプレート(.tt ファイル)のことですか?
そのとおりです。

昔、型付データセットで痛い目に会って以来、VisualStudioのポトリペタンを使いたくありません。
(重い、遅い、メンテしにくいの3拍子でした)

> スキャフォールディング機能
> http://surferonwww.info/BlogEngine/post/2017/07/23/creating-controller-and-view-in-mvc-using-scaffolding-function.aspx

ありがとうございます。参考にします。

> そのほうが自力でコードを書いて訳の分からないエラーで悩むよりよさそうに思うのですが。

そもそもなのですが、コードファーストでも、いったんテーブルが作成されれば、スキーマが変わらない限り
スキーマの変更更新に行かないはずだと思うわけです。
(でないと、安定しているはずのテーブルに毎回スキーマ変更命令が走るということになるので)

POCOにスキーマを変更するような修正を加えれば、それに合わせてスキーマ変更が発生するのは理解できます。
(調べたところ、このケースでどのように振る舞うかのオプションもありました)

今回、私が疑問に思っているケースでは、スキーマの変更は発生しません。
ただ、.ToList()や.Where()したいだけです。
にも関わらず、スキーマ変更っぽい動きをするのが、どうにも納得いかないわけです。

> どうしてもということでしたら、以下の記事にある「3. Reverse Engineer Model」の方法でコードを
> 自動生成することを試してみてはいかがですか?
>
> Code First to an Existing Database
> https://docs.microsoft.com/ja-jp/ef/ef6/modeling/code-first/workflows/existing-database

こちらの参照してみます。ありがとうございます。

引き続き、有識者の方のご意見をお待ちしております。
要点は、
・コードファーストにおいて、POCOを変更してスキーマ変更処理が走るのは当然。
・逆に言えば、コードファーストといえど、POCOに変更がなければスキーマを変更しに行かないはず

というところです。
コードの自動生成の話は、私にとってはニの次です。
引用返信 編集キー/
■90528 / inTopicNo.4)  Re[3]: EFのPOCOでテーブルを作ってほしくない
□投稿者/ WebSurfer (1788回)-(2019/03/18(Mon) 13:26:41)
No90525 (あみい さん) に返信

> ・コードファーストにおいて、POCOを変更してスキーマ変更処理が走るのは当然。
> ・逆に言えば、コードファーストといえど、POCOに変更がなければスキーマを変更しに行かないはず

イニシャライザの設定によります。デフォルトのイニシャライザは CreateDatabaseIfNotExists で、
読んで字のごとく、データベースが存在しない場合のみ生成します。

詳しくは以下の記事を見てください。

Database Initialization Strategies in EF 6 Code-First
http://www.entityframeworktutorial.net/code-first/database-initialization-strategy-in-code-first.aspx

Cutting Edge - Code First とデータベース初期化
https://msdn.microsoft.com/ja-jp/magazine/mt788618.aspx

entity framework code first default initializer をキーワードにググれば、他にも役に立ちそう
な記事が多々ヒットするので、自分でも調べてみてください。

質問者さんのケースで何故エラーになったかは分かりませんが、たぶん、モデルとスキーマに互換性
が無いからであろうと思います。

だから、よくわからないまま自力でコードを書いて訳の分からないエラーで悩むより Visual Studio
に自動生成して貰うことをお勧めしたのですが・・・

引用返信 編集キー/
■90542 / inTopicNo.5)  Re[4]: EFのPOCOでテーブルを作ってほしくない
□投稿者/ あみい (4回)-(2019/03/19(Tue) 19:53:52)
WebSurferさん、引き続き書き込み頂き、ありがとうございます。

No90528 (WebSurfer さん) に返信
> ■No90525 (あみい さん) に返信
>
>>・コードファーストにおいて、POCOを変更してスキーマ変更処理が走るのは当然。
>>・逆に言えば、コードファーストといえど、POCOに変更がなければスキーマを変更しに行かないはず
>
> イニシャライザの設定によります。デフォルトのイニシャライザは CreateDatabaseIfNotExists で、
> 読んで字のごとく、データベースが存在しない場合のみ生成します。

このあたりの知識はあります。
CreateDatabaseIfNotExistsにすれば、データベースが(テーブルが)存在しない時しかメタデータの更新
には行かないはず、と考えています。

> 質問者さんのケースで何故エラーになったかは分かりませんが、たぶん、モデルとスキーマに互換性
> が無いからであろうと思います。

そういえばテーブルのCreate文を付けていませんでしたね。

------------------------------------------------------
create table public.コードテーブル (
コード種別 character(6) not null
, コード integer not null
, コード名称 text not null
, primary key (コード種別,コード)
);
------------------------------------------------------

という感じです。

最初の質問に書いたPOCOクラスは

-------------------------------------------------------------
public class コードテーブル
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column(Order =0)]
public int コード種類 { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column(Order = 1)]
public int コード { get; set; }
public string コード名称 { get; set; }
}
-------------------------------------------------------------

です。

ご指摘頂いたように、おそらくCreateTableとPOCOのスキーマが異なると判断されての事象とは思いますが、
・どこが違うのか?(同じにしか見えない)
・なぜ、.ToList()や.Where()といったリード系のメソッドでスキーマ更新に行こうとするのか?
あたりが、どうにも腑に落ちず、気持ち悪いわけです。

「そんなのにこだわらず、おとなしく自動生成使ったら?」というご意見もごもっともとは思いますが、
気になりだすと止まらないわけです。

引き続き、有識者の方も含め、ご意見をお待ちしております。
引用返信 編集キー/
■90544 / inTopicNo.6)  Re[5]: EFのPOCOでテーブルを作ってほしくない
□投稿者/ WebSurfer (1791回)-(2019/03/19(Tue) 21:14:47)
No90542 (あみい さん) に返信

> 引き続き、有識者の方も含め、ご意見をお待ちしております。

自分が「有識者」度とは思いませんが、そういう言い方はないと思うのですけど・・・
引用返信 編集キー/
■90546 / inTopicNo.7)  Re[6]: EFのPOCOでテーブルを作ってほしくない
□投稿者/ せば (13回)-(2019/03/20(Wed) 11:24:00)
接続設定が見当たらないので追加して動かしてみたら、一応は動きました。
正しいかどうか別として

    public class コードテーブルContext : DbContext
    {
        public DbSet<コードテーブル> コードテーブルs { get; set; }

        public コードテーブルContext()
            : base("DefaultConnection") // ←接続設定
        {
            Database.SetInitializer<コードテーブルContext>(null);
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema("public");
        }

        public static コードテーブルContext Create()
        {
            return new コードテーブルContext();
        }
    }

    var db = コードテーブルContext.Create();
    var test = db.コードテーブルs.ToArray();


なお、DB上のカラムは「コード種別」でコード上では「コード種類」になってたりします。
「DefaultConnection」の指定なしで動かしたら似たようなエラーになったので、それじゃないかなぁっと


引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ