0

Je suis nouveau à Castle Windsor/Fluent NHibernate/NHibernate et j'essaie de travailler avec chacun d'entre eux dans un projet .NET MVC3 comme un exercice d'apprentissage.FLuent NHibernate/Castle Windsor, Id = 0 en essayant de mettre à jour

suis passé par this excellent tutoriel pour y aller et essayer de stay away from repositories, a fini avec les classes/applications suivantes:

// Entities 
public abstract class EntityBase 
{ 
    public virtual int Id { get; private set; } 
    public virtual DateTime Modified { get; set; } 
} 

public class Section : EntityBase 
{ 
    public virtual String Name { get; set; } 
    public virtual int Sortorder { get; set; } 
    public virtual IList<ContentPage> Pages { get; set; } 

    public Section() 
    { 
     Pages = new List<ContentPage>(); 
    } 

    public virtual void AddContentPage(ContentPage contentPage) 
    { 
     contentPage.Section = this; 
     this.Pages.Add(contentPage); 
    } 
} 

public class ContentPage : EntityBase 
{ 
    public virtual String Title { get; set; } 
    public virtual int Sortorder { get; set; } 
    public virtual String MetaKeywords { get; set; } 
    public virtual String MetaDescription { get; set; } 
    public virtual String Slug { get; set; } 

    public virtual Section Section { get; set; } 
} 

//Mappings 
public abstract class EntityBaseMap<T> : ClassMap<T> where T : EntityBase 
{ 
    public EntityBaseMap() 
    { 
     Id(x => x.Id); 
     Map(x => x.Modified); 
    } 
} 

public class SectionMap : EntityBaseMap<Section> 
{ 
    public SectionMap() 
    { 
     Map(x => x.Name); 
     Map(x => x.Sortorder); 
     HasMany(x => x.Pages) 
      .Inverse() 
      .Cascade.All(); 
    } 
} 
public class ContentPageMap : EntityBaseMap<ContentPage> 
{ 
    public ContentPageMap() 
    { 
     Map(x => x.Title); 
     Map(x => x.Sortorder); 
     Map(x => x.MetaKeywords); 
     Map(x => x.MetaDescription); 
     Map(x => x.Slug); 
     References(x => x.Section); 

    } 
} 

// SectionsController 

    private readonly ISession session; 

    public ActionResult Edit(int id) 
    { 
     Section section = session.QueryOver<Section>().Where(x => x.Id == id).SingleOrDefault(); 
     if (section == null) 
     { 
      return HttpNotFound(); 
     } 
     return View(section); 
    } 

    [HttpPost] 
    public ActionResult Edit(Section section) 
    { 
     section.Modified = DateTime.Now; 
     if (ModelState.IsValid) 
     { 
      session.Update(section); 
      return RedirectToAction("Index"); 
     } 
     return View(); 
    } 

Le problème que je suis en cours d'exécution en est quand je modifier une « section », le formulaire s'affiche correctement et l'identifiant 'caché' a la valeur correcte. Cependant, lorsque ce formulaire est soumis, la valeur de la colonne id à l'intérieur de l'action 'Edit' est 0. Ce qui est intéressant, c'est que 'Modified' fait également partie de la classe EntityBase, mais cela est bien rempli. Inutile de dire que l'ajout d'une nouvelle 'Section' n'est pas un problème car l'ID est généré correctement par la base de données. Donc, je sais que j'ai définitivement manqué quelque chose quelque part, et je ne le vois tout simplement pas. Quelqu'un peut-il faire la lumière sur ce qui me manque?

Edit: Merci à @ la réponse de Linkgoron ci-dessous, a ajouté une ViewModel ...

public class SectionViewModel 
{ 
    public int Id { get; set; } 

    [Required(ErrorMessage = "Section Name is required")] 
    [StringLength(25, ErrorMessage = "Name must be less than 25 characters")] 
    public String Name { get; set; } 
    [Required] 
    public int Sortorder { get; set; } 
} 

// Updated Controller methods 
public ActionResult Edit(int id) 
    { 
     Section section = session.Load<Section>(id); 
     if (section == null) 
     { 
      return HttpNotFound(); 
     } 
     return View(section); 
    } 

    [HttpPost] 
    public ActionResult Edit(SectionViewModel sectionInputModel) 
    { 
     var section = session.Get<Section>(sectionInputModel.Id); 
     section.Modified = DateTime.Now; 
     if (ModelState.IsValid) 
     { 
      Mapper.CreateMap<SectionViewModel, Section>(); 
      Mapper.Map(sectionInputModel, section); 
      session.SaveOrUpdate(section); 
      return RedirectToAction("Index"); 
     } 
     return View(); 
    } 

Maintenant, je reçois le code correct, et il est mis en correspondance sur correctement aussi, mais saveOrUpdate qui ne fonctionne pas semblent modifier les données dans la base de données. Quoi d'autre ai-je manqué?

Édition 2: Doh!

nécessaires pour Purger à savoir

session.SaveOrUpdate(section); 
session.Flush(); 
return RedirectToAction("Index"); 

Merci.

+0

Vous ne devez pas utiliser Mapper.CreateMap () à chaque fois, il suffit d'exécuter CreateMap une fois, dans l'application_start.C'est une opération lourde qui utilise la réflexion. En outre, lorsque vous utilisez nhibernate, vous devez toujours exécuter des opérations dans une transaction http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions – Linkgoron

+0

Yep - figuré autant. Ce qui précède était juste pour que ça marche. Merci beaucoup pour les pointeurs! – seekay

Répondre

1

Je crois que cela est dû au fait que l'ID est défini comme privé, de sorte que le classeur de modèle ne peut pas définir la valeur.

La meilleure façon de gérer cela serait de créer un ViewModel. Les bases d'un ViewModel créent un plus petit modèle par vue et un mappage entre le modèle de domaine et le modèle de vue. Fondamentalement, lorsque vous n'utilisez pas ViewModels, vous êtes ouvert sur-affichage/sous-publication (Brad Wilson's blog), ce qui est un gros problème de sécurité. Il y a aussi d'autres avantages tels qu'un meilleur refactoring, une meilleure validation et une meilleure séparation des préoccupations.

Plus d'infos:

ViewModel Best Practices

Using view models in ASP.NET MVC 3

Vous avez également obtenu des choses sans rapport y aller comme cette propriété modifiée. NHibernate a un support intégré pour ce type de propriété à l'aide de la cartographie Version (Ayende's blog, fluent nhibernate)

, il est également préféré en utilisant les méthodes Get/Charger de la session pour les objets de chargement par id au lieu d'interroger l'objet (Ayende's blog).

+0

Merci pour l'information sur [a] ViewModels [b] les méthodes Get/Load, et [c] la propriété Version - super utile! Vous avez toujours un problème avec l'enregistrement et la version en tant qu'horodatage, mais vous effectuerez des recherches sur ce dernier. – seekay

Questions connexes