質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

「AddObjectは…のメンバーではありません」の原因がわかりません。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 293

takumi0610

score 42

先日、
https://teratail.com/questions/275580
の質問をさせていただいた者ですが、
今回は、アップロードしたファイルをデータベースに登録する処理の実装を試みております。

前提・実現したいこと

アップロードしたファイルをデータベースに保存する機能を実装したいです。
前回同様、以下のサイトを参考にほぼそのまま書いているのですが、表題のようなエラーが発生しております。

https://www.atmarkit.co.jp/fdotnet/dotnettips/939aspmvcfileupload2/aspmvcfileupload2.html

発生している問題・エラーメッセージ

実行前の段階で、UploadController.vbのファイル内の「_db.AddObject("Photo", ph)」の箇所で、
以下のエラーが発生しております。

'AddObject'は'MyMvcContext'のメンバーではありません。

該当のソースコード

※Viewファイルです。(Index.vbhtml)※bodyタグの中身のみ記載
※参考サイトでは、<% %>のような記法で書かれておりますが、ところどころエラーが発生しましたので、書き直しています。

@Code
    ViewData("Title") = "Index"
End Code

<h2>Index</h2>

<div>
    @Using (Html.BeginForm("DbUpload", "Upload", FormMethod.Post, New With {.enctype = "multipart/form-data"}))
        @<input type="file" name="fl" size="50" />
        @<input type="submit" value="送信" />
    End Using

    @ViewData("msg")

</div>


※コントローラファイルです。(UploadController.vb)

Imports System.Web.Mvc
Imports System.IO

Namespace Controllers
    Public Class UploadController
        Inherits Controller

        ' GET: Upload
        Function Index() As ActionResult
            Return View()
        End Function


        ' アップロード処理を行うUpload/Indexアクション
        '(HTTP POSTによる実行)
        <AcceptVerbs(HttpVerbs.Post)>
        Function Index(ByVal fl As HttpPostedFileBase) As ActionResult

            ' コンテンツ・タイプが"image/*"であるか(画像ファイルか)
            ' をチェック
            If fl.ContentType.StartsWith("image/") Then

                ' アップロード先のパスを生成
                Dim upfile As String = Server.MapPath("~/App_Data/Uploaded/") _
                  & Path.GetFileName(fl.FileName)

                ' 同名のファイルが存在する場合はエラー
                If System.IO.File.Exists(upfile) Then
                    ViewData("msg") = "同名のファイルが存在します。"
                Else
                    ' 画像ファイルで同名のファイルが存在しない場合は保存処理
                    fl.SaveAs(upfile)
                    ViewData("msg") = String.Format(
                      "{0}をアップロードしました。", fl.FileName)
                End If
            Else
                ' 画像ファイルでない場合はエラー
                ViewData("msg") = "画像以外はアップロードできません。"
            End If
            ' 入力元のフォームに結果を表示
            Return View()
        End Function


        ' アップロード・フォームを生成するUpload/DbUploadアクション
        Function DbUpload() As ActionResult
            Return View()
        End Function

        ' アップロード処理を行うUpload/DbUploadアクション
        ' (HTTP POSTによる実行)
        <AcceptVerbs(HttpVerbs.Post)>
        Function DbUpload(ByVal fl As HttpPostedFileBase) As ActionResult

            ' コンテンツ・タイプが"image/*"であるか(画像ファイルか)を
            ' チェック
            If fl.ContentType.StartsWith("image/") Then

                ' EDMのコンテキスト・オブジェクトを生成
                Dim _db As New MyMvcContext()

                ' エンティティにアップロード・ファイルの情報をセット
                Dim ph As New Photo()
                ph.Name = Path.GetFileName(fl.FileName)  ' ファイル名
                ph.Mime = fl.ContentType  ' コンテンツ・タイプ

                Dim data(fl.ContentLength) As Byte
                fl.InputStream.Read(data, 0, fl.ContentLength)
                ph.Data = data  ' データ本体

                ' エンティティを追加&データソースに反映
                _db.AddObject("Photo", ph)
                _db.SaveChanges()
                ViewData("msg") = String.Format(
                  "{0}をアップロードしました。", fl.FileName)
            Else
                ' 画像ファイルでない場合はエラー
                ViewData("msg") = "画像以外はアップロードできません。"
            End If
            ' 入力元のフォームに結果を表示
            Return View()
        End Function


    End Class
End Namespace

モデルファイルです。(Photo.vb)

Imports System
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations

Public Class Photo

    Public Property Id As Integer

    Public Property Name As String

    Public Property Mime As String

    Public Property Data As IList(Of HttpPostedFileBase)

End Class

コンテキストファイルです。(MyMvcContext.vb)

Imports System.Data.Entity
Imports Upload

Public Class MyMvcContext : Inherits DbContext
    Public Property Tweets As DbSet(Of Photo) ' Tweetsテーブル
End Class

試したこと

エラー発生箇所となっているAddObjectは、_dbに対してのメソッドであり、_dbは(数行前に宣言している)MyMvcContextのインスタンスなので、
MyMvcContextに何かしら問題があるのでは?と考えてみましたが、その先がわかりません。

補足情報(FW/ツールのバージョンなど)

統合開発環境
Visual Studio2019
(言語:VB.NET、プロジェクトテンプレート:ASP.NET Webアプリケーション MVC)

MVCフレームワークのバージョン
5.2.7

使用PC
Windows10

