次に最近投稿した一覧を表示させます。
今回は、コントローラーの PostsController::RecentPosts メソッドから作っていきますね。
■コントローラーを LINQ で作る。
public ActionResult Recent() { int max = 5; wordpressEntities ent = new wordpressEntities(); var model = (from p in ent.wp_posts join u in ent.wp_users on p.post_author equals u.ID where p.post_status == "publish" orderby p.post_date descending select new { Post = p, User = u } ).Take(max); return View(model); }
投稿した人の名前(User.display_name)を表示させたいので、wp_users テーブルとリンクさせます。そていて、最初の5行だけ表示させたいので Take 関数を使っています。
このための専用のモデルを作るのは面倒なので、無名クラスを作って new { Post = p, User = u } として作成しています。
こうすると、ビュー側で
- item.Post.post_author
- item.User.display_name
のように参照ができるハズですね(実は、うまくいきません…)。
■ビューを作る
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Recent </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>最近投稿した記事</h2> <table> <tr> <th>ID</th> <th>post_date</th> <th>post_title</th> <th>post_author</th> <th>User.display_name</th> <th>guid</th> </tr> <% foreach (var item in Model) { %> <tr> <td><%: item.Post.ID %></td> <td><%: item.Post.post_title %></td> <td><%: item.Post.post_date %></td> <td><%: item.Post.post_author %></td> <td><%: item.User.display_name %></td> <td><%: item.Post.guid %></td> </tr> <% } %> </table> <h2>最近投稿した記事(リンク版)</h2> <ul> <% foreach (var item in Model) { %> <li> <a href="<%: item.Post.guid %>"><%: item.Post.post_title %></a> by <%: item.User.display_name %> at <%: item.Post.post_date %> </li> <% } %> </ul> </asp:Content>
型無しの指定なので、ViewPage
それぞれの表示は、そんまま aspx に記述するとタイピングミスが起こるので、あらかじめコントローラー内でコーディングしたものをコピー&ペーストしました。
コントローラーで、
foreach (var item in model) { Debug.Print("{0},{1}", item.Post.ID, item.Post.post_date, item.Post.post_author, item.User.display_name, item.Post.guid ); }
のように作っていくと、インテリセンスが使えて便利です。
さて、これを実行するとですね。。。実行エラーが発生するのです。
なんででしょうね?無名クラスで定義したものが、ビューのところではうまく取得できないようです。
■仕方がないのでモデルクラスを作る
という訳で、仕方がないので Posts モデルクラスを作ります。先に作った FindPosts メソッドも踏まえて、こんな感じです。
public class Posts : wp_posts { public wp_users User { get; set; } public wp_posts Post { get; set; } public IQueryable<wp_posts> FindPosts() { wordpressEntities ent = new wordpressEntities(); var model = from t in ent.wp_posts where t.post_status == "publish" select t; return model; } public List<Posts> RecentPosts(int max) { wordpressEntities ent = new wordpressEntities(); var model = (from p in ent.wp_posts join u in ent.wp_users on p.post_author equals u.ID where p.post_status == "publish" orderby p.post_date descending select new { Post = p, User = u } ).Take(max); List<Posts> posts = new List<Posts>(); foreach (var item in model) { posts.Add( new Posts { Post = item.Post, User = item.User }); } return posts; } }
プロパティで wp_posts と wp_users のテーブルが参照できるように Post, User を定義しておきます。後は、コントローラーで作成していた LINQ の文をコピー&ペーストして、この結果を List に詰めて返します。
対して、コントローラーの RecentPosts メソッドは非常になるのでが、なんだかなぁ、という感じですね。
public ActionResult Recent() { int max = 5; Models.Posts post = new Models.Posts(); var model = post.RecentPosts(max); return View(model); }
これを動かすと、ビューはそのままで綺麗に動きます。
一応、動くには動くのですが、wp_posts と wp_users のテーブルをいちいち join させないといけないのが CakePHP よりも劣っていますよね。
というのは、EDM(Entitiy Data Model)のところでリレーションを設定していないのが原因なのです。CakePHP では Model::$belongsTo などで join を指定しているのですが、wordpress のテーブルから引っ張ってきたテーブルでは、この join が設定されていません。
なので、お次は、リレーションを設定したうえで、最近投稿した一覧を表示させてみます。
item.Post が aspx 内で参照されない件は不具合っぽいですね…
直接 aspx に <% ... %> で model を抽出するコードを書くと動くので、controller から view に引き渡すところで、何かが違ってしまっているようです。