2016-06-01 2 views
2

그래서 현재 ViewModels의 사용을 연구하고 분석 중입니다.MVC 5 : ViewModel/생성 용 전달 목록

내 응용 프로그램 (소위 "레스토랑")에서 "사용자"가 메뉴를 만들 수있는 기능이 필요합니다.

메뉴를 만들 때 : 이름을 선택하고 메뉴에 참여할 수있는 사람의 수를 선택할 수 있습니다. 그러나 식당에 이미있는 양의 요리를 추가 할 수도 있습니다. 이것은 체크 박스의 스타일과 끝에 'Create'버튼이 될 것입니다.

이것은 ViewModel을 사용해야한다는 것을 의미합니다. 저는 현재 요리의 메뉴를 창조 메뉴에 추가 할 수있는 가능성을 주려고합니다. 하지만 나는 for 루프에 갇혀 있고, 요리를 반복하는 데 사용됩니다. 또는 더 나은, 나는 전체 개념에 붙어있어 :

  • 이미 만든 모든 요리를 CreateMenu보기에 표시하는 가장 좋은 방법은 무엇입니까? ViewBag에 추가 할 경우 ViewBag을 통해 반복 할 수 있습니까?

  • 제가하고 싶은 일을 성공적으로 해보려고합니다. ViewModel을 기반으로 새 메뉴를 만들거나 추출 할 수 있습니까? 나는 이미 그것에서 요리의 목록을 사용하기 때문에 모델 (나는 모든 메뉴의 자신의 요리를 표시 다른보기에서) 정말 변경할 수 없습니다 - 내 코드에서

에서 메뉴가 있음을 유의하시기 바랍니다.

또한 내가 플랑드르에서 모든 것을 번역 때문에

모델

public class Menu 
{ 
    [Key] 
    public int Id { get; set; } 
    [Required] 
    public string Name { get; set; } 
    [Range(0,10)] 
    public int AmountPersons { get; set; } 
    [Range(0,double.MaxValue)] 
    public double Price { get; set; } 
    public virtual List<Dish> Dishes { get; set; } 
} 

public class Dish 
{ 
    [Required] 
    public int Id { get; set; } 
    [Required] 
    public string Name { get; set; } 
    public enum Types { VOORGERECHT, HOOFDGERECHT, DRANK, DESSERT} 
    public Types Type { get; set; } 
    public double Price { get; set; } 
    public virtual List<Menu> Menus { get; set; } 
    public virtual List<Table> Tables { get; set; } 
    //Checked used for the 'checkbox' in the CreateMenu-View 
    [NotMapped] 
    public bool Checked { get; set; } 
} 

public class MenuViewModel 
{ 
    public Menu Menu { get; set; } 
    public List<Dish> AddedDishes { get; set; } 
} 

컨트롤러

public ActionResult CreateMenu() 
{ 
    MenuViewModel gm = new MenuViewModel(); 
    // Assign ALL already created dishes to the list that the user can choose. 
    // AddedDishes is wrong? ViewBag preferred? 
    gm.AddedDishes = db.Dishes.ToList(); 
    return View(gm); 
} 

// Add the Menu to all the Menu's in the Database. 
[HttpPost] 
public ActionResult MenuAanmaken(MenuModel gm) 
{ 
    // code to save the menu with all the added dishes to the database 
    // Conflict!? Cannot convert the MenuViewModel to the Menu-model How do we need to extract the Menu and the AddedDishes list 
    // to a menu and save that one to the database? 
    db.Menus.Add(gm); 
    return View(gm); 
} 

보기

,321, 잘못된 이름이나 데이터 맞춤법 오류의 가능성을 무시

public class MenuViewModel<T> 
{ 
    public Menu Menu { get; set; } 
    public List<T> DishList { get; set; } 
    public MenuViewModel() 
    { 
     this.Lijst = new List<T>(); 
    } 
} 

컨트롤러

