2011年04月21日

ASP.NET MVC 3とEntity Framework – Cascade Delete(カスケードデリート)

前回作ったアプリケーションではメモを削除しようとすると、コメントがある場合にエラーとなっていたので、メモの削除と同時に関連するコメントも削除するように変更したいと思います。 方法は簡単でCommentクラスに以下の二行を追加をします。
[Required]
public virtual Entry Entry { get; set; }

こうすることでCommentsテーブルからEntryiesテーブルへのリレーションがCascade Deleteの設定となり、親のメモを削除すると自動でコメントも削除するようになります。 image

posted by まーつん at 00:46| Comment(0) | TrackBack(0) | ASP.NET MVC | このブログの読者になる | 更新情報をチェックする

2011年04月11日

ASP.NET MVC 3とEntity Frameworkを使ったコードファースト開発に挑戦 (その3)

コントローラーの作成

コントローラーを作成します。ソリューション エクスプローラから Controllersフォルダを右クリックし、「追加」>「コントローラー」をクリックします。 image_thumb18_thumb
using System;
using System.Web.Mvc;
using MvcEFApp.Models;

namespace MvcEFApp.Controllers
{
    public class EntryController : Controller
    {
        public EntryController()
            : this(new EntryRepository())
        {
        }

        public EntryController(IEntryRepository entryRepository)
        {
            _entryRepository = entryRepository;
        }

        private readonly IEntryRepository _entryRepository;

        //
        // GET: /Entry/

        public ActionResult Index()
        {
            var entry = _entryRepository.GetAll();
            return View(entry);
        }

        //
        // GET: /Entry/Details/5

        public ActionResult Details(int id)
        {
            var entry = _entryRepository.Find(id);
            return View(entry);
        }

        //
        // GET: /Entry/Create

        public ActionResult Create()
        {
            return View();
        }

        //
        // POST: /Entry/Create

        [HttpPost]
        public ActionResult Create(Entry entry)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return View(entry);
                }

                entry.CreatedAt = DateTime.Now;
                _entryRepository.Add(entry);
                _entryRepository.Save();

                return RedirectToAction("Index");
            }
            catch
            {
                return View(entry);
            }
        }

        //
        // GET: /Entry/Edit/5

        public ActionResult Edit(int id)
        {
            var entry = _entryRepository.Find(id);
            return View(entry);
        }

        //
        // POST: /Entry/Edit/5

        [HttpPost]
        public ActionResult Edit(int id, FormCollection collection)
        {
            var entry = _entryRepository.Find(id);

            try
            {
                UpdateModel(entry);

                _entryRepository.Save();

                return RedirectToAction("Index");
            }
            catch
            {
                return View(entry);
            }
        }

        //
        // GET: /Entry/Delete/5

        public ActionResult Delete(int id)
        {
            var entry = _entryRepository.Find(id);
            return View(entry);
        }

        //
        // POST: /Entry/Delete/5

        [HttpPost]
        public ActionResult Delete(int id, FormCollection collection)
        {
            var entry = _entryRepository.Find(id);

            try
            {
                _entryRepository.Remove(entry);
                _entryRepository.Save();

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
    }
}
リポジトリパターンを利用しているため、最初にIEntryRepositoryインターフェイスを宣言し、パラメタなしのコンストラクタが呼ばれた時、自身のオブジェクトをEntryRepositoryクラスのパラメタ付きで再生成しています。パラメタ付きのコンストラクタで、EntryRepositoryクラスをIEntryRepositoryインターフェイスに代入して利用します。

ビューの作成

ビューを作成します。ソリューション エクスプローラから Viewsフォルダ内のEntryフォルダを右クリックし、「追加」>「表示」をクリックしそれぞれのアクションに対応したビュー作成します。

image_thumb22_thumb どのビューでも、モデルクラスにEntry (MvcEFApp.Models)を選びます。

ルーティングの設定

