2011-11-07 69 views
3

我正在學習一段時間的ASP.NET MVC。我遵循互聯網或書籍中的一些指導原則,並且希望確保我遵循關於視圖模型模式的最新發展。以下是一個博客實施的簡單例子。你能否確認我是否正確?假設我想在視圖上顯示帖子標題+說明,並在該帖子的評論下方顯示帖子標題+說明。所以我有一個觀點,其中有2個部分觀點。遵循視圖模型模式的最佳做法

在我的控制器:

public ActionResult DetailPost(int postID) 
    { 
     // retrieve infos 
     Post postModel = repository.Posts.FirstOrDefault(p => p.PostID == postID); 
     IEnumerable<Comments> commentsModel = postModel.Comments; 

     // prepare view model 
     DetailPostViewModel detailPostViewModel = new DetailPostViewModel 
                 { 
                  Post = postModel, 
                  Comments = commentsModel, 
                 }; 

     return View(detailPostViewModel); 
    } 

所以在這裏,我perpare的兩兩件事構成的視型號:

  • 後信息
  • 註釋的枚舉。

視圖模型將被傳遞到用於以下視圖模型圖案的圖。

在我的局部視圖:

@model WebUI.ViewModels.DetailPostViewModel 

@{ 
    ViewBag.Title = "Detail"; 
} 

<h2>Detail</h2> 

@Html.Partial("_DetailPost", Model.Post) 
@Html.Partial("_Comments", Model.Comments) 

所以在這裏,我用我的DetailPostViewModel。對於我的部分觀點,我通過了實體的必要信息!?我不知道這是正確的方式,還是我必須在這裏獨家查看模型?

在我_DetailPost觀點:

@model Domain.Entities.Post 

@Html.DisplayForModel() 
... 

所以在這裏,我的局部視圖,我用連接實體模型。是好還是壞?

在我_comments查看:

@model IEnumerable<Domain.Entities.Comment> 

@foreach (var item in Model) 
{ 
    @Html.DisplayFor(Model => item.Title) 
    @Html.DisplayFor(Model => item.Username) 
} 

所以在這裏,我的局部視圖,我用連接實體模型。是好還是壞?

感謝您的建議/建議。

編輯

我試圖實現我的Automapper的幫助視圖模型的模式,但我有一些問題,如下所述。我理解將一個對象映射到另一個對象的原則。在基本情況下,它工作得很好。現在,讓我們看看更復雜的情況:我有一個由某些屬性(id,title,...)組成的帖子,每個帖子可以附加一些註釋(object),每個註釋只能附加一個用戶(object) 。我想得到一個視圖模型,包括我的所有帖子和每個帖子,獲取所有的評論,併爲每個評論得到用戶附加。

這裏是域實體:

public class Post 
{ 
    public int PostID { get; set; } 
    public string Title  { get; set; } 
    ... 
    public virtual ICollection<Comment> Comments { get; set; } 
} 

public class Comment 
{ 
    public int CommentID { get; set; } 
    public string CommentText { get; set; } 
    ... 
    public virtual <User> User { get; set; } 
} 

public class User 
{ 
    public int UserID  { get; set; } 
    public string Username { get; set; } 
    ... 
} 

這裏是視圖模型:

public class PostVM 
{ 
    public int PostID { get; set; } 
    public string Title  { get; set; } 
    ... 
    public virtual ICollection<CommentVM> CommentsVM { get; set; } 
} 

public class CommentVM 
{ 
    public int CommentID { get; set; } 
    public string CommentText { get; set; } 
    ... 
    public virtual <UserVM> UserVM { get; set; } 
} 

public class UserVM 
{ 
    public int UserID  { get; set; } 
    public string Username { get; set; } 
    ... 
} 

這裏是我的控制器:

// I would like to list all posts in the DB. 
public ViewResult Index() 
{ 
    PostVM viewModel = new PostVM 
          { 
           ... 
          } 

    return View(viewModel); 
} 

如何映射我的列表(實體)將對象發佈到我的視圖模型對象和所有子對象(註釋,用戶)?

謝謝!

+0

我沒有看到這個實現的任何問題 – Ankur

+1

@Ankur:對我來說最大的問題是關於部分視圖。我的意思是在這些視圖上使用實體是一種很好的做法嗎?或者我也必須在這些局部視圖上使用視圖模型嗎?我問這個問題,因爲規則是:**「絕不將任何域模型傳遞給視圖」**! – Bronzato

+1

我個人不同意'從來沒有將任何領域模型傳遞給視圖'作爲我,它只是一些需要由View顯示的數據結構。這些規則讓你遠離真正的問題。 – Ankur

回答

5