public ActionResult CreateMenu(MenuViewModel<Dish> model) 
{ 
    model.DishList = db.Gerechten.ToList(); 
    return View(model); 
} 

[HttpPost] 
public ActionResult CreateMenu(MenuViewModel<Dish> model,List<Gerecht> SelectedList) 
{ 
    Menu t = new Menu(); 
    t.Naam = gm.Menu.Naam; 
    t.AmountPersons = gm.Menu.AmountPersons; 
    t.Dishes = SelectedList; 
    db.Menus.Add(t); 
    return View("Menus", model); 
} 
: 0

,

편집이 _ UPDATE 좋아 (아래 참조) 그래서 내가 지금 가까운 것 같아 나는 다음과 같은 내 수업을 편집

리스트 작성 기능보기

@for (int i = 0; i < Model.DishList.Count(); i++) 
{ 
    <tr> 
     <td> 
      @Html.Label(Model.DishList[i].Naam) 
      <input type="hidden" [email protected]("DishList[{0}].Id", i) [email protected](i).Id /> 
      <input type="hidden" [email protected]("DishList[{0}].Name", i) [email protected](i).Name /> 
      <input type="checkbox" [email protected]("DishList[{0}].value", i) /> 
      <input type="hidden" [email protected]("DishList[{0}].value", i) value="false" /> 
     </td> 
     <br /> 
    </tr> 
} 

ViewModels에 대한 약 10 개의 자습서를보고 난 후에이 작업을 수행했는데, 다음 방법은 처음 것보다 낫습니다. 나는 다음 접근 방식 일 것입니다 무슨 생각

enter image description here

: 내가 내 화면에서 다음을 얻을 수 있기 때문에

나는 그렇게 생각.나는 2 개의리스트 (viewmodel 중 1 개, 통과 된 1)를 비교하고 체크 박스 상태를 보려고 생각하고 있었습니까?

UPDATE 내 코드를 재 편집하지만 난 이해할 수가 없어 문제가 발견 스티븐 뮈크의 대답 후

. 당신이 만드는 경우, 그러나

// You have not indicated the 1-many table the dishes are saved to so adjust as required 
     MenuDish dish = new MenuDish() 
     { 
      MenuId = menu.ID, 
      DishId = dish 
     }; 
     db.MenuDishes.Add(dish); 

이었다 우리가 학교에서 배운 내용 :

대답은 내가 클래스와 형태의 1 일대 테이블의 위치에 있어야합니다 말한다 엔티티의 데이터 모델에 나열하면 연결된 테이블이 데이터베이스에 자동으로 생성됩니다. 그리고 그게 내 DB가 (MenuDish 클래스를 만들지 않고) 한 것입니다 :

MenuGerechts은 MenuDish를 의미합니다. 이것은 엔티티 프레임 워크가 자동으로 작성한 테이블입니다. enter image description here 다음 질문에 대한 답입니다.

[HttpPost] 
     public ActionResult MenuAanmaken(MenuVM model) 
     { 
      if (!ModelState.IsValid) 
      { 
       return View(model); 
      } 

      IEnumerable<int> selectedDishes = model.Dishes.Where(x => x.IsSelected).Select(x => x.ID); 
      Menu menu = new Menu() 
      { 
       Naam = model.Name, 
       AantalPersonen = model.AmountPersons 
      }; 

      foreach (int id in selectedDishes) 
       { 
        Dish g = db.Dishes.Find(id); 
        menu.Dishes.Add(g); 

       }; 

      db.Menus.Add(menu); 
      db.SaveChanges(); 

      return RedirectToAction("Menus", "Menu"); 
     } 

내가 Object reference not set to an instance of an object 오류가 나는 이유는 당연히 이해 해요 : 나는 다음에 컨트롤러를 다시 편집했습니다.

