none
MVC C#でのデータバインドがわかりません。 RRS feed

  • 質問

  • ASP.NET MVC C#にてデータバインドを書いています。

    View側でinputしたname=Codeをモデルに渡して、モデルからデータベースアクセスしてCodeと一致するものを検索したいと思っています。

    前任者が書いたVBをC#で書き直しているのですが、VBでは下記で動いています。

    パラメーター
    Public Property Code As Integer

    データバインド
    Public ReadOnly Property Code As IReadOnlyList(Of Integer)
        Get
            Return Me._Codes.Value
        End Get
    End Property
    Private ReadOnly _Codes As New Lazy(Of IReadOnlyList(Of Integer))(
        Function()
            Return If(Me.Code, {}).ToList()
        End Function)

    C#で単純に下記のように書いたのですがうまくいきません。

    パラメーター public int Code { get; set; }   

    データバインド

    public IReadOnlyList<int> Codes
    {
        get
        {
            return this._Codes.Value;
        }
    }

    private Lazy<IReadOnlyList<int>> _Codes = new Lazy<IReadOnlyList<int>>(
            return if (this.Code).{ToList()}
        );

    素人な質問で申し訳ないのですが、なにとぞご教授のほどお願いします。

    • 編集済み yamadamay 2016年2月2日 3:00
    2016年2月2日 2:58

