Domanda

Ho problemi con l'associazione del modello nell'applicazione RC ASP.NET MVC 2 che utilizza NHIBERNATE per l'accesso ai dati. Stiamo cercando di creare l'applicazione in un modo Ruby on Rails e avere un'architettura molto semplice in cui le entità del dominio sono utilizzate dal database alla vista.

L'applicazione ha un paio di entità di dominio che possono essere illustrate dalle seguenti due classi:

public class Product {
    ...

    public Category Category { get; set; }      
}

public class Category {
    public int Id { get; set; }
    public string Name { get; set; }
}

Nella vista che rende il modulo di modifica ha la seguente istruzione per visualizzare un elenco a discesa:

<%= Html.DropDownListFor(model => model.Category.Id, 
       new SelectList(ViewData["categories"] as IList<Category>, "Id", "Name"), 
       "-- Select Category --" ) %>

Si prega di ignorare l'uso di dati di visualizzazione "non tipiti" per contenere la raccolta di categorie.

Il metodo di azione che riceve il post del modulo è simile a quello seguente. Si noti che l'attributo TransactionFilter aggiunge la gestione delle transazioni nhibernate e commette la transazione se non si verificano eccezioni e la convalida ha successo.

[HttpPost]
[TransactionFilter]
public ActionResult Edit(int id, FormCollection collection) {
    var product = _repository.Load(id);

    // Update the product except the Id
    UpdateModel(product, null, null, new[] {"Id"}, collection);

    if (ModelState.IsValid) {
      return RedirectToAction("Details", new {id});
    }
    return View(product);
}

Il mio problema è che il prodotto.category.id è impostato con il valore selezionato nel modulo, ad esempio categoria.id = "2". Utilizzando il legante del modello predefinito risulta nel seguente tipo di eccezione nhibernata:

identifier of an instance of Name.Space.Entities.Category was altered from 4 to 2

Ciò ha molto senso poiché il prodotto ha già una categoria assegnata e solo la chiave primaria di quella categoria esistente viene modificata. Un'altra istanza di categoria avrebbe dovuto essere assegnata invece.

Immagino che possa essere creato un legante modello personalizzato per gestire questo problema, ma esiste un modo più semplice per far funzionare questo? (E dovrebbero) le entità del dominio possono essere modificate per gestire questo?

È stato utile?

Soluzione 3

La soluzione che abbiamo scelto in quel momento era qualcosa di simile a questo:

TryUpdateModel(product, null, null, new[] {"Category"}, collection);
int categoryId;
if (int.TryParse(collection["Category.Id"], NumberStyles.Integer, CultureInfo.InvariantCulture, out categoryId) && categoryId > 0) {
    product.Category = _categoryRepository.Load(categoryId);
}
else {
    product.Category = null;
}

Diciamo semplicemente al Binder del modello di escludere la proprietà dell'associazione e gestirlo manualmente. Non è carino ma ha funzionato al momento ...

Altri suggerimenti

Ho risolto un problema simile con le caselle combinate nella mia pagina di modifica modificando la riga seguente

@Html.DropDownListFor(x => x.Employee.Id, new SelectList(ViewBag.Employees, "Id", "DisplayName"))

di

@Html.DropDownListFor(x => x.Employee, new SelectList(ViewBag.Employees, "Id", "DisplayName"))

Così ho rimosso il '.id' come mi ha suggerito Bryan. Prima della modifica, il modello conteneva solo l'ID del dipendente e dopo la modifica, il legante ha anche caricato tutti i dettagli del dipendente nel modello.

Ho usato tecniche simili con LINQ alle classi SQL prima senza problemi. Non credo che per questo avresti bisogno di un legante modello personalizzato. UpdateModel dovrebbe aggiornare la classe di prodotti che ci stai passando, non la sotto -classe di categoria allegata. Controllare l'HTML generato dall'aiuta DropDownListfor. Qual è il nome dell'elemento? Dovrebbe essere il nome del campo Key Foreign nella tabella dei prodotti (ad es. "CategoryId" o "Product.CategoryId" Not "Category.id"). Se è "Category.id" - Prova a modificare il primo parametro di DropDownList per "Model => Model.Category" o "Model => Model.CategoryId" (o qualunque sia il campo chiave estero). Ciò dovrebbe far aggiornare UpdateModel solo il campo a chiave straniera nella classe di prodotti e non l'ID classe di categoria.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top