2009-08-13 5 views
5

Эта проблема была сводит меня с ума в течение нескольких часов теперь ...ASP.NET MVC модель привязки связанных сущностей на той же странице

В моем домене, у меня есть 2 сущностей, которые связаны друг с другом и SkuItem. У каждого ску может быть много предметов.

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; } 
} 

Я строю страницу, которая позволит конечному пользователю обновить некоторые поля на идентификатор и некоторые поля на каждой позиции одновременно.

<% 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 на моем методе контроллера можно удалить. Почему это не работает?

+1

Я не уверен, если я понимаю, что это ваша проблема, но проверить эту статью и, что более важно, комментарии, от Фила Хака http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx –

ответ

1

Возможно, для этого вам понадобится создать собственное связующее устройство модели?

+0

В конце концов я закончил с пользовательским связующим. –

1

Надеюсь, я вас понять проблему правильно ...

Вместо того, чтобы определять ваше Сохранить действие с 2 параметрами, вы пробовали просто определив его с одним параметром, типа Sku?

Вы бы тогда хотите переопределить элемент HTML управляет аналогично следующему примеру ...

<%= 
    Html.TextBox 
    (
     string.Format("sku.Items[{0}].{1}", i, "ItemId"), 
     Model.Items[i].ItemId, 
     new { @readonly = "readonly", onfocus = "this.blur();" } 
    ) 
%> 


Таким образом, вы заселение элементы непосредственно в Sku сам объект.


Другим возможным решением было бы добавить дополнительное поле в класс Item, такие как ...

Int32 SkuId { get; set; } 

Таким образом, вы можете определить дополнительное скрытое поле для каждого элемента в вашей точки зрения, что будет автоматически привязан к SkuId каждого элемента обратно на контроллере.

<%= 
    Html.Hidden 
    (
     string.Format("sku.Items[{0}].{1}", i, "SkuId"), 
     Model.Items[i].SkuId 
    ) 
%> 

После этого вы можете просто обновить свою коллекцию предметов независимо от объекта Sku. Независимо от того, каким образом вы идете, обе коллекции должны явно указывать Linq на SQL, чтобы обновить sku и элементы в любом случае.

Вы также можете определить свой собственный класс связующего, но это, вероятно, больше работы, чем в этом случае. Просто следуйте за ASP.NET MVC, и я думаю, вы должны найти что-то, что будет работать, не чувствуя, что это взломать.

0

У меня была аналогичная проблема, когда EntitySets не были связаны должным образом в моей модели ViewModel.

Что я сделал, чтобы создать еще одно свойство под названием Mvc [YourEntitySetPropertyName], как общий список, который оборачивают вокруг частных полей EntitySet:

public List<InvoiceLineItem> MvcInvoiceLineItemList 
    { 
     get { return _invoiceLineItemList.ToList(); } 
     set { _invoiceLineItemList.AddRange(value); } 
    } 

Затем я использовал, что вместо свойства EntitySet на мой вид разметки.

Там не будет необходимости передавать элементы в вашем методе контроллера signature- просто передать Sku в этой точке:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Save(Sku sku) 
{ 
    if (sku != null) 
    { 
     // save Sku to repository ... 
     // return Details view ... 
    } 

}