※平日は仕事のため、返信が19:30以降になります。(22時以降は返信が翌日になることが多いです)
※休日の返信は不定期です。
申し訳ございませんが、どうぞよろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2020/07/11 12:23 編集

    参考にしている @IT のサイトは、その URL を書くだけでなく、クリックしてそこに遷移できるようリンクを貼ってください。

    前のスレッドのアプリは完成したのでしょうか? アップロードしたファイルをアプリのフォルダに保存するということだったはずですが、それは期待通りになっていますか?

    今回参考にしている @IT の記事は、既存の SQL Server データベースがあって、それから DB First でコンテキストクラスとエンティティクラスを生成し、それを使ってファイルを保存するということですが、それは認識してますか? そこが全く分かってなくてメチャクチャという感じがしますけど・・・

    今度は参照している記事の内容をきちんとコピーできていることは十分確認ずみと思っていいですか? (前のような話はもう勘弁願います)

    キャンセル

  • takumi0610

    2020/07/11 15:27

    >SurferOnWww様

    >参考にしている @IT のサイトは、その URL を書くだけでなく、クリックしてそこに遷移できるようリンクを貼ってください。
    →修正いたしました。

    >前のスレッドのアプリは完成したのでしょうか?
    →はい。ソリューションの中の指定フォルダに画像ファイルが格納されていることも確認できました。

    >今回参考にしている @IT の記事は、既存の SQL Server データベースがあって、それから DB First でコンテキストクラスとエンティティクラスを生成し、それを使ってファイルを保存するということですが、それは認識してますか?
    →今回の記事がDB Firstであるという認識はできておりませんでした。指摘いただいてから気づきました。

    >今度は参照している記事の内容をきちんとコピーできていることは十分確認ずみと思っていいですか?
    →一点、vbhtmlファイルのアクション名が、(以前と異なっていることに気が付き)修正させていただきました。申し訳ございません。

    キャンセル

回答 1

checkベストアンサー

0

いろいろ分かってなくて迷走している感じで、先は長そうですがとりあえず説明します。

今回参考にしている @IT の記事は、既存の SQL Server データベースがあって、それから DB First でコンテキストクラスとエンティティクラスを生成し、それを使ってファイルを保存しています。また、記事が古くて、生成されるコンテキストクラスは ObjectContext クラス(DbContext クラスではなくて)を継承しているようです。

まずそのあたりに着目して、自分の書いているコードは何が問題なのかを、時間がかかるかもしれませんが、基本的なことなので理解できるまでよく考えてください。

まず、エラーメッセージ、

'AddObject'は'MyMvcContext'のメンバーではありません。

・・・ですが、質問者さんの書いた MyMvcContext.vb の MyMvcContext クラスは DbContext クラスを継承していますが、それには AddObject メソッドはないということでエラーになってます。

昔は DB First でコンテキストクラスを生成すると、デフォルトでは ObjectContext クラスを継承しました。ObjectContext クラスには AddObject メソッドが含まれます。@IT の記事はそれを使っているようです。

ObjectContext.AddObject(String, Object) メソッド
https://docs.microsoft.com/ja-jp/dotnet/api/system.data.objects.objectcontext.addobject?view=netframework-4.8

もう一つ、もっと根本的な問題ですが、質問者さんは DB First と Code First でのコンテキストクラス / エンティティクラスの作り方の違いが分かってないようです。

今回参考にしている @IT の記事は DB First です。そのようにしたいのであれば、まず SQL Server に @IT の記事のスキーマのデータベースを作ってください。そして、Visual Studio の ADO.NET Entity Data Model ウィザードを使って、その DB から EDM を作成します。

具体例は下の記事のステップ (2) ~ (10) を見てください。

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

これで以下の画像のようなコンテキストクラスと、

イメージ説明

DB のテーブルの数だけエンティティクラスが自動的に生成されます。(下の画像は Employees の例。赤枠で囲った Photo が画像データを保存するものです)

イメージ説明

これを利用して、アクションメソッドでは以下のようにして DB に保存できるはずです。

private NORTHWINDEntities db = new NORTHWINDEntities();
db.Employees.Add(<画像を含む enployee モデル>);
db.SaveChanges();

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/11 15:31

    >SurferOnWww様

    詳しく教えていただき、ありがとうございます。
    時間はかかりましたが、添付記事を参考に一つ一つ実施し、無事エラーを解消することができました。
    ありがとうございます。

    ObjectContextを使うことが古い(Db Firstが良くない?)ような印象を受けましたので、今後、Code Firstでの実装方法を模索した方が良いのかなとも思いました。
    いつもありがとうございます。

    キャンセル

  • 2020/07/11 15:54 編集

    > ObjectContextを使うことが古い(Db Firstが良くない?)ような印象を受けましたので、今後、Code Firstでの実装方法を模索した方が良いのかなとも思いました。

    それは誤解です。上の回答に貼ったコンテキストクラスの画像を見てください。DB First で作ったコンテキストクラスですが DbContext クラスを継承しています。

    そもそも、DB First にするか Code First にするかを選べることは現実的にはないはずです。既存のデーターベースがあって、それに対する操作を行う場合は DB First しか選択肢はないです。

    質門者さんの参考にしている @IT の記事は古いので、ObjectContext を使っていたり Razor 表記になっていなかったりしてます。もっと新しい記事を探すことをお勧めします。

    キャンセル

  • 2020/07/11 18:23

    >SurferOnWww様

    自学習の段階ではどちらでも選べるけども、実際の仕事では自分の任意で決めれないので、
    両方使えるようにしておいた方が良いということですね。
    わかりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る