나는 Data-Model Menu 이후 이미 변경된 목록을 가지고있다. 이미 List of Dishes가있다. 그러나 S. Muecke의 대답을 가정 할 때, 이것은 New Class (일대 다 관계를 지원하기 위해 생성 된)의 사용을 제안하기 때문에 ViewModel을 푸는 올바른 방법이 아닙니다.

  • 가 왜 불가능 여부를 권장 직접 메뉴 인스턴스에 선택한 요리를 추가하는 것입니다

    이것은 다음과 같은 질문의 결론에 저를 가져온다?

  • 데이터 모델에서 'MenuDish'테이블 사이에 항상 생성해야합니까?

  • 다음 코드는 여전히 작동하는 새로운 메뉴의 생성 후 (보여주는 메뉴의 그들의 요리)?

컨트롤러 :

public ActionResult Menus() 
      { 
       List<Menu> menus = db.Menus.ToList(); 
       return View(menus); 
      } 

보기 :

@model IEnumerable<VBExamen.Models.Menu> 

@{ 
    ViewBag.Title = "Menus"; 
} 

<h2>Menus</h2> 

<p> 
    @Html.ActionLink("Create New Menu", "CreateMenu") 
</p> 

@foreach (var item in Model) 
{ 
    <table> 


     <ul> 
      <p>@Html.DisplayFor(modelItem => item.Name)</p> 

      @foreach (var g in item.Dishes) 
      { 
       <li> 
        @Html.DisplayFor(modelItem => g.Name) 
       </li> 
      } 
     </ul> 
    </table> 
} 
다음 출력:

enter image description here

이 작업을 수행하는 좋은 동기는 무엇일까요?

UPDATE 2

그래서 나는 내 프로젝트에서 다음을 포함했다 : - 그것은 이미 만들어지는 한 **

  • 를 사용하기 위해 주석 는 ** 나는 Table()을 사용했다 ** 모델 : **

    표 ("MenuGerechts")] 공용 클래스 MenuGerechts { [Key] [ForeignKey ("Menu")] public virtual int? MenuId {get; 세트; } public 가상 메뉴 메뉴 {get; 세트; }

    [ForeignKey("Dish")] 
        public virtual int? DishId { get; set; } 
        public virtual Dish Dish { get; set; } 
    } 
    

은 그때 실제로 성공적으로 새로운 메뉴를 만들었습니다! 그러나 위의 그림에서 개요 메뉴 페이지로 이동하면 메뉴에 포함 된 식사 목록이 아닌 메뉴 이름 만 표시됩니다.

그러나 Database는 내 새로 만든 클래스에 MenuDish 링크 테이블을 사용하도록 허용하지 않았습니다. 새 메뉴를 만들었고 새 메뉴를 만든 다음 'old'메뉴를 사용하여 이전 메뉴의 이름을 '1'로 바꿉니다.

enter image description here

는 따라서 내가 왜 내 이전 질문을했다이이 운동에 내 모든 접근 방식을 뜻이었다 잘못

새로운 질문 :.? 내가 한 접시를 선택하는 경우 내 menuCreate 뷰 모델에만 작동? 왜 이렇게됩니까? llowing 오류가 The role 'MenuGerechts_Menu_Source' of the relationship 'VBExamen.Models.MenuGerechts_Menu' has multiplicity 1 or 0..1.

+0

첫 번째로 이해해야 할 것은 뷰 모델이란 무엇입니까? (http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc)/뷰 모델에는 데이터 모델입니다. 'MenuViewModel'에는보기에 표시하고자하는'Menu'의 2 가지 속성과'DistViewModel'에'DishViewModel' 속성이 포함될 필요가있는'IList '속성이 있어야합니다. 여기에는 접시 ID, 이름 및 'bool' IsSelected '재산. –

+0