回答

  • 動かなかったとはどのように動かなかったのでしょうか?

    >まだ自分にはASP.NET MVC C#は早かったようで無難にVBで修正していきます。

    と書かれていますが、ASP.NET MVC C#が早いのではなく、VBへの精通度が足らないのが原因だと思います。この状態でVBで修正していくという方向性で結論付けられたことに心配しています。例えば、

    Return If(Me.Code, {}).ToList()

    を、

    return if (this.Code).{ToList()}

    と書かれていますが、VBのコードの意味が分かっていれば、C#でそのように書かれないはずです。この場合のIfの意味は以下を参考にしてみて下さい。

    If Operator (Visual Basic)
    https://msdn.microsoft.com/ja-jp/library/bb513985.aspx

    もし、C#の方がVBよりも精通されているのでしたら、VBで修正されていく場合でもVBを勉強して行かなければならないのは同じですから、VBを勉強しつつ、C#で書いていくという方向でも間違っていないように思えます。もちろん、工数などトータルでかかるコスト等を考慮した上で結論付ける必要がありますので、最終判断はyamada1000さんが行うことになります。

    最初に書いたように、動かない理由が他のところにあるのであれば、ここMSDNフォーラム等を活用されると良いと思います。私の印象としては、動かないのはC#へのコンバートが主な原因ではなく、他に理由があるのではないかと思っています。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 4:50
    モデレータ
  • > 結論から言えば動きませんでした。
    > まだ自分にはASP.NET MVC C#は早かったようで無難にVBで修正していきます。

    そんなに簡単に諦めないで、動くようになるまで頑張ってみませんか?

    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 5:58
  • 変換サービス ↓ があるので使ってみてはいかがですか?

    http://converter.telerik.com/

    ちなみに質問者さんの VB.NET のコード:

    Public Property Code As Integer
     
     Public ReadOnly Property Code As IReadOnlyList(Of Integer)
         Get
             Return Me._Codes.Value
         End Get
     End Property
     Private ReadOnly _Codes As New Lazy(Of IReadOnlyList(Of Integer))(
         Function()
             Return If(Me.Code, {}).ToList()
         End Function)

    を上記 URL の変換サービスを使って C# に変換してみると:

    public int Code { get; set; }
    
    public IReadOnlyList<int> Code {
        get { return this._Codes.Value; }
    }
    
    private readonly Lazy<IReadOnlyList<int>> _Codes = 
      new Lazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    となりました。それで動くかどうかは定義不明な変数等が多々あるので分かりませんが・・・
    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 3:38
  • privateLazy<IReadOnlyList<int>> _Codes =  newLazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    VSで太文字の箇所に赤い波線ができ「カッコの対応や;がおかしいぞ」と言われます。

    {}はVBの構文になりますので、C#だと new object[0]辺りで良いと思います。
    ただ、Codeの定義が2つあり、これだけでエラーになりますので、本来は違うコードではないでしょうか? 最初に掲示されたVBのコードも、そのままではCodeの定義が2つあり、エラーになってしまいます。

    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 8:18
    モデレータ
  • > VSで太文字の箇所に赤い波線ができ「カッコの対応や;がおかしいぞ」と言われます。

    質問者さんのコードで Lazy<IReadOnlyList<int>> のコンストラクタの引数、即ち、

    Lazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    の () => { return (this.Code ?? {}).ToList(); } は IReadOnlyList<int> 型のオブジェクトを初期化して返すラムダ式(もしくはメソッドのデリゲート)になるはずなのですが、そうなってないです。

    Lazy<T> コンストラクター (Func<T>)
    https://msdn.microsoft.com/ja-jp/library/dd642329(v=vs.110).aspx

    従って、IReadOnlyList<int> 型のオブジェクトを初期化して返すメソッドを追加し、それを引数に使う必要があるはずです。

    例えば、Model でそれを行うとすると以下のようになるはずです。

    namespace MvcApplication.Models
    {
        public class Sample
        {
            public IReadOnlyList<int> Code
            {
                get { return this._Codes.Value; }
            }
    
            public static IReadOnlyList<int> GetList()
            {
                IReadOnlyList<int> list = null;
    
                // ここで ReadOnlyList<int> 型オブジェクトを初期化して list に代入する。
                // 初期化に失敗すると list は null のままとする。 
    
                return list;
            }
    
            private readonly Lazy<IReadOnlyList<int>> _Codes = new Lazy<IReadOnlyList<int>>(() =>
            {            
                return GetList() ?? new ReadOnlyList<int>();
            });
    
            // 上で ?? の意味は GetList() が null でなければ GetList() そのものを返し、
            // null の場合は new ReadOnlyList<int>() を返すということ。
            // 従って、GetList() メソッドを null を返さないように作れば以下でよい。
            // private readonly Lazy<IReadOnlyList<int>> _Codes = new Lazy<IReadOnlyList<int>>(GetList);
        }
    }

    #VB.NET のコードも同じことのはずですが・・・
    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 9:18
  • > MVCでデータベースファーストなwebアプリを構築するのに役に立ちそうなサイト
    >(できれば日本語)をご存じないでしょうか?

    ちょっと古くてなんですが、自分的には以下の記事が初心者向けでかなり役に立ちました。← 勘違いしてました。下の方の追伸を見てください。

    第2回 Entity Frameworkコード・ファーストでモデル開発
    http://www.atmarkit.co.jp/fdotnet/aspnetmvc3/aspnetmvc3_03/aspnetmvc3_03_01.html

    あと、自分のブログで恐縮ですが、上記の記事の環境を MVC3 ⇒ MVC4、EF4 ⇒ EF6、SQL Server Compact 4.0 ⇒ SQL Server 2008 Express にした場合の記事も紹介しておきます。

    MVC4 EF Code First
    http://surferonwww.info/BlogEngine/post/2014/12/20/aspnet-mvc4-entity-framework-code-first.aspx

    親子関係のあるデータ登録
    http://surferonwww.info/BlogEngine/post/2014/12/21/create-relational-data-in-parent-and-child-tables-of-sql-server-database.aspx


    【追伸】

    すみません「データベースファースト」でしたね。完全にボケてました(Code First だと思い込んでました)。

    データベースファーストですと、あくまでも自分的にですが、以下の記事が参考になりました。

    10 行でズバリ!! ASP.NET MVC を構成する各コンポーネントとネ​ーミング ルール (C#)
    https://code.msdn.microsoft.com/10-ASPNET-MVC-C-8566eeb5/

    10 行でズバリ!! ASP.NET MVC におけるデータの取得から画面表​示までの流れ (C#)
    https://code.msdn.microsoft.com/10-ASPNET-MVC-C-2098a196

    ただ、質問者さんのコードを見ると .NET 4.5 以降でないと使えないものがありますので、上に紹介した記事は古くて参考にならないかもしれません。

    • 編集済み SurferOnWww 2016年2月2日 13:16 追伸追加
    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月2日 9:27
  • > {}はVBの構文になりますので、C#だと new object[0]辺りで良いと思います。

    ?? の左側のオブジェクトの型によるのではないでしょうか?

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月2日 9:33
  • ?? の左側のオブジェクトの型によるのではないでしょうか?

    おっしゃる通りで、単純なコードコンバートではなく、実際にはそのようにしないと動かないかもしれませんね。掲載されているVBのコードが怪しいので、まずはそこからになると思います。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月2日 12:44
    モデレータ
  • > 太文字が「型または名前空間の名前ReadOnlyList<int>が見つかりませんでした」と言われます。

    すみません、うっかりしてました。ご指摘の通り、

    new ReadOnlyList<int>(); ⇒ new List<int>();

    としないとダメでした。

    > ラムダ式は右の結果を左へ渡すと理解しました。IReadOnlyListへのreturnとしてList<int>
    > を渡せば読み取り専用リストとして機能しますでしょうか?

    GetList() メソッドが、例えばオブジェクトの初期化に失敗して null を返すと、new List<int>() で作った空のリストを使うことになりますが、その先質問者さんのコードでそれをどのように使うかが分からないので何とも言えないです。

    想像ですが、空なので使い道はなさそうな気はします。ただ null ではないのでその先のコードでそれを参照した時 NullReferenceException が出ないぐらいのことはあると思いますが。

    先のレスのコードのコメントにも書きましたが、GetList() メソッドがオブジェクトの初期化に失敗しても null を返さないで、質問者さんの目的に使えるリストを返すようにしした方がよさそうです。

    あと、個人的意見ですが、先のコードのように GetList() を静的メソッドにするのは何となく気持ちが悪いいので、その部分を含め書き直しました。

    public class Sample2
    {
        private readonly Lazy<IReadOnlyList<int>> _codes = null;
            
        public IReadOnlyList<int> Codes
        {
            get { return this._codes.Value; }
        }
    
        private IReadOnlyList<int> GetList()
        {
            IReadOnlyList<int> list = null;
    
            // ここで DB 等からデータを取得しリストを作る。データの取得に失敗した場合でも
            // null ではなくて代わりにその先の目的に使えるリストを作って list に代入する。
    
            return list;
        }
    
        // コンストラクタ
        public Sample2()
        {
            this._codes = new Lazy<IReadOnlyList<int>>(this.GetList);
        }
    }



    • 編集済み SurferOnWww 2016年2月3日 8:34 誤記訂正
    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月3日 8:24
  • 今頃気づいて何ですが・・・

    > Public ReadOnly Property Codes As IReadOnlyList(Of Integer)

    上記で Code ⇒ Codes に訂正されていますが、以下の部分も間違っていませんか?

    誤:Public Property Code As Integer

    正:Public Property Code As Integer()

    そうすれば VB.NET のコードも動く(少なくともコンパイルはできる)レベルになって、それベースに C# に書き換える場合は先の私のレスとは話が違ってくると思われるのですが。

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月3日 23:40
  • >trapemiya様

    データバインド
    Public ReadOnly Property Codes As IReadOnlyList(Of Integer)
        Get
            Return Me._Codes.Value
        End Get
    End Property

    すみません。VBは上記のようにデータバインドがCodesでした。

    すみません。ばたばたしており、返信が遅れました。
    上記の間違いの件、了解しました。そうなると、
    Return If(Me.Code, {}).ToList() は、 Return If(Me.Codes, {}).ToList() の誤りではありませんか?

    いずれにしても掲示板等にコードを掲載する時は、手打ちではなくコピー&ペーストされれば、謝ったコードを掲載する可能性が激減しますので、それを基本とされることをお勧めします。
    先にも申しました通り、まずは正しいVBのコードを掲載していただかないと、C#への変換は進みようがありません。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 0:16
    モデレータ
  • 横レスですみません。

    > Return If(Me.Code, {}).ToList() は、 Return If(Me.Codes, {}).ToList() の誤りではありませんか?

    ToList() で「Integer 型の配列」を List(Of Integer) 型に変換して返しているようです。

    なので、さすが(?)の VB.NET Option Strict Off でも Me.Code(Integer 型を返す)  はコンパイルエラーでした。

    Me.Codes(IReadOnlyList(Of Integer) を返す)の方はコンパイラは通るのですが、循環参照(?)みたいになってしまうので、さすがの VB.NET でも実行時にエラーになると思います。(VB.NET は試していませんが C# では実行時エラーになりました)

    という訳で、上の私のレスに書いたように Code を「Integer 型の配列」を返すプロパティにしてそれを使う必要がありそうです。



    • 編集済み SurferOnWww 2016年2月4日 1:12 誤記訂正
    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 0:40
  • という訳で、上の私のレスに書いたように Code を「Integer 型の配列」を返すプロパティにしてそれを使う必要がありそうです。

    了解しました。検証ありがとうございます。いずれにしても質問者さんからのボール待ちといった状況のようですね。

    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 1:21
    モデレータ
  • > 正しくは下記でした。

    そのコードを先のレスで紹介した変換サービスを使うと以下のようになりますが(このままではダメです)、

    public IEnumerable<int> Code { get; set; }
    
    public IReadOnlyList<int> Codes {
        get { return this._Codes.Value; }
    }
    
    private readonly Lazy<IReadOnlyList<int>> _Codes =
        new Lazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    それに以下のように手を加えれば良い(少なくともコンパイルは通る)はずです。

    (1) Code プロパティに static キーワードを追加して静的にする(フィールド初期化子は静的でないプロパティを参照できないので)

    (2) ラムダ式の中の this.Code ?? {} を Code ?? new List<int>() に変更する(Code を静的プロパティに変更したためと C# では { } は使えないため)

    個人的には、前のレスで紹介したように、Code は静的プロパティにしないで(インスタンスプロパティのままにしておいて)、フィールドの初期化をコンストラクタで行うのが良いと思いますが。



    • 編集済み SurferOnWww 2016年2月4日 4:48 一部訂正
    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 4:47
  • 最初の質問「VB.NET のコードを C# のコードに書き換える」は解決したと思いますが、そうであれば役に立った回答に「回答としてマーク」をつけて(複数可)、このスレッドはクローズしていただくようお願いします。(もし VB.NET ⇒ C# 書き換えの問題が依然として解決していなければその旨書いてください)

    > もし万が一DBが空だった場合nullを返してエラー処理をした方が、問題の切り分けが楽なように思います
    > がどうでしょう?

    とか、

    > viewからinputでCodeを取得し,modelにそれを受け取るためのCodeを定義し、読み取り専用のCodesを定義し、
    > 検索対象が多いので、遅延対策で、_Codesを作る。という認識をしていますが、間違っていましたでしょうか?

    は次のステップの質問として新たに別のスレッドを立てて質問していただければと思います。(このフォーラムは「ユーザー同士の情報交換の場」ということですので、基本的に一つのスレッドで一つの質問が望ましいようです)

    なお、その際は先のレスで紹介したチュートリアルにあるような、誰でも入手可能な AdventureWorks とか Northwind などのサンプルデータベースを例に使って、もっと具体的に書いていただくようお願いします。

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 5:02
  • 解決されたようですが、私の方で自力でできるだけ似せてC#にしてみたコードを掲載しておきます。

    public IEnumerable<int> Code { get; set; }
    
    public IReadOnlyList<int> Codes
    {
        get { return this._Codes.Value; }
    }
    
    private Lazy<IReadOnlyList<int>> _Codes
    {
        get
        {
            return new Lazy<IReadOnlyList<int>>(() => { return (this.Code ?? Enumerable.Range(0, 0)).ToList(); });
        }
    }

    C#ではインスタンスフィールドを他のインスタンスフィールドを使って初期化できないので(VBはできるんですね)、_Codesをプロパティにしました。また、{}はC#では通りませんので、Enumerable.Range(0, 0)でIEnumerable<int>型で要素数0のコレクションを返しています。
    なお、SurferOnWwwさんが書かれているようにCodeを静的なフィールドにしても良いですが、この場合、Codeがプログラム全体で共有されることになりますので、それが原因で運用開始後に障害が発生することがあるかもしれませんので、お気を付けください。

    (追記)
    _Codesはプロパティの名前付け規則から言って一般的ではないので、名前は適当なものに変えたほうが良いです。どのみちprivateかつreadonlyなプロパティですので、名前を変えても大きな影響は出ないと思われます。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/


    2016年2月4日 5:24
    モデレータ

すべての返信

  • 変換サービス ↓ があるので使ってみてはいかがですか?

    http://converter.telerik.com/

    ちなみに質問者さんの VB.NET のコード:

    Public Property Code As Integer
     
     Public ReadOnly Property Code As IReadOnlyList(Of Integer)
         Get
             Return Me._Codes.Value
         End Get
     End Property
     Private ReadOnly _Codes As New Lazy(Of IReadOnlyList(Of Integer))(
         Function()
             Return If(Me.Code, {}).ToList()
         End Function)

    を上記 URL の変換サービスを使って C# に変換してみると:

    public int Code { get; set; }
    
    public IReadOnlyList<int> Code {
        get { return this._Codes.Value; }
    }
    
    private readonly Lazy<IReadOnlyList<int>> _Codes = 
      new Lazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    となりました。それで動くかどうかは定義不明な変数等が多々あるので分かりませんが・・・
    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 3:38
  • 早々にご返事いただきありがとうございます。

    結論から言えば動きませんでした。

    まだ自分にはASP.NET MVC C#は早かったようで無難にVBで修正していきます。

    2016年2月2日 4:20
  • 動かなかったとはどのように動かなかったのでしょうか?

    >まだ自分にはASP.NET MVC C#は早かったようで無難にVBで修正していきます。

    と書かれていますが、ASP.NET MVC C#が早いのではなく、VBへの精通度が足らないのが原因だと思います。この状態でVBで修正していくという方向性で結論付けられたことに心配しています。例えば、

    Return If(Me.Code, {}).ToList()

    を、

    return if (this.Code).{ToList()}

    と書かれていますが、VBのコードの意味が分かっていれば、C#でそのように書かれないはずです。この場合のIfの意味は以下を参考にしてみて下さい。

    If Operator (Visual Basic)
    https://msdn.microsoft.com/ja-jp/library/bb513985.aspx

    もし、C#の方がVBよりも精通されているのでしたら、VBで修正されていく場合でもVBを勉強して行かなければならないのは同じですから、VBを勉強しつつ、C#で書いていくという方向でも間違っていないように思えます。もちろん、工数などトータルでかかるコスト等を考慮した上で結論付ける必要がありますので、最終判断はyamada1000さんが行うことになります。

    最初に書いたように、動かない理由が他のところにあるのであれば、ここMSDNフォーラム等を活用されると良いと思います。私の印象としては、動かないのはC#へのコンバートが主な原因ではなく、他に理由があるのではないかと思っています。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 4:50
    モデレータ
  • > 結論から言えば動きませんでした。
    > まだ自分にはASP.NET MVC C#は早かったようで無難にVBで修正していきます。

    そんなに簡単に諦めないで、動くようになるまで頑張ってみませんか?

    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 5:58
  • trapemiya様

    暖かいコメントありがとうございます。

    率直に申し上げて、VBは初心者。C#初めてなのが現状です。

    ただ業界の流れと業務の幅をと思いまして、インタプリタ時代のVBをMVC VBの見本を見ながらC#で書き直しているのが現状です。

    >>結論から言えば動きませんでした。

    仰る通り、正確ではありませんね。

    privateLazy<IReadOnlyList<int>> _Codes =  newLazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    VSで太文字の箇所に赤い波線ができ「カッコの対応や;がおかしいぞ」と言われます。

    ともなってnamespaceのかっこの対応にも干渉してエラーを吐きます。

    本当に初心者すぎてお恥ずかしい。

    追うとすればどこから解消したらよいでしょうか?

      


    • 編集済み yamadamay 2016年2月2日 6:59
    2016年2月2日 6:52

  • SurferOnWww様

    すみません。昨日から進捗がなく、おまけに社内にプログラマが僕一人なので聞ける相手もいなく、C#もわからず、回答を焦ってしまいました。励ましていただきありがとうございます。頑張ってみます。

    MVCでデータベースファーストなwebアプリを構築するのに役に立ちそうなサイト(できれば日本語)をご存じないでしょうか?


    • 編集済み yamadamay 2016年2月2日 6:59
    2016年2月2日 6:56
  • privateLazy<IReadOnlyList<int>> _Codes =  newLazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    VSで太文字の箇所に赤い波線ができ「カッコの対応や;がおかしいぞ」と言われます。

    {}はVBの構文になりますので、C#だと new object[0]辺りで良いと思います。
    ただ、Codeの定義が2つあり、これだけでエラーになりますので、本来は違うコードではないでしょうか? 最初に掲示されたVBのコードも、そのままではCodeの定義が2つあり、エラーになってしまいます。

    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 8:18
    モデレータ
  • > VSで太文字の箇所に赤い波線ができ「カッコの対応や;がおかしいぞ」と言われます。

    質問者さんのコードで Lazy<IReadOnlyList<int>> のコンストラクタの引数、即ち、

    Lazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    の () => { return (this.Code ?? {}).ToList(); } は IReadOnlyList<int> 型のオブジェクトを初期化して返すラムダ式(もしくはメソッドのデリゲート)になるはずなのですが、そうなってないです。

    Lazy<T> コンストラクター (Func<T>)
    https://msdn.microsoft.com/ja-jp/library/dd642329(v=vs.110).aspx

    従って、IReadOnlyList<int> 型のオブジェクトを初期化して返すメソッドを追加し、それを引数に使う必要があるはずです。

    例えば、Model でそれを行うとすると以下のようになるはずです。

    namespace MvcApplication.Models
    {
        public class Sample
        {
            public IReadOnlyList<int> Code
            {
                get { return this._Codes.Value; }
            }
    
            public static IReadOnlyList<int> GetList()
            {
                IReadOnlyList<int> list = null;
    
                // ここで ReadOnlyList<int> 型オブジェクトを初期化して list に代入する。
                // 初期化に失敗すると list は null のままとする。 
    
                return list;
            }
    
            private readonly Lazy<IReadOnlyList<int>> _Codes = new Lazy<IReadOnlyList<int>>(() =>
            {            
                return GetList() ?? new ReadOnlyList<int>();
            });
    
            // 上で ?? の意味は GetList() が null でなければ GetList() そのものを返し、
            // null の場合は new ReadOnlyList<int>() を返すということ。
            // 従って、GetList() メソッドを null を返さないように作れば以下でよい。
            // private readonly Lazy<IReadOnlyList<int>> _Codes = new Lazy<IReadOnlyList<int>>(GetList);
        }
    }

    #VB.NET のコードも同じことのはずですが・・・
    • 回答としてマーク yamadamay 2016年2月4日 5:14
    2016年2月2日 9:18
  • > MVCでデータベースファーストなwebアプリを構築するのに役に立ちそうなサイト
    >(できれば日本語)をご存じないでしょうか?

    ちょっと古くてなんですが、自分的には以下の記事が初心者向けでかなり役に立ちました。← 勘違いしてました。下の方の追伸を見てください。

    第2回 Entity Frameworkコード・ファーストでモデル開発
    http://www.atmarkit.co.jp/fdotnet/aspnetmvc3/aspnetmvc3_03/aspnetmvc3_03_01.html

    あと、自分のブログで恐縮ですが、上記の記事の環境を MVC3 ⇒ MVC4、EF4 ⇒ EF6、SQL Server Compact 4.0 ⇒ SQL Server 2008 Express にした場合の記事も紹介しておきます。

    MVC4 EF Code First
    http://surferonwww.info/BlogEngine/post/2014/12/20/aspnet-mvc4-entity-framework-code-first.aspx

    親子関係のあるデータ登録
    http://surferonwww.info/BlogEngine/post/2014/12/21/create-relational-data-in-parent-and-child-tables-of-sql-server-database.aspx


    【追伸】

    すみません「データベースファースト」でしたね。完全にボケてました(Code First だと思い込んでました)。

    データベースファーストですと、あくまでも自分的にですが、以下の記事が参考になりました。

    10 行でズバリ!! ASP.NET MVC を構成する各コンポーネントとネ​ーミング ルール (C#)
    https://code.msdn.microsoft.com/10-ASPNET-MVC-C-8566eeb5/

    10 行でズバリ!! ASP.NET MVC におけるデータの取得から画面表​示までの流れ (C#)
    https://code.msdn.microsoft.com/10-ASPNET-MVC-C-2098a196

    ただ、質問者さんのコードを見ると .NET 4.5 以降でないと使えないものがありますので、上に紹介した記事は古くて参考にならないかもしれません。

    • 編集済み SurferOnWww 2016年2月2日 13:16 追伸追加
    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月2日 9:27
  • > {}はVBの構文になりますので、C#だと new object[0]辺りで良いと思います。

    ?? の左側のオブジェクトの型によるのではないでしょうか?

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月2日 9:33
  • ?? の左側のオブジェクトの型によるのではないでしょうか?

    おっしゃる通りで、単純なコードコンバートではなく、実際にはそのようにしないと動かないかもしれませんね。掲載されているVBのコードが怪しいので、まずはそこからになると思います。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月2日 12:44
    モデレータ
  • 理解するのに時間がかかり、返信が遅れて申し訳ありません。

    >trapemiya様

    データバインド
    Public ReadOnly Property Codes As IReadOnlyList(Of Integer)
        Get
            Return Me._Codes.Value
        End Get
    End Property

    すみません。VBは上記のようにデータバインドがCodesでした。

    >SurferOnWww様

    お書き頂いたコードをコピペして内容を思考してみたのですが、

    return GetList() ?? new ReadOnlyList<int>();

    太文字が「型または名前空間の名前ReadOnlyList<int>が見つかりませんでした」と言われます。

    仮にIReadOnlyList<int>にすると

    「抽象クラスまたはインターフェイスIReadOnlyList<int>のインスタンスを作成できません」

    と言われます。なので下記のようではどうでしょうか?

    privatereadonlyLazy<IReadOnlyList<int>> _Codes = newLazy<IReadOnlyList<int>>(() => { return GetList() ?? newList<int>(); });

    浅いですが、ラムダ式は右の結果を左へ渡すと理解しました。IReadOnlyListへの

    returnとしてList<int>を渡せば読み取り専用リストとして機能しますでしょうか?

    ご意見いただければと思います。

    2016年2月3日 5:46
  • > 太文字が「型または名前空間の名前ReadOnlyList<int>が見つかりませんでした」と言われます。

    すみません、うっかりしてました。ご指摘の通り、

    new ReadOnlyList<int>(); ⇒ new List<int>();

    としないとダメでした。

    > ラムダ式は右の結果を左へ渡すと理解しました。IReadOnlyListへのreturnとしてList<int>
    > を渡せば読み取り専用リストとして機能しますでしょうか?

    GetList() メソッドが、例えばオブジェクトの初期化に失敗して null を返すと、new List<int>() で作った空のリストを使うことになりますが、その先質問者さんのコードでそれをどのように使うかが分からないので何とも言えないです。

    想像ですが、空なので使い道はなさそうな気はします。ただ null ではないのでその先のコードでそれを参照した時 NullReferenceException が出ないぐらいのことはあると思いますが。

    先のレスのコードのコメントにも書きましたが、GetList() メソッドがオブジェクトの初期化に失敗しても null を返さないで、質問者さんの目的に使えるリストを返すようにしした方がよさそうです。

    あと、個人的意見ですが、先のコードのように GetList() を静的メソッドにするのは何となく気持ちが悪いいので、その部分を含め書き直しました。

    public class Sample2
    {
        private readonly Lazy<IReadOnlyList<int>> _codes = null;
            
        public IReadOnlyList<int> Codes
        {
            get { return this._codes.Value; }
        }
    
        private IReadOnlyList<int> GetList()
        {
            IReadOnlyList<int> list = null;
    
            // ここで DB 等からデータを取得しリストを作る。データの取得に失敗した場合でも
            // null ではなくて代わりにその先の目的に使えるリストを作って list に代入する。
    
            return list;
        }
    
        // コンストラクタ
        public Sample2()
        {
            this._codes = new Lazy<IReadOnlyList<int>>(this.GetList);
        }
    }



    • 編集済み SurferOnWww 2016年2月3日 8:34 誤記訂正
    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月3日 8:24
  • 今頃気づいて何ですが・・・

    > Public ReadOnly Property Codes As IReadOnlyList(Of Integer)

    上記で Code ⇒ Codes に訂正されていますが、以下の部分も間違っていませんか?

    誤:Public Property Code As Integer

    正:Public Property Code As Integer()

    そうすれば VB.NET のコードも動く(少なくともコンパイルはできる)レベルになって、それベースに C# に書き換える場合は先の私のレスとは話が違ってくると思われるのですが。

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月3日 23:40
  • >trapemiya様

    データバインド
    Public ReadOnly Property Codes As IReadOnlyList(Of Integer)
        Get
            Return Me._Codes.Value
        End Get
    End Property

    すみません。VBは上記のようにデータバインドがCodesでした。

    すみません。ばたばたしており、返信が遅れました。
    上記の間違いの件、了解しました。そうなると、
    Return If(Me.Code, {}).ToList() は、 Return If(Me.Codes, {}).ToList() の誤りではありませんか?

    いずれにしても掲示板等にコードを掲載する時は、手打ちではなくコピー&ペーストされれば、謝ったコードを掲載する可能性が激減しますので、それを基本とされることをお勧めします。
    先にも申しました通り、まずは正しいVBのコードを掲載していただかないと、C#への変換は進みようがありません。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 0:16
    モデレータ
  • 横レスですみません。

    > Return If(Me.Code, {}).ToList() は、 Return If(Me.Codes, {}).ToList() の誤りではありませんか?

    ToList() で「Integer 型の配列」を List(Of Integer) 型に変換して返しているようです。

    なので、さすが(?)の VB.NET Option Strict Off でも Me.Code(Integer 型を返す)  はコンパイルエラーでした。

    Me.Codes(IReadOnlyList(Of Integer) を返す)の方はコンパイラは通るのですが、循環参照(?)みたいになってしまうので、さすがの VB.NET でも実行時にエラーになると思います。(VB.NET は試していませんが C# では実行時エラーになりました)

    という訳で、上の私のレスに書いたように Code を「Integer 型の配列」を返すプロパティにしてそれを使う必要がありそうです。



    • 編集済み SurferOnWww 2016年2月4日 1:12 誤記訂正
    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 0:40
  • という訳で、上の私のレスに書いたように Code を「Integer 型の配列」を返すプロパティにしてそれを使う必要がありそうです。

    了解しました。検証ありがとうございます。いずれにしても質問者さんからのボール待ちといった状況のようですね。

    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 1:21
    モデレータ
  • 大変申し訳ございません。

    最初に提示したVBに誤りがありました。真摯に相談にのって頂いているのに前提を覆してしまいなんとお詫びしたらよいやら。

    正しくは下記でした。

    Public Property Code As IEnumerable(Of Integer)
     
    Public ReadOnly Property Codes As IReadOnlyList(Of Integer)
    	Get
    		Return Me._Codes.Value
    	End Get
    End Property
    Private ReadOnly _Codes As New Lazy(Of IReadOnlyList(Of Integer))(
    	Function()
    		Return If(Me.Code, {}).ToList()
    	End Function)

    僕の理解の不十分さでIEnumerableを置き去りにしてしまいました。

    >SurferOnWww様


    最終的にはDBからデータをEntitiesに起こしこみ下記のようなVBコード(不完全です)で検索をかける予定です。

    Public ReadOnly Property 該当受注コードs As IQueryable(Of Entities.受注コード)
        Get
            Dim result = (
                From 受注コード
                In Me.Context.受注コードs)

            ' 受注コードで絞り込み
            For Each Code In Me.Codes
                result = (
                    From 受注コード
                    In result
                    Where
                        受注コード.コード.Contains(Code)
                    )
            Next

            Return result
        End Get
    End Property

    ほぼDBが空のこと考えられませんが、検索をするにあたりlistをnullにすべきかそれとも空のlistでエラーをなくすかは、どちらの方が僕の好みですがもし万が一DBが空だった場合nullを返してエラー処理をした方が、問題の切り分けが楽なように思いますがどうでしょう?


    >trapemiya様

    >Return If(Me.Code, {}).ToList() は、 Return If(Me.Codes, {}).ToList() の誤りではありませんか?

    上記のコードで間違いありません。

    しっかりと提示できず申し訳ございません。

    viewからinputでCodeを取得し,modelにそれを受け取るためのCodeを定義し、読み取り専用のCodes

    を定義し、検索対象が多いので、遅延対策で、_Codesを作る。

    という認識をしていますが、間違っていましたでしょうか?


    2016年2月4日 2:37
  • > 正しくは下記でした。

    そのコードを先のレスで紹介した変換サービスを使うと以下のようになりますが(このままではダメです)、

    public IEnumerable<int> Code { get; set; }
    
    public IReadOnlyList<int> Codes {
        get { return this._Codes.Value; }
    }
    
    private readonly Lazy<IReadOnlyList<int>> _Codes =
        new Lazy<IReadOnlyList<int>>(() => { return (this.Code ?? {}).ToList(); });

    それに以下のように手を加えれば良い(少なくともコンパイルは通る)はずです。

    (1) Code プロパティに static キーワードを追加して静的にする(フィールド初期化子は静的でないプロパティを参照できないので)

    (2) ラムダ式の中の this.Code ?? {} を Code ?? new List<int>() に変更する(Code を静的プロパティに変更したためと C# では { } は使えないため)

    個人的には、前のレスで紹介したように、Code は静的プロパティにしないで(インスタンスプロパティのままにしておいて)、フィールドの初期化をコンストラクタで行うのが良いと思いますが。



    • 編集済み SurferOnWww 2016年2月4日 4:48 一部訂正
    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 4:47
  • 最初の質問「VB.NET のコードを C# のコードに書き換える」は解決したと思いますが、そうであれば役に立った回答に「回答としてマーク」をつけて(複数可)、このスレッドはクローズしていただくようお願いします。(もし VB.NET ⇒ C# 書き換えの問題が依然として解決していなければその旨書いてください)

    > もし万が一DBが空だった場合nullを返してエラー処理をした方が、問題の切り分けが楽なように思います
    > がどうでしょう?

    とか、

    > viewからinputでCodeを取得し,modelにそれを受け取るためのCodeを定義し、読み取り専用のCodesを定義し、
    > 検索対象が多いので、遅延対策で、_Codesを作る。という認識をしていますが、間違っていましたでしょうか?

    は次のステップの質問として新たに別のスレッドを立てて質問していただければと思います。(このフォーラムは「ユーザー同士の情報交換の場」ということですので、基本的に一つのスレッドで一つの質問が望ましいようです)

    なお、その際は先のレスで紹介したチュートリアルにあるような、誰でも入手可能な AdventureWorks とか Northwind などのサンプルデータベースを例に使って、もっと具体的に書いていただくようお願いします。

    • 回答としてマーク yamadamay 2016年2月4日 5:13
    2016年2月4日 5:02
  • >SurferOnWww様

    申し訳ございません。

    初めての書き込みゆえ、利用方法を正確にとらえられていませんでした。

    C#への変換を確かにうまく行ったので、クローズします。

    ありがとうございました。

    >trapemiya様

    長々とお付き合い頂き、ありがとうございました。

    2016年2月4日 5:16
  • 解決されたようですが、私の方で自力でできるだけ似せてC#にしてみたコードを掲載しておきます。

    public IEnumerable<int> Code { get; set; }
    
    public IReadOnlyList<int> Codes
    {
        get { return this._Codes.Value; }
    }
    
    private Lazy<IReadOnlyList<int>> _Codes
    {
        get
        {
            return new Lazy<IReadOnlyList<int>>(() => { return (this.Code ?? Enumerable.Range(0, 0)).ToList(); });
        }
    }

    C#ではインスタンスフィールドを他のインスタンスフィールドを使って初期化できないので(VBはできるんですね)、_Codesをプロパティにしました。また、{}はC#では通りませんので、Enumerable.Range(0, 0)でIEnumerable<int>型で要素数0のコレクションを返しています。
    なお、SurferOnWwwさんが書かれているようにCodeを静的なフィールドにしても良いですが、この場合、Codeがプログラム全体で共有されることになりますので、それが原因で運用開始後に障害が発生することがあるかもしれませんので、お気を付けください。

    (追記)
    _Codesはプロパティの名前付け規則から言って一般的ではないので、名前は適当なものに変えたほうが良いです。どのみちprivateかつreadonlyなプロパティですので、名前を変えても大きな影響は出ないと思われます。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/


    2016年2月4日 5:24
    モデレータ
  • >trapemiya様

    はい、本題は解決しました。いろいろとご説明ご指摘ありがとうございました。

    そのうえでお手間をとってわざわざコード書いて頂きなんとお礼を申したらよいか。

    こういう書き方もできるのかと感心するばかりです。理解しつつ参考にさせて頂きます。

    また、スレッドを立てる機会がありましたら是非ともよろしくお願いします。

    2016年2月4日 5:38