FLuent NHibernate / Castle Windsor, Id = 0 при попытке обновления - PullRequest
0 голосов
/ 23 апреля 2011

Я новичок в Castle Windsor / Свободно владею 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 внутри действия «Редактировать» равно 0. Что интересно, «Измененный» также является частью класса EntityBase, но он заполнен нормально.

Само собой разумеется, что добавление нового «Раздела» не является проблемой, поскольку идентификатор правильно генерируется базой данных.

Так что я знаю, что где-то определенно что-то упустил, и просто не вижу этого. Кто-нибудь может пролить свет на то, что мне не хватает?

Редактировать: Благодаря ответу @ 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();
    }

Теперь я получаю правильный идентификатор, и он также отображается правильно, но SaveOrUpdate, похоже, не изменяет данные в базе данных. Что еще я пропустил?

Редактировать 2: Doh!

необходимо промыть, т.е.

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

Спасибо.

1 Ответ

1 голос
/ 23 апреля 2011

Я считаю, что это потому, что Id установлен как частный, поэтому связыватель модели не может установить значение.

Лучший способ справиться с этим - создать ViewModel. Основы ViewModel - создание модели меньшего размера для каждого представления и сопоставление между моделью домена и моделью представления.

По сути, когда вы не используете ViewModels, вы открыты для чрезмерной или недостаточной публикации ( блог Брэда Уилсона ), что является большой проблемой безопасности. Есть и другие преимущества, такие как лучший рефакторинг, лучшая проверка и лучшее разделение проблем.

Подробнее:

Лучшие практики ViewModel

Использование моделей представления в ASP.NET MVC 3

У вас также есть кое-что несвязанное, например, это свойство Modified. nHibernate имеет встроенную поддержку для этого типа свойств, используя отображение версий ( блог Айенде , беглый nhibernate )

Кроме того, предпочтительно использовать методы Get / Load Session для загрузки объектов по id вместо запросов к объекту ( блог Айенде ).

...