답장을 보내 주셔서 감사합니다. Stephen,하지만 당신은'Menu'가 ViewModel에서 2 개의 속성을 필요로한다고 언급 했습니까? 'Menu '의 새로운 대상만으로 충분하지 않은가? 그리고 ViewModel은 다른 것과 상호 작용하는 것이 일반적입니까? 아니면 여기서 본 예나 인터넷에서 본 것을 많이 보지 못했기 때문에 이것은 단지 예외입니다. ** 마지막 질문. 당신은 뷰 모델은 데이터 모델이라는 속성을 결코 포함해서는 안되지만 새로운'Menu'에 추가 할 수있는 (데이터베이스로부터) 모든 요리를 보여줄 필요가 있기 때문에 제 경우에는 의무 사항이 아닙니다. 창조? –

+0

[이 답변] (http://stackoverflow.com/questions/29542107/pass-list-of-checkboxes-into-view-and-pull-out-ienumerable/29554416#29554416)에서 뷰 모델, 컨트롤러 코드 및 뷰의 기본 구조. –

답변

2

먼저보기 모델에는 데이터 모델 인 속성을 포함하면 안됩니다. 보기에 표시/편집하는 속성 만 포함해야하며 What is ViewModel in MVC?을 읽는 것이 좋습니다. 당신이 보여 양식의 이미지에 본사를 둔

, 뷰 모델은

public ActionResult CreateMenu() 
{ 
    // Get all the dishes from the database 
    var dishes = db.Dishes; // modify to suit 
    // Initialize the view model 
    var model = new MenuVM() 
    { 
     Dishes = dishes.Select(x => new DishVM() 
     { 
      ID = x.Id, 
      Name = x.Name 
     }).ToList() 
    }; 
    return View(model); 
} 

다음 (생략 표시 및 검증 특성)

public class MenuVM 
{ 
    public int? ID { get; set; } // included so this can be used for editing as well as creating 
    public string Name { get; set; } 
    public int AmountPersons { get; set; } 
    public List<DishVM> Dishes { get; set; } 
} 
public class DishVM 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public bool IsSelected { get; set; } 
} 

및 컨트롤러 GET 방법이 될 필요가있다 보기에서 (LabelFor()ValidationFor()은 간단히하기 위해 생략되었습니다)

@model MenuVM 
@using (Html.BeginForm()) 
{ 
    @Html.TextBoxFor(m => m.Name) 
    @Html.TextBoxFor(m => m.AmountPersons) 
    for(int i = 0; i < Model.Dishes.Count; i++) 
    { 
     <div> 
      @Html.HiddenFor(m => m.Dishes[i].ID) 
      @Html.HiddenFor(m => m.Dishes[i].Name) 
      @Html.CheckBoxFor(m => m.Dishes[i].IsSelected) 
      @Html.LabelFor(m => m.Dishes[i].IsSelected, Model.Dishes[i].Name) 
     </div> 
    } 
    <input type="submit" value="Create" /> 
} 
,210

그리고 마지막으로 POST 방법은

public ActionResult CreateMenu(MenuVM model) 
{ 
    if (!ModelState.IsValid) 
    { 
     return View(model); 
    } 
    // Initialize and save the Menu 
    Menu menu = new Menu() 
    { 
     Name = model.Name, 
     AmountPersons = model.AmountPersons 
    }; 
    db.Menus.Add(menu); 
    db.SaveChanges(); // you now have the ID of the new menu 
    // Save the dishes associated with the menu 
    IEnumerable<int> selectedDishes = model.Dishes.Where(x => x.IsSelected).Select(x => x.ID); 
    foreach(int id in selectedDishes) 
    { 
     // You have not indicated the 1-many table the dishes are saved to so adjust as required 
     MenuDish dish = new MenuDish() 
     { 
      MenuId = menu.ID, 
      DishId = dish 
     }; 
     db.MenuDishes.Add(dish); 
    } 
    db.SaveChanges(); // save the selected dishes 
    return RedirectToAction(...); // redirect somewhere 
} 

사이드 참고가 될 것입니다 : 데이터 모델에서 [NotMapped] public bool Checked { get; set; } 속성을 제거합니다.

+0

답변 주셔서 감사합니다 스티븐! 내 질문을 다시 편집했습니다. 이 주제에 대해 더 많은 설명을 듣기를 희망합니다. –

