我是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");
感谢。
答案 0 :(得分:1)
我相信这是因为Id设置为私有,因此Model Binder无法设置该值。
处理此问题的最佳方法是创建ViewModel。 ViewModel的基础是为每个视图创建一个较小的模型,并在域模型和视图模型之间进行映射。
基本上,当您不使用ViewModels时,您会打开过度发布/不足发布(Brad Wilson's blog),这是一个很大的安全问题。还有其他好处,例如更好的重构,更好的验证和更好的分离。
更多信息:
Using view models in ASP.NET MVC 3
你也有一些不相关的东西就像那个改良的属性一样。 nHibernate使用版本映射(Ayende's blog,fluent nhibernate)
内置了对此类属性的支持此外,首选使用Session的Get / Load方法按id加载对象,而不是查询对象(Ayende's blog)。