2014-09-10 5 views
1

아래 그림에서 볼 수있는 모델에 관한 한 가지 질문이 있습니다.asp.net mvc보기에서 모델을 생성/편집하는 방법 5

enter image description here

당신은 내가 3 엔티티와 1을 가지고 볼 수 있듯이 : n과 m : n은 그들 사이의 관계.

웹 인터페이스를 통해 이러한 모델을 편집 할 수 있기를 바랍니다. 따라서이 세 모델을 스캐 폴딩 (엔티티 프레임 워크가있는 컨트롤러 추가)하고 각 엔티티 당 하나의 컨트롤러 인 edit/delete/create/ 뷰를 얻었습니다.

하지만 VS에 의해 자동으로 관계에 대해 생성 된 입력/입력란이 없습니다. 그래서 저는 그것들을 수동으로 구현하려고 생각했습니다. 이전에이 모델을 구현/스캐 폴딩하는 간단한 방법이 있기 때문에 관계를 편집 할 수도 있습니다 (확인란 또는 (다중) 선택이 가장 좋음). 미리 감사드립니다.

+0

+1 : 당신은 다중 선택을 가능하게 ListBoxFor 대신 DropDownListFor을 사용하십시오 soldev/archive/2013/09/20/managing-entity-relationships-with-mvc-scaffolding.aspx – InferOn

답변

0