+1

@KahnKah, SO는 포럼이나 토론 사이트가 아닙니다. 한 번에 한 가지 질문 만하고 다른 질문이 있으면 다른 질문을하십시오 (시간이 지남에 따라 투표를 유도하므로 편집을 롤백하는 것이 좋습니다). –

+0

답변이 늦어서 죄송 합니다만 시험에서받은 성적을 받았고 ASP.NET 시험을 통과했습니다. 프로그래밍 언어의 어려운 측면을 배우는 데 실제로 도움을 주신 이후로 100,000 번 감사드립니다. 시험 중에 불안했지만 코드를 분석하는 긴 밤을 보냈습니다! 다시 한 번 감사드립니다! –

2

첫 번째 질문이있는 경우에만 대답은 ... 나는 일을 :) 난 강력하게 당신이 데이터 컨텍스트를 만들고,이 정보를 저장하는 엔티티 프레임 워크를 사용하는 조언

을 다시 가봐야 겠어 Initializer (Entity Framework Requirements) 및 View Model을 사용하면 컨트롤러 및 뷰를 포함하여 프로젝트의 모든 것을 비계 할 수 있습니다. 이는 뷰 백이 아닌 ViewModel 클래스에서 정보를 가져 오는 것을 의미합니다.

스캐 폴딩은 Visual Studio에서 CRUD (생성, 읽기, 업데이트, 삭제) 컨트롤러 및 뷰에 대한 모든 코드를 생성하여이를 허용 할 수 있음을 의미합니다. 격렬한 타이핑으로 45 분이나 벽에 머리를 두드리는 시간에서 벗어나십시오.

그래서 먼저 우리는 DbContext (엔티티 프레임 워크의 일부)에서 상속 우리 자신의 상황에 맞는 클래스를 만들고,이 작업을 수행 할 수 있습니다 : 여기에서 언급 된 기본은 연결의 당신의 web.config 파일의 이름을 지정

public class MenuContext : DbContext { 

    public MenuContext() : base("MenuContext") { 

} 

우리가 잠시 설정할 문자열. 또는 이름 대신 연결 문자열을 지정할 수 있습니다.

public DbSet<MenuViewModel> Menus { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 

    } 

} 

데이터베이스가 연결 문자열 위치에없는 경우 다음에 설정할 Initializer 클래스가 데이터베이스를 채 웁니다.

class MenuInitializer : CreateDatabaseIfNotExists<MenuContext> { 

    protected override void Seed(MenuContext context) { 

     // This sets up your database to populate with whatever you type into this method. 
    } 
} 

이제 솔루션 탐색기로 이동하여 컨트롤러 폴더를 마우스 오른쪽 단추로 클릭하고 추가 - 컨트롤러를 클릭하십시오. 그런 다음 Entity Framework를 사용하여 뷰가있는 MVC 5 컨트롤러를 지정합니다. 클릭 - 추가.

대화 상자가 표시되고 뷰 모델을 지정하고 컨텍스트 클래스를 설정 한 다음 "뷰 생성"이 선택되어 있는지 확인하고 컨트롤러와 BAM의 이름을 지정하십시오! 프로젝트를 빌드하고 자동으로 생성 된 모든 것을보십시오!

+0

대단히 감사합니다. 너 대답 해. 그러나 Entity Framework Object가 생성되기 위해 Key (기본 키)가 필요하지는 않습니까? ViewModels와 Entity Framework는 서로 관련이 없다고 생각했습니다. –

+0

그들은 서로 관련이 없지만 Entity 프레임 워크는 이미 뷰 모델에있는 데이터 주석을 사용하여 데이터 형식이 데이터베이스에 어떤 것인지를 결정합니다. –

+0

흠 좋아, 그럼 내가 너의 대답 접근 방식으로 약간 연주하려고 노력할 것 같아. 다시 한 번 감사드립니다! –