none
LINQのSELECTの全項目と指定項目の違いについて RRS feed

  • 質問

  • LINQのSELECTの全項目はエラーにならず、

    項目指定の場合

    型 'System.Collections.Generic.List`1[VB$AnonymousType_0`6[System.Int32,System.String,System.DateTime,System.String,System.Decimal,System.String]]'
    のオブジェクトを型 'System.Collections.Generic.IEnumerable`1[MvcMovie.Movie]' にキャストできません。

    のエラーになってしまいます。

    LINQのSELECTの全項目の場合(エラーにならない)

                Dim movies = From m In db.Movies
                             Select m
                md.Mymo = movies.ToList()<---モデルクラスへ設定

    LINQのSELECTの項目指定の場合(エラーになる)

                Dim movies = From m In db.Movies
                             Select m.ID, m.Title, m.ReleaseDate, m.Genre, m.Price, m.Rating
                md.Mymo = movies.ToList()<---モデルクラスへ設定(エラーになってしまう)

    DBのテーブル項目内容

    Public Class Movie
        Public Property ID() As Integer

        <Required()>
        Public Property Title() As String

        Public Property ReleaseDate() As Date

        Public Property Genre() As String

        <Required(), Range(5, 100, ErrorMessage:="The price must be between $5 and $100")>
        Public Property Price() As Decimal

        <StringLength(5)>
        Public Property Rating() As String
    End Class

    モデルクラス

    Public Class Mymodel
        Public Property Mymo() As IList(Of Movie)
    End Class

    何故SELECTで全項目の時はエラーにならず、指定項目の時はキャストできませんエラーになるのでしょうか?

    2011年8月15日 6:45

