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

发布于 2024-11-02 19:27:23 字数 4264 浏览 3 评论 0原文

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

经历了这个 出色的入门教程,并尝试 远离存储库,最终得到以下类/映射:

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

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

不用说,添加新的“部分”不是问题,因为 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");

谢谢。

I'm new to Castle Windsor/Fluent NHibernate / NHibernate and am trying to work with all of them in a .NET MVC3 project as a learning exercise.

Went through this excellent tutorial to get going, and trying to stay away from repositories, ended up with the following classes/mappings:

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

The problem I'm running into is when I edit a 'Section', the form displays fine and the hidden 'id' has the correct value. However, when that form is submitted, the value of the id column inside the 'Edit' action is 0. What's interesting is the 'Modified' is also part of the EntityBase class, but that's populated fine.

Needless to say, adding a new 'Section' is not a problem as the id is generated correctly by the database.

So I know I definitely missed something somewhere, and I'm just not seeing it. Can anyone please shed any light on what I'm missing?

Edit: Thanks to @Linkgoron's answer below, added a 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();
    }

Now I do get the correct id, and it is mapped over correctly as well, but SaveOrUpdate doesn't seem to modify the data in the database. What else did I miss?

Edit 2: Doh!

Needed to Flush i.e.

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

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小霸王臭丫头 2024-11-09 19:27:23

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

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

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

更多信息:

ViewModel 最佳实践

在 ASP.NET MVC 3 中使用视图模型

您还得到了一些不相关的内容,例如 Modified 属性。 nHibernate 使用版本映射(Ayende 的博客 , Fluent nhibernate

另外,最好使用 Get/Load Session 的方法通过 id 加载对象而不是查询对象( Ayende 的博客)。

I Believe that this is because Id is set as private, so the Model Binder can't set the value.

The best way to handle this would be to create a ViewModel. The basics of a ViewModel is creating a smaller model per view and mapping between the the domain model and the view model.

Basically, when you're not using ViewModels you're open over-posting/under-posting (Brad Wilson's blog) which is a BIG security problem. There also other benefits such as better refactoring, better validation and better seperation of concerns.

More info:

ViewModel Best Practices

Using view models in ASP.NET MVC 3

You've also got some unrelated stuff going there like that Modified property. nHibernate has built-in support for this kind of property using the Version mapping (Ayende's blog , fluent nhibernate)

Also, it's preferred using the Get/Load methods of the Session for loading objects by id instead of querying for the object (Ayende's blog).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文