アプリケーションのルーティングを設定します。 今回はデフォルトでEntryコントローラーのIndexアクションをコールするように設定します。 Global.asaxのRegisterRoutesメソッド内を以下の用に変更します。

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default", // ルート名
        "{controller}/{action}/{id}", // パラメーター付きの URL
        new { controller = "Entry", action = "Index", id = UrlParameter.Optional } // パラメーターの既定値
    );

}
F5キーを押してアプリケーションを起動してみます。 ここまででEntryに関しては表示とCRUDができるようになりました。

コメントの実装

コメントを入力できるようにコントローラーと、メモの詳細ページでコメントを入力できるように部分ビューを作成します。 image_thumb24_thumb

namespace MvcEFApp.Controllers
{
    public class CommentController : Controller
    {
        private readonly IEntryRepository _entryRepository;

        public CommentController()
            : this(new EntryRepository())
        {
        }

        public CommentController(IEntryRepository entryRepository)
        {
            _entryRepository = entryRepository;
        }

        //
        // GET: /Comment/Create
        [ChildActionOnly]
        public ActionResult Create()
        {
            return PartialView();
        } 

        //
        // POST: /Comment/Create

        [HttpPost]
        public ActionResult Create(int id, Comment comment)
        {
            try
            {
                var entry = _entryRepository.Find(id);

                comment.CreatedAt = DateTime.Now;

                entry.Comments.Add(comment);

                _entryRepository.Save();

                return RedirectToAction("Details", "Entry", new { id = id });
            }
            catch
            {
                return RedirectToAction("Details", "Entry", new { id = id });
            }
        }
        
    }
}

GETで呼ばれるCreateアクションにChildActionOnly属性を付けています。これによりURL指定でアクセスされた時にビューを返さなくなります。 またreturnに利用するメソッドをPartialViewメソッドに変更しています。

Postで呼ばれるCreateアクションにはidパラメータを追加しました。このidで対象のメモを取得してCommentsに追加しています。

コメントはCreateアクションだけを実装するので、その他のアクションを削除しています。

コメント登録用に部分ビューを作成します。image_thumb26_thumb 「部分ビューとして作成する」にチェックを入れます。

@using (Html.BeginForm("Create","Comment")) {
    @Html.ValidationSummary(true)
     Comment 
@Html.LabelFor(model => model.NickName)
@Html.EditorFor(model => model.NickName) @Html.ValidationMessageFor(model => model.NickName)
@Html.LabelFor(model => model.Body)
@Html.EditorFor(model => model.Body) @Html.ValidationMessageFor(model => model.Body)
  }
部分ビューからのサブミットになるため、Html.BeginForm()をHtml.BeginForm("Create","Comment")に変更します。 Detailsビューにコメントを表示します。
@model MvcEFApp.Models.Entry

@{
    ViewBag.Title = "Details";
}

Details

Entry
Title
@Model.Title
Body
@*改行するように変更*@
@Html.Raw(Model.Body.Replace("\n", "<br/>"))
CreatedAt
@String.Format("{0:g}", Model.CreatedAt)
@*コメントを表示する*@

コメント

@foreach (var comment in Model.Comments) {
@comment.NickName (@comment.CreatedAt.ToString("g"))
@Html.Raw(@comment.Body.Replace("\n", " "))
}
@Html.Action("Create", "Comment")

@Html.ActionLink("Edit", "Edit", new { id=Model.EntryId }) | @Html.ActionLink("Back to List", "Index")

Html.Actionメソッドを利用し、コメント入力の表示を追加します。 @Html.Action("Create", "Comment")

ここまでで、メモにコメントの表示と入力ができるようになり、アプリケーションが完成しました。

自動生成されたテーブルの確認

最後にサーバーエクスプローラーからテーブルを見てみましょう。 Entriesテーブル image_thumb33_thumb Commentsテーブル image_thumb31_thumb 期待した通り、プライマリーキー、文字列の長さ、CommentsテーブルにEntriesテーブルへのリレーションなどが自動でできていることがわかります。

タグ:ASP.NET MVC
posted by まーつん at 00:53| Comment(1) | TrackBack(0) | ASP.NET MVC | このブログの読者になる | 更新情報をチェックする

2011年04月10日

ASP.NET MVC 3とEntity Frameworkを使ったコードファースト開発に挑戦 (その2)