你近了,但對我來說這不是視圖模型的正確用法。你有以下幾點:

public class DetailPostViewModel 
{ 
    public Post Post { get; set; } 
    public IEnumerable<Comment> Comments { get; set; } 
} 

這是某種混合僞視圖模型。真實視圖模型不應該引用任何域模型。

更正確的例子是下面的:

public class DetailPostViewModel 
{ 
    public PostViewModel Post { get; set; } 
    public IEnumerable<CommentViewModel> Comments { get; set; } 
} 

其中當然PostViewModel和CommentViewModel的是爲各自的域實體對應的視圖模式。

而且不是諧音我會使用的顯示模板:

@model WebUI.ViewModels.DetailPostViewModel 

@{ 
    ViewBag.Title = "Detail"; 
} 

<h2>Detail</h2> 

@Html.DisplayFor(x => x.Post) 
@Html.DisplayFor(x => x.Comments) 

,然後你將有相應的顯示模板(~/Views/Shared/DisplayTemplates/PostViewModel.cshtml):

@model WebUI.ViewModels.PostViewModel 
... some properties of a post 

和(~/Views/Shared/DisplayTemplates/CommentViewModel.cshtml):

@model WebUI.ViewModels.CommentViewModel 
@Html.DisplayFor(x => x.Title) 
@Html.DisplayFor(x => x.Username) 

很明顯,因爲評論是一個枚舉顯示模式平板將自動呈現爲集合的每個元素。這樣你就不需要在你的視圖中編寫任何循環。

就控制器邏輯而言,我個人喜歡使用AutoMapper來映射域實體和視圖模型。

因此,它可能是這樣的:

public ActionResult DetailPost(int postID) 
{ 
    // retrieve infos 
    var postModel = repository.Posts.FirstOrDefault(p => p.PostID == postID); 

    var viewModel = new DetailPostViewModel 
    { 
     Post = Mapper.Map<Post, PostViewModel>(postModel), 
     Comments = Mapper.Map<IEnumerable<Comment>, IEnumerable<CommentViewModel>>(postModel.Comments) 
    }; 
    return View(viewModel); 
} 

甚至更​​好:

public class PostViewModel 
{ 
    ... some properties of a Post 
    public IEnumerable<CommentViewModel> Comments { get; set; } 
} 

然後:

public ActionResult DetailPost(int postID) 
{ 
    // retrieve infos 
    var postModel = repository.Posts.FirstOrDefault(p => p.PostID == postID); 
    var viewModel = Mapper.Map<Post, PostViewModel>(postModel); 
    return View(viewModel); 
} 

,然後你的觀點會被強類型到PostViewModel :

@model WebUI.ViewModels.PostViewModel 

@{ 
    ViewBag.Title = "Detail"; 
} 

<h2>Detail</h2> 

... some properties of a post 

@Html.DisplayFor(x => x.Comments) 

正如在評論部分要求在這裏是如何的域模型和視圖模型之間的映射是這樣的:

Mapper.CreateMap<User, UserVM>(); 
Mapper 
    .CreateMap<Comment, CommentVM>() 
    .ForMember(
     dest => dest.UserVM, 
     opt => opt.MapFrom(src => src.User) 
    ); 
Mapper 
    .CreateMap<Post, PostVM>() 
    .ForMember(
     dest => dest.CommentsVM, 
     opt => opt.MapFrom(src => src.Comments) 
); 

注:這兩個ForMemeber通話不會有必要的,如果屬性在視圖模型中被命名爲相同的方式:UserComments。 AutoMapper依賴於標準的命名約定,也可以編寫自己的自定義約定策略,以避免單獨映射每個成員。然後,您需要的是在定義視圖模型時保持一致並遵循約定。

,然後在控制器:

IEnumerable<Post> posts = ... 
IEnumerable<PostVm> postVms = Mapper.Map<IEnumerable<Post>, IEnumerable<PostVM>>(posts); 
return View(postVms); 
+0

謝謝。我會重構我的例子,稍後再重新提交(我現在不得不離開)以徵求意見/建議。 – Bronzato

+0

嗨,我更新了我的文章(編輯部分)試圖使用Automapper,但我有一些困難,你可以檢查它嗎? – Bronzato

+0

@Bronzato,第一個問題是:你需要在視圖中的所有屬性嗎? –

2

你使用你的域模型到你的觀點。你的視圖模型只是域模型的一個容器。

就我個人而言,我在我的視圖中使用實體或域模型沒有問題。我通常從他們開始。當域/實體模型沒有給我完全我想要的(而不是將邏輯引入到我的視圖中)時,我切換到查看模型。

沒有其他代碼依賴於您的視圖,因此可以隨時重構它們並切換模型。

相關問題