回答

  • 返信ありがとうございます。

    Public Class Mymodel
        Public Property Mymo() As IList(Of Movie)
    End Class

     ↓修正(Movie 型のインスタンス作成は今回はしないことにしましたが、対処方法としてはMovie 型のインスタンス作成と

     言うことですね。(List<Movie> にしたければ、 New Movie With {} を使って Movie 型のインスタンスを作ってください。)

    Public Class Mymodel
        Public Property Mymo() As IList
    End Class

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

    • 回答としてマーク winwin333 2011年8月15日 9:13
    2011年8月15日 9:13
  • 返信ありがとうございます。

    項目指定時は、Movie() クラスへDB項目を設定した方がデータ型が設定されるということですね。ありがとうございました。

    Dim movies = From m In db.Movies
    Select New Movie() With {
    .ID = m.ID,
    .Title = m.Title,
    .ReleaseDate = m.ReleaseDate,
    .Genre = m.Genre,
    .Price = m.Price,
    .Rating = m.Rating }
    md.Mymo = movies.ToList()


    Microsoft SQL Server データ型と、それぞれに対応する System.Data.SqlTypes 名前空間の SQL Server CLR (共通言語ランタイム) データ型および Microsoft .NET Framework のネイティブ CLR データ型を示します。
    http://msdn.microsoft.com/ja-jp/library/ms131092(v=sql.90).aspx

    • 回答としてマーク winwin333 2011年8月15日 11:16
    2011年8月15日 11:16

すべての返信

  • 後者の書き方の、

    Select m.ID, m.Title, m.ReleaseDate, m.Genre, m.Price, m.Rating

    の場合、これは、ID, Title, ReleaseDate, Genre, Price, Rating というプロパティを持つ新しい匿名型が作られます。元の方(Movie クラス)にはなりません。

    List<Movie> にしたければ、 New Movie With {} を使って Movie 型のインスタンスを作ってください。


    IWANAGA Nobuyuki
    2011年8月15日 8:13
  • エラーメッセージを見ると、匿名型のリストを Movie のリストに代入しようとしているため例外が発生しています。クエリは匿名型のリストを生成してます。
    成功するクエリは From m In db.Movies Select m としてるので、推測するに m は Movie 型のインスタンスであり、それをそのまま Select で返却しているからエラーにならないのでしょう。

    対処法としては、Select 句で Movie のコンストラクタを改造し、インスタンスを生成して返却するか、もしくは Mymodel の Mymo プロパティを IList(Of Movie) から IList のみにして対応する方法が考えられます。個人的には IList にするのが好きですね。

     

    Public Class Mymodel
     Public Property Mymo() As IList
    End Class
    

     


    ひらぽん http://d.hatena.ne.jp/hilapon/


    2011年8月15日 8:22
    モデレータ
  • もし Mymodel クラスのプロパティを変更できないなら、以下のように Movie クラスのコンストラクタを改造し、Select 句の中で Movie のインスタンスを生成します。

    Public Class Movie
    	Public Property ID() As Integer
    	<Required()>
    	Public Property Title() As String
    	Public Property ReleaseDate() As Date
    	Public Property Genre() As String
    	<Required(), Range(5, 100, ErrorMessage:="The price must be between $5 and $100")>
    	Public Property Price() As Decimal
    	<StringLength(5)>
    	Public Property Rating() As String
    
    	Public Sub New()
    	End Sub
    
    	Public Sub New (id As Integer, title As String, releaseDate As Date, genre As String, price AS Decimal, rating As String)
    		Me.ID = id
    		Me.Title = title
    		Me.ReleaseDate = releaseDate
    		Me.Genre = genre
    		Me.Price = price
    		Me.Rating = rating
    	End Sub
    End Class
    
    
    Dim movies = From m In db.Movies 
    	Select New Movie(m.ID, m.Title, m.ReleaseDate, m.Genre, m.Price, m.Rating)
    md.Mymo = movies.ToList()
    


    ひらぽん http://d.hatena.ne.jp/hilapon/
    2011年8月15日 8:32
    モデレータ
  • 返信ありがとうございます。

    Public Class Mymodel
        Public Property Mymo() As IList(Of Movie)
    End Class

     ↓修正(Movie 型のインスタンス作成は今回はしないことにしましたが、対処方法としてはMovie 型のインスタンス作成と

     言うことですね。(List<Movie> にしたければ、 New Movie With {} を使って Movie 型のインスタンスを作ってください。)

    Public Class Mymodel
        Public Property Mymo() As IList
    End Class

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

    • 回答としてマーク winwin333 2011年8月15日 9:13
    2011年8月15日 9:13
  • 解決済みのようですが、某所で指摘されました。わざわざコンストラクタ用意せず、オブジェクト初期化子で返す方法もありましたね。orz

     

    Dim movies = From m In db.Movies 
    	Select New Movie() With { 
    		.ID = m.ID, 
    		.Title = m.Title, 
    		.ReleaseDate = m.ReleaseDate, 
    		.Genre = m.Genre, 
    		.Price = m.Price, 
    		.Rating = m.Rating }
    md.Mymo = movies.ToList()
    
    

    あと IList のジェネリック指定しないのも非推奨と指摘されてます。これについてはまだ調べてます。

     


    ひらぽん http://d.hatena.ne.jp/hilapon/

    2011年8月15日 9:24
    モデレータ
  • すみません。更新が遅れて iwanaga さんの発言が読めてませんでした。

    後者の書き方の、

    Select m.ID, m.Title, m.ReleaseDate, m.Genre, m.Price, m.Rating

    の場合、これは、ID, Title, ReleaseDate, Genre, Price, Rating というプロパティを持つ新しい匿名型が作られます。元の方(Movie クラス)にはなりません。

    List<Movie> にしたければ、 New Movie With {} を使って Movie 型のインスタンスを作ってください。


    IWANAGA Nobuyuki


    この回答が最良の対処法だと思えます。

    Public Property Mymo() As IList としてジェネリックを外すのは型の安全性から返って非推奨との意見が何人かの方から上がっております。私がガイドラインを誤って捉えていたようです。誤った情報を提供してすみません。 IList(Of Movie) → IList は忘れてください。


    ひらぽん http://d.hatena.ne.jp/hilapon/
    2011年8月15日 9:54
    モデレータ
  • 返信ありがとうございます。

    項目指定時は、Movie() クラスへDB項目を設定した方がデータ型が設定されるということですね。ありがとうございました。

    Dim movies = From m In db.Movies
    Select New Movie() With {
    .ID = m.ID,
    .Title = m.Title,
    .ReleaseDate = m.ReleaseDate,
    .Genre = m.Genre,
    .Price = m.Price,
    .Rating = m.Rating }
    md.Mymo = movies.ToList()


    Microsoft SQL Server データ型と、それぞれに対応する System.Data.SqlTypes 名前空間の SQL Server CLR (共通言語ランタイム) データ型および Microsoft .NET Framework のネイティブ CLR データ型を示します。
    http://msdn.microsoft.com/ja-jp/library/ms131092(v=sql.90).aspx

    • 回答としてマーク winwin333 2011年8月15日 11:16
    2011年8月15日 11:16