モデルクラスの作成

ソリューション エクスプローラから Modelsフォルダを右クリックし、「追加」>「クラス」をクリックします。 メモ用のモデルクラスを作成するので、ファイル名にEntryと入力して「OK」をクリックします。

namespace MvcEFApp.Models
{
    public class Entry
    {
        public int EntryId { get; set; }

        [Required]
        [StringLength(64)]
        [DisplayName("タイトル")]
        public string Title { get; set; }

        [Required]
        [DisplayName("本文")]
        [StringLength(2048)]
        public string Body { get; set; }

        public DateTime CreatedAt { get; set; }

        public virtual ICollection<Comment> Comments { get; set; }

    }
}
同様の手順でコメント用のCommentクラスを作成します。
namespace MvcEFApp.Models
{
    public class Comment
    {
        public int CommentId { get; set; }

        [Required]
        [StringLength(64)]
        [DisplayName("ニックネーム")]
        public string NickName { get; set; }

        [Required]
        [StringLength(1024)]
        [DisplayName("コメント")]
        public string Body { get; set; }

        public DateTime CreatedAt { get; set; }
    }
}

次にこれらのクラスを使うためにデータコンテキストを作ります。DbContextを継承してMvcEFAppContextクラスを作ります。 データコンテキストクラスには DbSet<T> 型のプロパティを利用します。

namespace MvcEFApp.Models
{
    public class MvcEFAppContext : DbContext
    {
        public DbSet Entrys<Entry> { get; set; }
        public DbSet Comments<Comment> { get; set; }
    }
}
Web.configのconnectionStringsにデータベースファイルの接続文字列を以下のように指定します。
<connectionStrings>
    <add name="MvcEFAppContext"
         connectionString="Data Source=|DataDirectory|MvcEFApp.sdf"
         providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>
DBの自動生成を行うためにGlobal.asax.csのApplication_StartメソッドにDbDatabase.SetInitializer<T>メソッドを設定します。
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            //モデルクラスに変更があった時にテーブルを自動で再作成する
            Database.SetInitializer<MvcEFAppContext>(new DropCreateDatabaseIfModelChanges<MvcEFAppContext>());
        }
ここまででDBを自動生成する準備が整いました。

リポジトリ パターンの適用

リポジトリ パターンを使用して、データ アクセス コードをアプリケーションのそれ以外の部分と分離します。 リポジトリパターンの説明は以下のページがわかりやすいので目を通すと良いでしょう。

  • ASP.NET MVCの開発応用編1 〜リポジトリパターンをマスターする〜
  • [C#] #36. フェーズ #4 - アプリケーションの疎結合化
    •  
      • 1.インターフェイスを作成する
      • 2.インターフェイスを実装する具体的なクラスを作成する
    • リポジトリ パターンを実装するには、次の 2 つの手順を完了する必要があります。

        IEntryRepositoryインターフェースを作成します。image_thumb[17]
      namespace MvcEFApp.Models
      {
          public interface IEntryRepository
          {
              Entry Find(int id);
              IList<Entry> GetAll();
              void Add(Entry entry);
              void Remove(Entry entry);
              void Save();
          }
      }
      
      次にインターフェイスを実装したEntryRepositoryクラスを作成します。
      namespace MvcEFApp.Models
      {
          public class EntryRepository : IEntryRepository
          {
              private readonly MvcEFAppContext _context = new MvcEFAppContext();
      
              public Entry Find(int id)
              {
                  return _context.Entrys.Find(id);
              }
      
              public IList GetAll()
              {
                  return _context.Entrys.ToList();
      
              }
      
              public void Add(Entry entry)
              {
                  _context.Entrys.Add(entry);
              }
      
              public void Remove(Entry entry)
              {
                  _context.Entrys.Remove(entry);
              }
      
              public void Save()
              {
                  _context.SaveChanges();
              }
          }
      }
タグ:ASP.NET MVC
posted by まーつん at 23:03| Comment(1) | TrackBack(0) | ASP.NET MVC | このブログの読者になる | 更新情報をチェックする
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。