web-dev-qa-db-ja.com

1つのビューで2つのIENumerableモデルを使用する方法

1つのビューで2つのモデルを使用しようとしていますが、私の理解では、プログラム内にオブジェクトが表示されません。

これが私のコードです。

モデル:

    public class Album
    {
        [Key]
        public int ThreadId { get; set; } 
        public int GenreId { get; set; }
        public string Title { get; set; }
        public string ThreadByUser { get; set; } 
        public string ThreadCreationDate { get; set; }
        public string ThreadContent { get; set; } 
        public Genre Genre { get; set; }
        public List<Posts> Posty { get; set; }
    }
    public class Posts 
    {
        [Key]
        public int PostId { get; set; }
        public int ThreadId { get; set; } 
        public string PostTitle { get; set; }
        public string PostContent { get; set; }
        public string PostDate { get; set; }
        public string PosterName { get; set; }
        public Album Album { get; set; }

    }

    public class ModelMix
    {
        public IEnumerable<Posts> PostsObject { get; set; }
        public IEnumerable<Album> ThreadsObject { get; set; }
    }  

インデックスコントローラーコード:

    public ActionResult Index(int id)
    {

        ViewBag.ThreadId = id;
        var posts = db.Posts.Include(p => p.Album).ToList();
        var albums = db.Albums.Include(a => a.Genre).ToList();

        var mixmodel = new ModelMix
        {
            PostsObject = posts,
            ThreadsObject = albums
        };

        return View(mixmodel);
    }

コードを表示:

@model MvcMusicStore.Models.ModelMix

<h2>Index</h2>

@Html.DisplayNameFor(model => model.PostsObject.PostContent)

そして、プログラムを実行しようとすると、次のエラーが発生します。

CS1061:「System.Collections.Generic.IEnumerable」に「PostContent」の定義が含まれていません。「PostContent」を展開するメソッドが見つかりません。これは、「System.Collections.Generic.IEnumerable」タイプの最初の引数を取ります。

どうすれば意図したとおりに機能させることができますか?インターネット上に私のような質問がたくさんありますが、私の場合に一致するものは見つかりませんでした。

9
user3163730

テンプレート化されたヘルパー(つまり、Html.DisplayForHtml.EditorFor)に、コレクション内のすべての要素に対してヘルパーが自動的に呼び出すテンプレートを提供できるため、MVCでモデルをループすることは、最初は少し混乱する可能性があります。つまり、MVCを初めて使用し、コレクションにDisplayTemplateまたはEditorTemplateがまだ提供されていないことに気付いていない場合は、単純なように見えます。

@Html.DisplayFor(m => m.SomePropertyThatHoldsACollection)

は、あなたが必要とすることすべてです。したがって、そのようなものをすでに見たことがあれば、それが機能すると仮定した理由かもしれません。ただし、しばらくの間、テンプレートが提供されていないと仮定しましょう。 2つのオプションがあります。

まず、最も簡単に言えば、コレクションに対してforeachを使用することです。

@foreach (var post in Model.PostsObject)
{
    @Html.DisplayFor(m => post.PostTitle)
    // display other properties
}

forループを使用することもできますが、IEnumerable<T>ではインデクサーがないため、これは機能しません。

@for (int i = 0; i < Model.PostsObject.Count(); i++)
{
    // This generates a compile-time error because
    // the index post[i] does not exist.
    // This syntax would work for a List<T> though.
    @Html.DisplayFor(m => post[i].PostTitle)
    // display other properties
}

forループをまだ使用したい場合は、次のように使用できます。

@for (int i = 0; i < Model.PostsObject.Count(); i++)
{
    // This works correctly
    @Html.DisplayFor(m => post.ElementAt(i).PostTitle)
    // display other properties
}

だからあなたが好きな方を使ってください。ただし、ある時点で、 タイプのテンプレート の提供を検討することをお勧めします。 (注:この記事はMVC 2向けに書かれていますが、アドバイスは引き続き適用されます。)ビューからループロジックを削除して、ビューをクリーンに保つことができます。 Html.DisplayForまたはHtml.EditorForと組み合わせると、モデルバインディングの正しい要素名も生成されます(これはすばらしいことです)。また、タイプのプレゼンテーションを再利用することもできます。

最後に、プロパティの名前は少し冗長であるとコメントします。

public class ModelMix
{
    public IEnumerable<Posts> PostsObject { get; set; }
    public IEnumerable<Album> ThreadsObject { get; set; }
}

それらがオブジェクトであることはすでにわかっているので、最後に追加する必要はありません。これはより読みやすいです:

public class ModelMix
{
    public IEnumerable<Posts> Posts { get; set; }
    public IEnumerable<Album> Threads { get; set; }
}
8
John H

通常、任意のタイプのIEnumerable<>を渡す場合は、各アイテムを反復処理する必要があります。半複雑なモデルを作成したので、各リストにforeachアイテムを表示する必要があります。これは、ASP.NETMVCチュートリアルに基づいた例です。少し役立つと思います。

@model IEnumerable<ContosoUniversity.Models.Course>

@{
    ViewBag.Title = "Courses";
}

<h2>Courses</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.CourseID)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Credits)
        </th>
        <th>
            Department
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.CourseID)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Credits)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Department.Name)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.CourseID }) |
            @Html.ActionLink("Details", "Details", new { id=item.CourseID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.CourseID })
        </td>
    </tr>
}

</table>

一般に、ほとんどの人はリストにICollectionを使用します。ここで、例はオブジェクトにあります。

public virtual ICollection<Post> Posts { get; set; }

ソース: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/reading-related-data-with-the-entity-framework-in-an- asp-net-mvc-application

これを行う必要がある理由を理解するのに役立つので、最初から始めることをお勧めします: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc

0
Jon Douglas

次のように繰り返す必要があります。

@model MvcMusicStore.Models.ModelMix

<h2>Index</h2>

@for(var i=0; i<model.PostsObject.Count(); i++)
{
    @Html.DisplayNameFor(model => model.PostsObject[i].PostContent)
}

また、Count()メソッドを使用する代わりに、Countプロパティを持つため、IEnumerableの代わりにIListを保存することをお勧めします。

0
Sergey Litvinov