한 많은 당신이 파트너보기에 팁에 대한 DropDownList로 사용할 수 있습니다 (Scott Allen's solution를 참조하십시오. 많은-많은 마네처럼 ViewModels와 자바 스크립트 프레임 워크에 의해 처리 할 수 ​​있습니다.

0

가 아니, 비계가 의도적으로 여기 unopinionated하는 경우, 아마도 당신은 선택 목록에서 선택하기를 원할 것입니다. 아마도 체크 박스를 원할까요? 아니면 실제로 관련 항목을 인라인으로 추가/편집하고 싶습니까? 그리고 마지막으로, 한 번에 모두 올리거나 AJAX를 사용하고 싶으십니까?

따라서, 프레임 워크는 결정을 내리지 않습니다. 에 설치해야합니다. 그럼에도 불구하고 발판에 의존하는 것이 더 자주 당신을 물게 될 것입니다. 이들은 가장 기본적이고 이상적인 시나리오에서만 작동하며 응용 프로그램 요구 사항이 기본 적이거나 이상적인 경우는 언제입니까? 이 시점에서 나는 컨트롤러와 뷰를 수동으로 생성하는 것을 선호하지만, 지금은 그다지 신경 쓰지 않습니다. 그것은 발판을 다루는 것보다 더 빨리 끝나고 모든 것을 적용 취소합니다.

그래서 선택 상자 (단일 선택 또는 다중 선택)를 찾고 있기 때문에 먼저 엔티티에 대한보기 모델을 만드는 것이 좋습니다. 예를 들어, Tip과 : 여기

public class TipViewModel 
{ 
    [Required] 
    public string Name { get; set; } 

    [Required] 
    [DataType(DataType.MultilineText)] 
    public string Description { get; set; } 

    [Required] 
    public int? SelectedPartnerId { get; set; } 
    public IEnumerable<SelectListItem> PartnerChoices { get; set;} 

    [Required] 
    public int? SelectedBookId { get; set; } 
    public IEnumerable<SelectListItem> BookChoices { get; set; } 
} 

, 나는 Book 선택의 ID를 추적하는 속성 (대신 첫 번째 옵션 설정에, 그들이 초기 상태로 선택 될 수있는 널 (NULL)을 사용하여) 널 (NULL) INT를 추가했습니다/Partner 엔티티에 외래 키에 대한 명시 적 속성이 표시되지 않기 때문에 괜찮습니다.하지만 약간의 차이가 있습니다. 관계를 저장하는 것이 약간 더 복잡하지는 않습니다. 명시 적 외래 키 특성이있는 경우에는보기 모델의 특성을 대신 미러링해야합니다. 나는이 선택 목록을 채우는 코드를 추상화 한

public ActionResult Create() 
{ 
    var model = new TipViewModel(); 

    PopulateChoices(model); 

    return View(model); 
} 

... 

protected void PopulateChoices(TipViewModel model) 
{ 
    model.PartnerChoices = db.Partners.Select(m => new SelectListItem 
    { 
     Value = m.Id.ToString(), 
     Text = m.Name 
    }); 
    model.BookChoices = db.Books.Select(m => new SelectListItem 
    { 
     Value = m.Id.ToString(), 
     Text = string.Format("{0} by {1}", m.Name, m.Author) 
    }); 
} 

코드가 사용되므로 여러 : 액션의 GET 버전 이제

, 다음과 같은 일을해야합니다 귀하의 컨트롤러 전체에서. 또한 string.FormatText 값으로 사용하여 선택 목록 항목의 텍스트를 원하는대로 지정할 수 있음을 보여줍니다. 또한, 위의 코드는 분명히 create 액션을위한 것입니다.편집을하는 것은 비슷하지만 약간 다른 것 :

public ActionResult Edit(int id) 
{ 
    var tip = db.Tips.Find(id); 
    if (tip == null) 
    { 
     return new HttpNotFoundResult(); 
    } 

    var model = new TipViewModel 
    { 
     Name = tip.Name, 
     Description = tip.Description, 
     SelectedPartnerId = tip.Partner != null ? tip.Partner.Id : new int?(), 
     SelectedBookId = tip.Book != null ? tip.Book.Id : new int?() 
    } 

    PopulateChoices(model); 

    return View(model); 
} 

가장 큰 차이점은 데이터베이스에서 당겨 필요가 그래서 당신은 분명 기존 인스턴스 상대하고 있다는 점이다. 그런 다음 엔티티의 데이터를 뷰 모델에 매핑하면됩니다. 다시 한번 명시 적 외래 키 특성이 없기 때문에 현재 선택된 Partner/Book 값을 얻으려면 약간의 다리 작업을해야합니다. 그렇지 않으면 외래 키 특성 값을 직접 복사 할 수 있습니다. 또한 여기서는 수동 매핑 만하고 있지만 타사 라이브러리를 사용하면이 작업을 더 쉽게 수행 할 수 있습니다 (AutoMapper 참조).

이렇게하면보기를 구현할 수 있습니다. 엔티티를 직접 사용할 때와 똑같이 모든 것이 작동 할 것이므로 몇 가지 수정 만하면됩니다. 첫째, 당신은 당신의 뷰의 모델 선언을 변경해야합니다 :

@model Namespace.To.TipViewModel 

그런 다음 두 개의 관련 속성에 대한 선택 목록을 추가 :

@Html.DropDownListFor(m => m.SelectedPartnerId, Model.PartnerChoices) 

... 

@Html.DropDownListFor(m => m.SelectedBookId, Model.BookChoices) 

재미는 당신의 행동의 POST 버전에서 발생합니다. 대부분의 코드는 GET 버전에서 동일하게 유지되지만, 이제 당신은 if (ModelState.IsValid) 블록을해야합니다 :

[HttpPost] 
public ActionResult Create(TipViewModel model) 
{ 
    if (ModelState.IsValid) 
    { 
     // map the data from model to your entity 
     var tip = new Tip 
     { 
      Name = model.Name, 
      Description = model.Description, 
      Partner = db.Partners.Find(model.SelectedPartnerId), 
      Book = db.Books.Find(model.SelectedBookId) 
     } 

     db.Tips.Add(tip); 
     db.SaveChanges(); 

     return RedirectToAction("Index"); 
    } 

    // Form has errors, repopulate choices and redisplay form 

    PopulateChoices(model); 

    return View(model); 
} 

편집 버전, 다시, 당신은 기존 인스턴스에 매핑하는거야 제외하고 유사하다 예 :

tip.Name = model.Name; 
tip.Description = model.Description; 
tip.Partner = db.Partners.Find(model.SelectedPartnerId); 
tip.Book = db.Books.Find(model.SelectedBookId); 

참조 용으로 모든 것이 있습니다. 귀하의 질문에 귀하의 사업체에 실제로 M2M 또는 일대 다 (one-to-many) 물건이없는 것은 아닙니다. 모든 것이 일대일이지만 컬렉션 속성이 있다면 약간 다르게 처리해야합니다. 선택한 값과 사용 가능한 선택 항목을 유지하려면 뷰 모델의 속성이 필요합니다.

public List<int> SelectedFooIds { get; set; } 
public IEnumerable<SelectListItem> FooChoices { get; set; } 

선택 항목 채우기도 동일합니다. 옵션은 옵션입니다. 당신이 한두 가지만 선택한다면 그것은 중요하지 않습니다.

var tip = new Tip 
{ 
    ... 
    Foos = db.Foos.Where(m => model.SelectedFooIds.Contains(m.Id)), 
} 

: 데이터베이스에서 선택한 모든 항목을 선택하고 그에게 엔터티 컬렉션 속성을 설정해야 할 것로 만드는 작업에 개체 위에

매핑하지만 다른 것 그리고 편집 작업의 GET 및 POST 버전을 모두 변경해야합니다.

var model = new TipViewModel 
{ 
    ... 
    SelectedFooIds = tip.Foos.Select(m => m.Id).ToList(), 
} 

을 그리고 편집 버전, 새로운 선택한 항목을 설정하십시오 GET를 들어, ID 목록에 컬렉션 속성을 응축 할 필요가

마지막으로
tip.Foos = db.Foos.Where(m => model.SelectedFooIds.Contains(m.Id); 

, 귀하의 의견에, downvote 부정 http://blogs.msdn.com/b/mcsuk -

@Html.ListBoxFor(m => m.SelectedFooIds, Model.FooChoices)