尝试更新时,FLUEnt NHibernate / Castle Windsor,Id = 0

时间:2011-04-22 21:20:43

标签: nhibernate asp.net-mvc-3 fluent-nhibernate castle-windsor

我是Castle Windsor / Fluent NHibernate / NHibernate的新手,我正在尝试在.NET MVC3项目中使用它们作为学习练习。

通过this出色的教程开始,尝试stay away from repositories,最后得到以下类/映射:

 // 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();
    }

我遇到的问题是当我编辑'Section'时,表单显示正常,隐藏的'id'具有正确的值。但是,当提交该表单时,“编辑”操作中的id列的值为0.有趣的是,“已修改”也是EntityBase类的一部分,但是填充的很好。

毋庸置疑,添加新的“Section”不是问题,因为数据库正确生成了id。

所以我知道我肯定错过了某个地方,我只是没有看到它。任何人都可以对我缺少的东西有所了解吗?

编辑:感谢@ Linkgoron的回答,添加了一个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();
    }

现在我确实得到了正确的id,并且它也被正确映射,但是SaveOrUpdate似乎没有修改数据库中的数据。还有什么我想念的?

编辑2:Doh!

需要冲洗,即

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

感谢。

1 个答案:

答案 0 :(得分:1)

我相信这是因为Id设置为私有,因此Model Binder无法设置该值。

处理此问题的最佳方法是创建ViewModel。 ViewModel的基础是为每个视图创建一个较小的模型,并在域模型和视图模型之间进行映射。

基本上,当您不使用ViewModels时,您会打开过度发布/不足发布(Brad Wilson's blog),这是一个很大的安全问题。还有其他好处,例如更好的重构,更好的验证和更好的分离。

更多信息:

ViewModel Best Practices

Using view models in ASP.NET MVC 3

你也有一些不相关的东西就像那个改良的属性一样。 nHibernate使用版本映射(Ayende's blogfluent nhibernate

内置了对此类属性的支持

此外,首选使用Session的Get / Load方法按id加载对象,而不是查询对象(Ayende's blog)。