동일한 페이지의 ASP.NET MVC 모델 바인딩 관련 엔티티
-
16-09-2019 - |
문제
이 문제는 지금 몇 시간 동안 나를 미치게 만들었습니다 ...
내 도메인에는 서로 관련이있는 2 개의 엔티티가 있습니다. Sku
그리고 Item
. 각 SKU에는 많은 항목이있을 수 있습니다.
public class Sku
{
private readonly EntitySet<Item> items;
public Sku()
{
items = new EntitySet<Item>(AttachItems, DetachItems);
}
public int SkuId { get; set; }
public string LongDescription { get; set; }
public EntitySet<Item> Items
{
get { return items; }
set{ items.Assign(value);}
}
private void AttachItems(Item entity)
{
entity.Sku = this;
}
private static void DetachItems(Item entity)
{
entity.Sku = null;
}
}
public class Item
{
public Sku Sku { get; set; }
public int ItemId { get; set; }
public string Category { get; set; }
public string Description { get; set; }
}
최종 사용자가 SKU의 일부 필드와 각 항목의 일부 필드를 동시에 업데이트 할 수있는 페이지를 작성하고 있습니다.
<% using (Html.BeginForm("Save", "Merchant", FormMethod.Post,
new { enctype = "multipart/form-data" })) { %>
<fieldset>
<legend>Sku</legend>
<p><label for="SkuId">SkuId:</label>
<%= Html.TextBox("SkuId", Model.SkuId,
new{@readonly="readonly",onfocus="this.blur();"}) %></p>
<p><label for="LongDescription">LongDescription:</label>
<%= Html.TextBox("LongDescription", Model.LongDescription) %></p>
</fieldset>
<% for (int i = 0; i < Model.Items.Count; i++) { %>
<fieldset>
<legend>Item</legend>
<p><label for="ItemId">ItemId:</label>
<%= Html.TextBox(string.Format("items[{0}].{1}", i, "ItemId"),
Model.Items[i].ItemId,
new { @readonly = "readonly", onfocus = "this.blur();" })%></p>
<p><label for="Category">Category:</label>
<%= Html.TextBox(string.Format("items[{0}].{1}", i, "Category"),
Model.Items[i].Category)%></p>
<p><label for="Description">Description:</label>
<%= Html.TextBox(string.Format("items[{0}].{1}", i, "Description"),
Model.Items[i].Description)%></p>
</fieldset>
<%} // for-loop %>
<p><input type="submit" value="Save" /></p>
<%} // form %>
둘 다 수락하여 작동하는 컨트롤러 코드가 있습니다. Sku
그리고 EntitySet
의 Item
그런 다음 할당합니다 Items
~로 Sku
.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(Sku sku, EntitySet<Item> items)
{
if (sku != null)
{
if (items != null)
{
sku.Items.Assign(items);
}
}
// save Sku to repository ...
// return Details view ...
}
이것은 효과가 있지만, 나는 그것이 DefaultModelBinder
각각 Item
한 번의 여행 외에도 Sku
. 때 Sku
묶인 세터 Items
호출되며 바인더는 수화로 통과합니다. Items
올바른 값을 가진 수집. 그러나 전화 후 items.Assign
, Items.Count
~이다 0
. 이것이 컨트롤러 코드에서 항목을 다시 할당 해야하는 이유입니다. 나는 품목이 Items
바인더에 의한 수집. 이것은 항목 당 추가 여행을 제거해야합니다. items
컨트롤러 메소드의 매개 변수를 제거 할 수 있습니다. 왜 이것이 작동하지 않습니까?
해결책
이를 위해 사용자 정의 모델 바인더를 만들어야 할 수도 있습니까?
다른 팁
바라건대, 나는 당신이 문제를 정확하게 이해하고 있습니다 ...
당신의 정의보다는 구하다 2 개의 매개 변수를 가진 동작, 단일 매개 변수로 정의하는 것만으로 시도 했습니까? 스쿠?
그런 다음 다음 예제와 유사한 HTML 컨트롤 항목을 재정의하려고합니다 ...
<%=
Html.TextBox
(
string.Format("sku.Items[{0}].{1}", i, "ItemId"),
Model.Items[i].ItemId,
new { @readonly = "readonly", onfocus = "this.blur();" }
)
%>
이런 식으로, 당신은 SKU 객체 자체에 직접 항목을 채우고 있습니다.
또 다른 잠재적 솔루션은 항목 클래스에 추가 필드를 추가하는 것입니다.
Int32 SkuId { get; set; }
이렇게하면 컨트롤러에서 각 항목의 Skuid에 자동으로 연결된 각 항목에 대해 추가 숨겨진 필드를 정의 할 수 있습니다.
<%=
Html.Hidden
(
string.Format("sku.Items[{0}].{1}", i, "SkuId"),
Model.Items[i].SkuId
)
%>
그런 다음 SKU 객체와 독립적으로 항목 컬렉션을 업데이트 할 수 있습니다. 어떤 방식 으로든 상관없이 두 컬렉션은 SKU와 항목을 업데이트하기 위해 LINQ에서 SQL을 명시 적으로 알려야합니다.
당신은 또한 자신의 바인더 클래스를 정의 할 수 있지만,이 경우 가치보다 더 많은 작업 일 것입니다. ASP.NET MVC 컨벤션을 따르십시오. 해킹처럼 느끼지 않고 작동 할 무언가를 찾을 수 있어야한다고 생각합니다.
내 뷰 모델에서 EntitySets가 제대로 묶이지 않은 비슷한 문제가있었습니다.
내가 한 일은 EngitySet의 개인 필드를 감싸는 MVC [YourEntitySetPropertyName]라는 다른 속성을 제작하는 것이 었습니다.
public List<InvoiceLineItem> MvcInvoiceLineItemList
{
get { return _invoiceLineItemList.ToList(); }
set { _invoiceLineItemList.AddRange(value); }
}
그런 다음 내보기 마크 업에서 EntitySet 속성 대신에 사용했습니다.
컨트롤러 메소드 서명의 항목을 전달할 필요가 없습니다. 그 시점에서 SKU를 통과시킵니다.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(Sku sku)
{
if (sku != null)
{
// save Sku to repository ...
// return Details view ...
}
}